aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-m32r/spinlock.h
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2005-09-10 03:25:56 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-10 13:06:21 -0400
commitfb1c8f93d869b34cacb8b8932e2b83d96a19d720 (patch)
treea006d078aa02e421a7dc4793c335308204859d36 /include/asm-m32r/spinlock.h
parent4327edf6b8a7ac7dce144313947995538842d8fd (diff)
[PATCH] spinlock consolidation
This patch (written by me and also containing many suggestions of Arjan van de Ven) does a major cleanup of the spinlock code. It does the following things: - consolidates and enhances the spinlock/rwlock debugging code - simplifies the asm/spinlock.h files - encapsulates the raw spinlock type and moves generic spinlock features (such as ->break_lock) into the generic code. - cleans up the spinlock code hierarchy to get rid of the spaghetti. Most notably there's now only a single variant of the debugging code, located in lib/spinlock_debug.c. (previously we had one SMP debugging variant per architecture, plus a separate generic one for UP builds) Also, i've enhanced the rwlock debugging facility, it will now track write-owners. There is new spinlock-owner/CPU-tracking on SMP builds too. All locks have lockup detection now, which will work for both soft and hard spin/rwlock lockups. The arch-level include files now only contain the minimally necessary subset of the spinlock code - all the rest that can be generalized now lives in the generic headers: include/asm-i386/spinlock_types.h | 16 include/asm-x86_64/spinlock_types.h | 16 I have also split up the various spinlock variants into separate files, making it easier to see which does what. The new layout is: SMP | UP ----------------------------|----------------------------------- asm/spinlock_types_smp.h | linux/spinlock_types_up.h linux/spinlock_types.h | linux/spinlock_types.h asm/spinlock_smp.h | linux/spinlock_up.h linux/spinlock_api_smp.h | linux/spinlock_api_up.h linux/spinlock.h | linux/spinlock.h /* * here's the role of the various spinlock/rwlock related include files: * * on SMP builds: * * asm/spinlock_types.h: contains the raw_spinlock_t/raw_rwlock_t and the * initializers * * linux/spinlock_types.h: * defines the generic type and initializers * * asm/spinlock.h: contains the __raw_spin_*()/etc. lowlevel * implementations, mostly inline assembly code * * (also included on UP-debug builds:) * * linux/spinlock_api_smp.h: * contains the prototypes for the _spin_*() APIs. * * linux/spinlock.h: builds the final spin_*() APIs. * * on UP builds: * * linux/spinlock_type_up.h: * contains the generic, simplified UP spinlock type. * (which is an empty structure on non-debug builds) * * linux/spinlock_types.h: * defines the generic type and initializers * * linux/spinlock_up.h: * contains the __raw_spin_*()/etc. version of UP * builds. (which are NOPs on non-debug, non-preempt * builds) * * (included on UP-non-debug builds:) * * linux/spinlock_api_up.h: * builds the _spin_*() APIs. * * linux/spinlock.h: builds the final spin_*() APIs. */ All SMP and UP architectures are converted by this patch. arm, i386, ia64, ppc, ppc64, s390/s390x, x64 was build-tested via crosscompilers. m32r, mips, sh, sparc, have not been tested yet, but should be mostly fine. From: Grant Grundler <grundler@parisc-linux.org> Booted and lightly tested on a500-44 (64-bit, SMP kernel, dual CPU). Builds 32-bit SMP kernel (not booted or tested). I did not try to build non-SMP kernels. That should be trivial to fix up later if necessary. I converted bit ops atomic_hash lock to raw_spinlock_t. Doing so avoids some ugly nesting of linux/*.h and asm/*.h files. Those particular locks are well tested and contained entirely inside arch specific code. I do NOT expect any new issues to arise with them. If someone does ever need to use debug/metrics with them, then they will need to unravel this hairball between spinlocks, atomic ops, and bit ops that exist only because parisc has exactly one atomic instruction: LDCW (load and clear word). From: "Luck, Tony" <tony.luck@intel.com> ia64 fix Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Arjan van de Ven <arjanv@infradead.org> Signed-off-by: Grant Grundler <grundler@parisc-linux.org> Cc: Matthew Wilcox <willy@debian.org> Signed-off-by: Hirokazu Takata <takata@linux-m32r.org> Signed-off-by: Mikael Pettersson <mikpe@csd.uu.se> Signed-off-by: Benoit Boissinot <benoit.boissinot@ens-lyon.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/asm-m32r/spinlock.h')
-rw-r--r--include/asm-m32r/spinlock.h127
1 files changed, 30 insertions, 97 deletions
diff --git a/include/asm-m32r/spinlock.h b/include/asm-m32r/spinlock.h
index 6608d8371c50..7de7def28da9 100644
--- a/include/asm-m32r/spinlock.h
+++ b/include/asm-m32r/spinlock.h
@@ -14,57 +14,30 @@
14#include <asm/atomic.h> 14#include <asm/atomic.h>
15#include <asm/page.h> 15#include <asm/page.h>
16 16
17extern int printk(const char * fmt, ...)
18 __attribute__ ((format (printf, 1, 2)));
19
20#define RW_LOCK_BIAS 0x01000000
21#define RW_LOCK_BIAS_STR "0x01000000"
22
23/* 17/*
24 * Your basic SMP spinlocks, allowing only a single CPU anywhere 18 * Your basic SMP spinlocks, allowing only a single CPU anywhere
25 */ 19 *
26 20 * (the type definitions are in asm/spinlock_types.h)
27typedef struct { 21 *
28 volatile int slock;
29#ifdef CONFIG_DEBUG_SPINLOCK
30 unsigned magic;
31#endif
32#ifdef CONFIG_PREEMPT
33 unsigned int break_lock;
34#endif
35} spinlock_t;
36
37#define SPINLOCK_MAGIC 0xdead4ead
38
39#ifdef CONFIG_DEBUG_SPINLOCK
40#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC
41#else
42#define SPINLOCK_MAGIC_INIT /* */
43#endif
44
45#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
46
47#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
48
49/*
50 * Simple spin lock operations. There are two variants, one clears IRQ's 22 * Simple spin lock operations. There are two variants, one clears IRQ's
51 * on the local processor, one does not. 23 * on the local processor, one does not.
52 * 24 *
53 * We make no fairness assumptions. They have a cost. 25 * We make no fairness assumptions. They have a cost.
54 */ 26 */
55 27
56#define spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0) 28#define __raw_spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0)
57#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) 29#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
58#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) 30#define __raw_spin_unlock_wait(x) \
31 do { cpu_relax(); } while (__raw_spin_is_locked(x))
59 32
60/** 33/**
61 * _raw_spin_trylock - Try spin lock and return a result 34 * __raw_spin_trylock - Try spin lock and return a result
62 * @lock: Pointer to the lock variable 35 * @lock: Pointer to the lock variable
63 * 36 *
64 * _raw_spin_trylock() tries to get the lock and returns a result. 37 * __raw_spin_trylock() tries to get the lock and returns a result.
65 * On the m32r, the result value is 1 (= Success) or 0 (= Failure). 38 * On the m32r, the result value is 1 (= Success) or 0 (= Failure).
66 */ 39 */
67static inline int _raw_spin_trylock(spinlock_t *lock) 40static inline int __raw_spin_trylock(raw_spinlock_t *lock)
68{ 41{
69 int oldval; 42 int oldval;
70 unsigned long tmp1, tmp2; 43 unsigned long tmp1, tmp2;
@@ -78,7 +51,7 @@ static inline int _raw_spin_trylock(spinlock_t *lock)
78 * } 51 * }
79 */ 52 */
80 __asm__ __volatile__ ( 53 __asm__ __volatile__ (
81 "# spin_trylock \n\t" 54 "# __raw_spin_trylock \n\t"
82 "ldi %1, #0; \n\t" 55 "ldi %1, #0; \n\t"
83 "mvfc %2, psw; \n\t" 56 "mvfc %2, psw; \n\t"
84 "clrpsw #0x40 -> nop; \n\t" 57 "clrpsw #0x40 -> nop; \n\t"
@@ -97,16 +70,10 @@ static inline int _raw_spin_trylock(spinlock_t *lock)
97 return (oldval > 0); 70 return (oldval > 0);
98} 71}
99 72
100static inline void _raw_spin_lock(spinlock_t *lock) 73static inline void __raw_spin_lock(raw_spinlock_t *lock)
101{ 74{
102 unsigned long tmp0, tmp1; 75 unsigned long tmp0, tmp1;
103 76
104#ifdef CONFIG_DEBUG_SPINLOCK
105 if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
106 printk("pc: %p\n", __builtin_return_address(0));
107 BUG();
108 }
109#endif
110 /* 77 /*
111 * lock->slock : =1 : unlock 78 * lock->slock : =1 : unlock
112 * : <=0 : lock 79 * : <=0 : lock
@@ -118,7 +85,7 @@ static inline void _raw_spin_lock(spinlock_t *lock)
118 * } 85 * }
119 */ 86 */
120 __asm__ __volatile__ ( 87 __asm__ __volatile__ (
121 "# spin_lock \n\t" 88 "# __raw_spin_lock \n\t"
122 ".fillinsn \n" 89 ".fillinsn \n"
123 "1: \n\t" 90 "1: \n\t"
124 "mvfc %1, psw; \n\t" 91 "mvfc %1, psw; \n\t"
@@ -145,12 +112,8 @@ static inline void _raw_spin_lock(spinlock_t *lock)
145 ); 112 );
146} 113}
147 114
148static inline void _raw_spin_unlock(spinlock_t *lock) 115static inline void __raw_spin_unlock(raw_spinlock_t *lock)
149{ 116{
150#ifdef CONFIG_DEBUG_SPINLOCK
151 BUG_ON(lock->magic != SPINLOCK_MAGIC);
152 BUG_ON(!spin_is_locked(lock));
153#endif
154 mb(); 117 mb();
155 lock->slock = 1; 118 lock->slock = 1;
156} 119}
@@ -164,59 +127,32 @@ static inline void _raw_spin_unlock(spinlock_t *lock)
164 * can "mix" irq-safe locks - any writer needs to get a 127 * can "mix" irq-safe locks - any writer needs to get a
165 * irq-safe write-lock, but readers can get non-irqsafe 128 * irq-safe write-lock, but readers can get non-irqsafe
166 * read-locks. 129 * read-locks.
130 *
131 * On x86, we implement read-write locks as a 32-bit counter
132 * with the high bit (sign) being the "contended" bit.
133 *
134 * The inline assembly is non-obvious. Think about it.
135 *
136 * Changed to use the same technique as rw semaphores. See
137 * semaphore.h for details. -ben
167 */ 138 */
168typedef struct {
169 volatile int lock;
170#ifdef CONFIG_DEBUG_SPINLOCK
171 unsigned magic;
172#endif
173#ifdef CONFIG_PREEMPT
174 unsigned int break_lock;
175#endif
176} rwlock_t;
177
178#define RWLOCK_MAGIC 0xdeaf1eed
179
180#ifdef CONFIG_DEBUG_SPINLOCK
181#define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC
182#else
183#define RWLOCK_MAGIC_INIT /* */
184#endif
185
186#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
187
188#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
189 139
190/** 140/**
191 * read_can_lock - would read_trylock() succeed? 141 * read_can_lock - would read_trylock() succeed?
192 * @lock: the rwlock in question. 142 * @lock: the rwlock in question.
193 */ 143 */
194#define read_can_lock(x) ((int)(x)->lock > 0) 144#define __raw_read_can_lock(x) ((int)(x)->lock > 0)
195 145
196/** 146/**
197 * write_can_lock - would write_trylock() succeed? 147 * write_can_lock - would write_trylock() succeed?
198 * @lock: the rwlock in question. 148 * @lock: the rwlock in question.
199 */ 149 */
200#define write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) 150#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
201
202/*
203 * On x86, we implement read-write locks as a 32-bit counter
204 * with the high bit (sign) being the "contended" bit.
205 *
206 * The inline assembly is non-obvious. Think about it.
207 *
208 * Changed to use the same technique as rw semaphores. See
209 * semaphore.h for details. -ben
210 */
211/* the spinlock helpers are in arch/i386/kernel/semaphore.c */
212 151
213static inline void _raw_read_lock(rwlock_t *rw) 152static inline void __raw_read_lock(raw_rwlock_t *rw)
214{ 153{
215 unsigned long tmp0, tmp1; 154 unsigned long tmp0, tmp1;
216 155
217#ifdef CONFIG_DEBUG_SPINLOCK
218 BUG_ON(rw->magic != RWLOCK_MAGIC);
219#endif
220 /* 156 /*
221 * rw->lock : >0 : unlock 157 * rw->lock : >0 : unlock
222 * : <=0 : lock 158 * : <=0 : lock
@@ -264,13 +200,10 @@ static inline void _raw_read_lock(rwlock_t *rw)
264 ); 200 );
265} 201}
266 202
267static inline void _raw_write_lock(rwlock_t *rw) 203static inline void __raw_write_lock(raw_rwlock_t *rw)
268{ 204{
269 unsigned long tmp0, tmp1, tmp2; 205 unsigned long tmp0, tmp1, tmp2;
270 206
271#ifdef CONFIG_DEBUG_SPINLOCK
272 BUG_ON(rw->magic != RWLOCK_MAGIC);
273#endif
274 /* 207 /*
275 * rw->lock : =RW_LOCK_BIAS_STR : unlock 208 * rw->lock : =RW_LOCK_BIAS_STR : unlock
276 * : !=RW_LOCK_BIAS_STR : lock 209 * : !=RW_LOCK_BIAS_STR : lock
@@ -320,7 +253,7 @@ static inline void _raw_write_lock(rwlock_t *rw)
320 ); 253 );
321} 254}
322 255
323static inline void _raw_read_unlock(rwlock_t *rw) 256static inline void __raw_read_unlock(raw_rwlock_t *rw)
324{ 257{
325 unsigned long tmp0, tmp1; 258 unsigned long tmp0, tmp1;
326 259
@@ -342,7 +275,7 @@ static inline void _raw_read_unlock(rwlock_t *rw)
342 ); 275 );
343} 276}
344 277
345static inline void _raw_write_unlock(rwlock_t *rw) 278static inline void __raw_write_unlock(raw_rwlock_t *rw)
346{ 279{
347 unsigned long tmp0, tmp1, tmp2; 280 unsigned long tmp0, tmp1, tmp2;
348 281
@@ -366,9 +299,9 @@ static inline void _raw_write_unlock(rwlock_t *rw)
366 ); 299 );
367} 300}
368 301
369#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) 302#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
370 303
371static inline int _raw_write_trylock(rwlock_t *lock) 304static inline int __raw_write_trylock(raw_rwlock_t *lock)
372{ 305{
373 atomic_t *count = (atomic_t *)lock; 306 atomic_t *count = (atomic_t *)lock;
374 if (atomic_sub_and_test(RW_LOCK_BIAS, count)) 307 if (atomic_sub_and_test(RW_LOCK_BIAS, count))