Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* spinlock.h: 64-bit Sparc spinlock support. |
2 | * | |
3 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | |
4 | */ | |
5 | ||
6 | #ifndef __SPARC64_SPINLOCK_H | |
7 | #define __SPARC64_SPINLOCK_H | |
8 | ||
9 | #include <linux/config.h> | |
10 | #include <linux/threads.h> /* For NR_CPUS */ | |
11 | ||
12 | #ifndef __ASSEMBLY__ | |
13 | ||
14 | /* To get debugging spinlocks which detect and catch | |
15 | * deadlock situations, set CONFIG_DEBUG_SPINLOCK | |
16 | * and rebuild your kernel. | |
17 | */ | |
18 | ||
19 | /* All of these locking primitives are expected to work properly | |
20 | * even in an RMO memory model, which currently is what the kernel | |
21 | * runs in. | |
22 | * | |
23 | * There is another issue. Because we play games to save cycles | |
24 | * in the non-contention case, we need to be extra careful about | |
25 | * branch targets into the "spinning" code. They live in their | |
26 | * own section, but the newer V9 branches have a shorter range | |
27 | * than the traditional 32-bit sparc branch variants. The rule | |
28 | * is that the branches that go into and out of the spinner sections | |
29 | * must be pre-V9 branches. | |
30 | */ | |
31 | ||
fb1c8f93 | 32 | #define __raw_spin_is_locked(lp) ((lp)->lock != 0) |
1da177e4 | 33 | |
fb1c8f93 IM |
34 | #define __raw_spin_unlock_wait(lp) \ |
35 | do { rmb(); \ | |
36 | } while((lp)->lock) | |
1da177e4 | 37 | |
fb1c8f93 | 38 | static inline void __raw_spin_lock(raw_spinlock_t *lock) |
1da177e4 LT |
39 | { |
40 | unsigned long tmp; | |
41 | ||
42 | __asm__ __volatile__( | |
43 | "1: ldstub [%1], %0\n" | |
b445e26c | 44 | " membar #StoreLoad | #StoreStore\n" |
1da177e4 | 45 | " brnz,pn %0, 2f\n" |
b445e26c | 46 | " nop\n" |
1da177e4 LT |
47 | " .subsection 2\n" |
48 | "2: ldub [%1], %0\n" | |
b445e26c | 49 | " membar #LoadLoad\n" |
1da177e4 | 50 | " brnz,pt %0, 2b\n" |
b445e26c | 51 | " nop\n" |
1da177e4 LT |
52 | " ba,a,pt %%xcc, 1b\n" |
53 | " .previous" | |
54 | : "=&r" (tmp) | |
55 | : "r" (lock) | |
56 | : "memory"); | |
57 | } | |
58 | ||
fb1c8f93 | 59 | static inline int __raw_spin_trylock(raw_spinlock_t *lock) |
1da177e4 LT |
60 | { |
61 | unsigned long result; | |
62 | ||
63 | __asm__ __volatile__( | |
64 | " ldstub [%1], %0\n" | |
65 | " membar #StoreLoad | #StoreStore" | |
66 | : "=r" (result) | |
67 | : "r" (lock) | |
68 | : "memory"); | |
69 | ||
70 | return (result == 0UL); | |
71 | } | |
72 | ||
fb1c8f93 | 73 | static inline void __raw_spin_unlock(raw_spinlock_t *lock) |
1da177e4 LT |
74 | { |
75 | __asm__ __volatile__( | |
76 | " membar #StoreStore | #LoadStore\n" | |
77 | " stb %%g0, [%0]" | |
78 | : /* No outputs */ | |
79 | : "r" (lock) | |
80 | : "memory"); | |
81 | } | |
82 | ||
fb1c8f93 | 83 | static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) |
1da177e4 LT |
84 | { |
85 | unsigned long tmp1, tmp2; | |
86 | ||
87 | __asm__ __volatile__( | |
88 | "1: ldstub [%2], %0\n" | |
1da177e4 | 89 | " membar #StoreLoad | #StoreStore\n" |
b445e26c DM |
90 | " brnz,pn %0, 2f\n" |
91 | " nop\n" | |
1da177e4 LT |
92 | " .subsection 2\n" |
93 | "2: rdpr %%pil, %1\n" | |
94 | " wrpr %3, %%pil\n" | |
95 | "3: ldub [%2], %0\n" | |
1da177e4 | 96 | " membar #LoadLoad\n" |
b445e26c DM |
97 | " brnz,pt %0, 3b\n" |
98 | " nop\n" | |
1da177e4 | 99 | " ba,pt %%xcc, 1b\n" |
b445e26c | 100 | " wrpr %1, %%pil\n" |
1da177e4 LT |
101 | " .previous" |
102 | : "=&r" (tmp1), "=&r" (tmp2) | |
103 | : "r"(lock), "r"(flags) | |
104 | : "memory"); | |
105 | } | |
106 | ||
1da177e4 LT |
107 | /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ |
108 | ||
fb1c8f93 | 109 | static void inline __read_lock(raw_rwlock_t *lock) |
1da177e4 LT |
110 | { |
111 | unsigned long tmp1, tmp2; | |
112 | ||
113 | __asm__ __volatile__ ( | |
114 | "1: ldsw [%2], %0\n" | |
115 | " brlz,pn %0, 2f\n" | |
116 | "4: add %0, 1, %1\n" | |
117 | " cas [%2], %0, %1\n" | |
118 | " cmp %0, %1\n" | |
b445e26c | 119 | " membar #StoreLoad | #StoreStore\n" |
1da177e4 | 120 | " bne,pn %%icc, 1b\n" |
b445e26c | 121 | " nop\n" |
1da177e4 LT |
122 | " .subsection 2\n" |
123 | "2: ldsw [%2], %0\n" | |
b445e26c | 124 | " membar #LoadLoad\n" |
1da177e4 | 125 | " brlz,pt %0, 2b\n" |
b445e26c | 126 | " nop\n" |
1da177e4 LT |
127 | " ba,a,pt %%xcc, 4b\n" |
128 | " .previous" | |
129 | : "=&r" (tmp1), "=&r" (tmp2) | |
130 | : "r" (lock) | |
131 | : "memory"); | |
132 | } | |
133 | ||
d3ed309a DM |
134 | static int inline __read_trylock(raw_rwlock_t *lock) |
135 | { | |
136 | int tmp1, tmp2; | |
137 | ||
138 | __asm__ __volatile__ ( | |
139 | "1: ldsw [%2], %0\n" | |
140 | " brlz,a,pn %0, 2f\n" | |
141 | " mov 0, %0\n" | |
142 | " add %0, 1, %1\n" | |
143 | " cas [%2], %0, %1\n" | |
144 | " cmp %0, %1\n" | |
145 | " membar #StoreLoad | #StoreStore\n" | |
146 | " bne,pn %%icc, 1b\n" | |
147 | " mov 1, %0\n" | |
148 | "2:" | |
149 | : "=&r" (tmp1), "=&r" (tmp2) | |
150 | : "r" (lock) | |
151 | : "memory"); | |
152 | ||
153 | return tmp1; | |
154 | } | |
155 | ||
fb1c8f93 | 156 | static void inline __read_unlock(raw_rwlock_t *lock) |
1da177e4 LT |
157 | { |
158 | unsigned long tmp1, tmp2; | |
159 | ||
160 | __asm__ __volatile__( | |
161 | " membar #StoreLoad | #LoadLoad\n" | |
162 | "1: lduw [%2], %0\n" | |
163 | " sub %0, 1, %1\n" | |
164 | " cas [%2], %0, %1\n" | |
165 | " cmp %0, %1\n" | |
166 | " bne,pn %%xcc, 1b\n" | |
167 | " nop" | |
168 | : "=&r" (tmp1), "=&r" (tmp2) | |
169 | : "r" (lock) | |
170 | : "memory"); | |
171 | } | |
172 | ||
fb1c8f93 | 173 | static void inline __write_lock(raw_rwlock_t *lock) |
1da177e4 LT |
174 | { |
175 | unsigned long mask, tmp1, tmp2; | |
176 | ||
177 | mask = 0x80000000UL; | |
178 | ||
179 | __asm__ __volatile__( | |
180 | "1: lduw [%2], %0\n" | |
181 | " brnz,pn %0, 2f\n" | |
182 | "4: or %0, %3, %1\n" | |
183 | " cas [%2], %0, %1\n" | |
184 | " cmp %0, %1\n" | |
b445e26c | 185 | " membar #StoreLoad | #StoreStore\n" |
1da177e4 | 186 | " bne,pn %%icc, 1b\n" |
b445e26c | 187 | " nop\n" |
1da177e4 LT |
188 | " .subsection 2\n" |
189 | "2: lduw [%2], %0\n" | |
b445e26c | 190 | " membar #LoadLoad\n" |
1da177e4 | 191 | " brnz,pt %0, 2b\n" |
b445e26c | 192 | " nop\n" |
1da177e4 LT |
193 | " ba,a,pt %%xcc, 4b\n" |
194 | " .previous" | |
195 | : "=&r" (tmp1), "=&r" (tmp2) | |
196 | : "r" (lock), "r" (mask) | |
197 | : "memory"); | |
198 | } | |
199 | ||
fb1c8f93 | 200 | static void inline __write_unlock(raw_rwlock_t *lock) |
1da177e4 LT |
201 | { |
202 | __asm__ __volatile__( | |
203 | " membar #LoadStore | #StoreStore\n" | |
204 | " stw %%g0, [%0]" | |
205 | : /* no outputs */ | |
206 | : "r" (lock) | |
207 | : "memory"); | |
208 | } | |
209 | ||
fb1c8f93 | 210 | static int inline __write_trylock(raw_rwlock_t *lock) |
1da177e4 LT |
211 | { |
212 | unsigned long mask, tmp1, tmp2, result; | |
213 | ||
214 | mask = 0x80000000UL; | |
215 | ||
216 | __asm__ __volatile__( | |
217 | " mov 0, %2\n" | |
218 | "1: lduw [%3], %0\n" | |
219 | " brnz,pn %0, 2f\n" | |
220 | " or %0, %4, %1\n" | |
221 | " cas [%3], %0, %1\n" | |
222 | " cmp %0, %1\n" | |
b445e26c | 223 | " membar #StoreLoad | #StoreStore\n" |
1da177e4 | 224 | " bne,pn %%icc, 1b\n" |
b445e26c | 225 | " nop\n" |
1da177e4 LT |
226 | " mov 1, %2\n" |
227 | "2:" | |
228 | : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result) | |
229 | : "r" (lock), "r" (mask) | |
230 | : "memory"); | |
231 | ||
232 | return result; | |
233 | } | |
234 | ||
fb1c8f93 | 235 | #define __raw_read_lock(p) __read_lock(p) |
d3ed309a | 236 | #define __raw_read_trylock(p) __read_trylock(p) |
fb1c8f93 IM |
237 | #define __raw_read_unlock(p) __read_unlock(p) |
238 | #define __raw_write_lock(p) __write_lock(p) | |
239 | #define __raw_write_unlock(p) __write_unlock(p) | |
240 | #define __raw_write_trylock(p) __write_trylock(p) | |
241 | ||
fb1c8f93 IM |
242 | #define __raw_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) |
243 | #define __raw_write_can_lock(rw) (!(rw)->lock) | |
1da177e4 LT |
244 | |
245 | #endif /* !(__ASSEMBLY__) */ | |
246 | ||
247 | #endif /* !(__SPARC64_SPINLOCK_H) */ |