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