Import 2.3.18pre1
[davej-history.git] / include / asm-sparc / spinlock.h
blobbcc8f0b8789d48144279c963f190418912e6e15d
1 /* spinlock.h: 32-bit Sparc spinlock support.
3 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
4 */
6 #ifndef __SPARC_SPINLOCK_H
7 #define __SPARC_SPINLOCK_H
9 #include <linux/threads.h> /* For NR_CPUS */
11 #ifndef __ASSEMBLY__
13 #include <asm/psr.h>
15 /* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */
16 #define SPIN_LOCK_DEBUG
18 #ifdef SPIN_LOCK_DEBUG
19 struct _spinlock_debug {
20 unsigned char lock;
21 unsigned long owner_pc;
23 typedef struct _spinlock_debug spinlock_t;
25 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0 }
26 #define spin_lock_init(lp) do { (lp)->owner_pc = 0; (lp)->lock = 0; } while(0)
27 #define spin_is_locked(lp) (*((volatile unsigned char *)(&((lp)->lock))) != 0)
28 #define spin_unlock_wait(lp) do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock))
30 extern void _do_spin_lock(spinlock_t *lock, char *str);
31 extern int _spin_trylock(spinlock_t *lock);
32 extern void _do_spin_unlock(spinlock_t *lock);
34 #define spin_trylock(lp) _spin_trylock(lp)
36 #define spin_lock(lock) _do_spin_lock(lock, "spin_lock")
37 #define spin_lock_irq(lock) do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
38 #define spin_lock_bh(lock) do { local_bh_disable(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
39 #define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
41 #define spin_unlock(lock) _do_spin_unlock(lock)
42 #define spin_unlock_irq(lock) do { _do_spin_unlock(lock); __sti(); } while(0)
43 #define spin_unlock_bh(lock) do { _do_spin_unlock(lock); local_bh_enable(); } while(0)
44 #define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
46 struct _rwlock_debug {
47 volatile unsigned int lock;
48 unsigned long owner_pc;
49 unsigned long reader_pc[NR_CPUS];
51 typedef struct _rwlock_debug rwlock_t;
53 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, {0} }
55 extern void _do_read_lock(rwlock_t *rw, char *str);
56 extern void _do_read_unlock(rwlock_t *rw, char *str);
57 extern void _do_write_lock(rwlock_t *rw, char *str);
58 extern void _do_write_unlock(rwlock_t *rw);
60 #define read_lock(lock) \
61 do { unsigned long flags; \
62 __save_and_cli(flags); \
63 _do_read_lock(lock, "read_lock"); \
64 __restore_flags(flags); \
65 } while(0)
66 #define read_lock_irq(lock) do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
67 #define read_lock_bh(lock) do { local_bh_disable(); _do_read_lock(lock, "read_lock_irq"); } while(0)
68 #define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
70 #define read_unlock(lock) \
71 do { unsigned long flags; \
72 __save_and_cli(flags); \
73 _do_read_unlock(lock, "read_unlock"); \
74 __restore_flags(flags); \
75 } while(0)
76 #define read_unlock_irq(lock) do { _do_read_unlock(lock, "read_unlock_irq"); __sti(); } while(0)
77 #define read_unlock_bh(lock) do { _do_read_unlock(lock, "read_unlock_irq"); local_bh_enable(); } while(0)
78 #define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
80 #define write_lock(lock) \
81 do { unsigned long flags; \
82 __save_and_cli(flags); \
83 _do_write_lock(lock, "write_lock"); \
84 __restore_flags(flags); \
85 } while(0)
86 #define write_lock_irq(lock) do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
87 #define write_lock_bh(lock) do { local_bh_disable(); _do_write_lock(lock, "write_lock_irq"); } while(0)
88 #define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
90 #define write_unlock(lock) \
91 do { unsigned long flags; \
92 __save_and_cli(flags); \
93 _do_write_unlock(lock); \
94 __restore_flags(flags); \
95 } while(0)
96 #define write_unlock_irq(lock) do { _do_write_unlock(lock); __sti(); } while(0)
97 #define write_unlock_bh(lock) do { _do_write_unlock(lock); local_bh_enable(); } while(0)
98 #define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
100 #else /* !SPIN_LOCK_DEBUG */
102 typedef unsigned char spinlock_t;
103 #define SPIN_LOCK_UNLOCKED 0
105 #define spin_lock_init(lock) (*(lock) = 0)
106 #define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
107 #define spin_unlock_wait(lock) do { barrier(); } while(*(volatile unsigned char *)lock)
109 extern __inline__ void spin_lock(spinlock_t *lock)
111 __asm__ __volatile__("
112 1: ldstub [%0], %%g2
113 orcc %%g2, 0x0, %%g0
114 bne,a 2f
115 ldub [%0], %%g2
116 .text 2
117 2: orcc %%g2, 0x0, %%g0
118 bne,a 2b
119 ldub [%0], %%g2
120 b,a 1b
121 .previous
122 " : /* no outputs */
123 : "r" (lock)
124 : "g2", "memory", "cc");
127 extern __inline__ int spin_trylock(spinlock_t *lock)
129 unsigned int result;
130 __asm__ __volatile__("ldstub [%1], %0"
131 : "=r" (result)
132 : "r" (lock)
133 : "memory");
134 return (result == 0);
137 extern __inline__ void spin_unlock(spinlock_t *lock)
139 __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory");
142 extern __inline__ void spin_lock_irq(spinlock_t *lock)
144 __asm__ __volatile__("
145 rd %%psr, %%g2
146 or %%g2, %0, %%g2
147 wr %%g2, 0x0, %%psr
148 nop; nop; nop;
149 1: ldstub [%1], %%g2
150 orcc %%g2, 0x0, %%g0
151 bne,a 2f
152 ldub [%1], %%g2
153 .text 2
154 2: orcc %%g2, 0x0, %%g0
155 bne,a 2b
156 ldub [%1], %%g2
157 b,a 1b
158 .previous
159 " : /* No outputs */
160 : "i" (PSR_PIL), "r" (lock)
161 : "g2", "memory", "cc");
164 #define spin_lock_bh(___lk) do { local_bh_disable(); spin_lock(___lk); } while(0)
166 extern __inline__ void spin_unlock_irq(spinlock_t *lock)
168 __asm__ __volatile__("
169 rd %%psr, %%g2
170 andn %%g2, %1, %%g2
171 stb %%g0, [%0]
172 wr %%g2, 0x0, %%psr
173 nop; nop; nop;
174 " : /* No outputs. */
175 : "r" (lock), "i" (PSR_PIL)
176 : "g2", "memory");
179 #define spin_unlock_bh(___lk) do { spin_unlock(___lk); local_bh_enable(); } while(0)
181 #define spin_lock_irqsave(__lock, flags) \
182 do { \
183 register spinlock_t *__lp asm("g1"); \
184 __lp = (__lock); \
185 __asm__ __volatile__( \
186 "rd %%psr, %0\n\t" \
187 "or %0, %1, %%g2\n\t" \
188 "wr %%g2, 0x0, %%psr\n\t" \
189 "nop; nop; nop;\n" \
190 "1:\n\t" \
191 "ldstub [%2], %%g2\n\t" \
192 "orcc %%g2, 0x0, %%g0\n\t" \
193 "bne,a 2f\n\t" \
194 " ldub [%2], %%g2\n\t" \
195 ".text 2\n" \
196 "2:\n\t" \
197 "orcc %%g2, 0x0, %%g0\n\t" \
198 "bne,a 2b\n\t" \
199 " ldub [%2], %%g2\n\t" \
200 "b,a 1b\n\t" \
201 ".previous\n" \
202 : "=r" (flags) \
203 : "i" (PSR_PIL), "r" (__lp) \
204 : "g2", "memory", "cc"); \
205 } while(0)
207 extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
209 __asm__ __volatile__("
210 stb %%g0, [%0]
211 wr %1, 0x0, %%psr
212 nop; nop; nop;
213 " : /* No outputs. */
214 : "r" (lock), "r" (flags)
215 : "memory", "cc");
218 /* Read-write spinlocks, allowing multiple readers
219 * but only one writer.
221 * NOTE! it is quite common to have readers in interrupts
222 * but no interrupt writers. For those circumstances we
223 * can "mix" irq-safe locks - any writer needs to get a
224 * irq-safe write-lock, but readers can get non-irqsafe
225 * read-locks.
227 * XXX This might create some problems with my dual spinlock
228 * XXX scheme, deadlocks etc. -DaveM
230 typedef struct { volatile unsigned int lock; } rwlock_t;
232 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
234 /* Sort of like atomic_t's on Sparc, but even more clever.
236 * ------------------------------------
237 * | 24-bit counter | wlock | rwlock_t
238 * ------------------------------------
239 * 31 8 7 0
241 * wlock signifies the one writer is in or somebody is updating
242 * counter. For a writer, if he successfully acquires the wlock,
243 * but counter is non-zero, he has to release the lock and wait,
244 * till both counter and wlock are zero.
246 * Unfortunately this scheme limits us to ~16,000,000 cpus.
248 extern __inline__ void _read_lock(rwlock_t *rw)
250 register rwlock_t *lp asm("g1");
251 lp = rw;
252 __asm__ __volatile__("
253 mov %%o7, %%g4
254 call ___rw_read_enter
255 ldstub [%%g1 + 3], %%g2
256 " : /* no outputs */
257 : "r" (lp)
258 : "g2", "g4", "g7", "memory", "cc");
261 #define read_lock(lock) \
262 do { unsigned long flags; \
263 __save_and_cli(flags); \
264 _read_lock(lock); \
265 __restore_flags(flags); \
266 } while(0)
268 extern __inline__ void _read_unlock(rwlock_t *rw)
270 register rwlock_t *lp asm("g1");
271 lp = rw;
272 __asm__ __volatile__("
273 mov %%o7, %%g4
274 call ___rw_read_exit
275 ldstub [%%g1 + 3], %%g2
276 " : /* no outputs */
277 : "r" (lp)
278 : "g2", "g4", "g7", "memory", "cc");
281 #define read_unlock(lock) \
282 do { unsigned long flags; \
283 __save_and_cli(flags); \
284 _read_unlock(lock); \
285 __restore_flags(flags); \
286 } while(0)
288 extern __inline__ void write_lock(rwlock_t *rw)
290 register rwlock_t *lp asm("g1");
291 lp = rw;
292 __asm__ __volatile__("
293 mov %%o7, %%g4
294 call ___rw_write_enter
295 ldstub [%%g1 + 3], %%g2
296 " : /* no outputs */
297 : "r" (lp)
298 : "g2", "g4", "g7", "memory", "cc");
301 #define write_unlock(rw) do { (rw)->lock = 0; } while(0)
302 #define read_lock_irq(lock) do { __cli(); _read_lock(lock); } while (0)
303 #define read_unlock_irq(lock) do { _read_unlock(lock); __sti(); } while (0)
304 #define write_lock_irq(lock) do { __cli(); write_lock(lock); } while (0)
305 #define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0)
307 #define read_lock_bh(lock) do { local_bh_disable(); _read_lock(lock); } while (0)
308 #define read_unlock_bh(lock) do { _read_unlock(lock); local_bh_enable(); } while (0)
309 #define write_lock_bh(lock) do { local_bh_disable(); write_lock(lock); } while (0)
310 #define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0)
312 #define read_lock_irqsave(lock, flags) \
313 do { __save_and_cli(flags); _read_lock(lock); } while (0)
314 #define read_unlock_irqrestore(lock, flags) \
315 do { _read_unlock(lock); __restore_flags(flags); } while (0)
316 #define write_lock_irqsave(lock, flags) \
317 do { __save_and_cli(flags); write_lock(lock); } while (0)
318 #define write_unlock_irqrestore(lock, flags) \
319 do { write_unlock(lock); __restore_flags(flags); } while (0)
321 #endif /* SPIN_LOCK_DEBUG */
323 #endif /* !(__ASSEMBLY__) */
325 #endif /* __SPARC_SPINLOCK_H */