Rev 422 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
422 | giacomo | 1 | #ifndef __ASM_SPINLOCK_H |
2 | #define __ASM_SPINLOCK_H |
||
3 | |||
4 | #include <asm/atomic.h> |
||
5 | #include <asm/rwlock.h> |
||
6 | #include <asm/page.h> |
||
7 | #include <linux/config.h> |
||
8 | #include <linux/compiler.h> |
||
9 | |||
10 | extern int printk(const char * fmt, ...) |
||
11 | __attribute__ ((format (printf, 1, 2))); |
||
12 | |||
13 | /* |
||
14 | * Your basic SMP spinlocks, allowing only a single CPU anywhere |
||
15 | */ |
||
16 | |||
17 | typedef struct { |
||
18 | volatile unsigned int lock; |
||
19 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
20 | unsigned magic; |
||
21 | #endif |
||
22 | } spinlock_t; |
||
23 | |||
24 | #define SPINLOCK_MAGIC 0xdead4ead |
||
25 | |||
26 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
27 | #define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC |
||
28 | #else |
||
29 | #define SPINLOCK_MAGIC_INIT /* */ |
||
30 | #endif |
||
31 | |||
32 | #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT } |
||
33 | |||
34 | #define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) |
||
35 | |||
36 | /* |
||
37 | * Simple spin lock operations. There are two variants, one clears IRQ's |
||
38 | * on the local processor, one does not. |
||
39 | * |
||
40 | * We make no fairness assumptions. They have a cost. |
||
41 | */ |
||
42 | |||
43 | #define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) |
||
44 | #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) |
||
45 | |||
46 | #define spin_lock_string \ |
||
47 | "\n1:\t" \ |
||
48 | "lock ; decb %0\n\t" \ |
||
49 | "js 2f\n" \ |
||
50 | LOCK_SECTION_START("") \ |
||
51 | "2:\t" \ |
||
52 | "rep;nop\n\t" \ |
||
53 | "cmpb $0,%0\n\t" \ |
||
54 | "jle 2b\n\t" \ |
||
55 | "jmp 1b\n" \ |
||
56 | LOCK_SECTION_END |
||
57 | |||
58 | /* |
||
59 | * This works. Despite all the confusion. |
||
60 | * (except on PPro SMP or if we are using OOSTORE) |
||
61 | * (PPro errata 66, 92) |
||
62 | */ |
||
63 | |||
64 | #if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE) |
||
65 | |||
66 | #define spin_unlock_string \ |
||
67 | "movb $1,%0" \ |
||
68 | :"=m" (lock->lock) : : "memory" |
||
69 | |||
70 | |||
71 | static inline void _raw_spin_unlock(spinlock_t *lock) |
||
72 | { |
||
73 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
74 | BUG_ON(lock->magic != SPINLOCK_MAGIC); |
||
75 | BUG_ON(!spin_is_locked(lock)); |
||
76 | #endif |
||
77 | __asm__ __volatile__( |
||
78 | spin_unlock_string |
||
79 | ); |
||
80 | } |
||
81 | |||
82 | #else |
||
83 | |||
84 | #define spin_unlock_string \ |
||
85 | "xchgb %b0, %1" \ |
||
86 | :"=q" (oldval), "=m" (lock->lock) \ |
||
87 | :"0" (oldval) : "memory" |
||
88 | |||
89 | static inline void _raw_spin_unlock(spinlock_t *lock) |
||
90 | { |
||
91 | char oldval = 1; |
||
92 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
93 | BUG_ON(lock->magic != SPINLOCK_MAGIC); |
||
94 | BUG_ON(!spin_is_locked(lock)); |
||
95 | #endif |
||
96 | __asm__ __volatile__( |
||
97 | spin_unlock_string |
||
98 | ); |
||
99 | } |
||
100 | |||
101 | #endif |
||
102 | |||
103 | static inline int _raw_spin_trylock(spinlock_t *lock) |
||
104 | { |
||
105 | char oldval; |
||
106 | __asm__ __volatile__( |
||
107 | "xchgb %b0,%1" |
||
108 | :"=q" (oldval), "=m" (lock->lock) |
||
109 | :"0" (0) : "memory"); |
||
110 | return oldval > 0; |
||
111 | } |
||
112 | |||
113 | static inline void _raw_spin_lock(spinlock_t *lock) |
||
114 | { |
||
115 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
116 | __label__ here; |
||
117 | here: |
||
118 | if (unlikely(lock->magic != SPINLOCK_MAGIC)) { |
||
119 | printk("eip: %p\n", &&here); |
||
120 | BUG(); |
||
121 | } |
||
122 | #endif |
||
123 | __asm__ __volatile__( |
||
124 | spin_lock_string |
||
125 | :"=m" (lock->lock) : : "memory"); |
||
126 | } |
||
127 | |||
128 | |||
129 | /* |
||
130 | * Read-write spinlocks, allowing multiple readers |
||
131 | * but only one writer. |
||
132 | * |
||
133 | * NOTE! it is quite common to have readers in interrupts |
||
134 | * but no interrupt writers. For those circumstances we |
||
135 | * can "mix" irq-safe locks - any writer needs to get a |
||
136 | * irq-safe write-lock, but readers can get non-irqsafe |
||
137 | * read-locks. |
||
138 | */ |
||
139 | typedef struct { |
||
140 | volatile unsigned int lock; |
||
141 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
142 | unsigned magic; |
||
143 | #endif |
||
144 | } rwlock_t; |
||
145 | |||
146 | #define RWLOCK_MAGIC 0xdeaf1eed |
||
147 | |||
148 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
149 | #define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC |
||
150 | #else |
||
151 | #define RWLOCK_MAGIC_INIT /* */ |
||
152 | #endif |
||
153 | |||
154 | #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } |
||
155 | |||
156 | #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) |
||
157 | |||
158 | #define rwlock_is_locked(x) ((x)->lock != RW_LOCK_BIAS) |
||
159 | |||
160 | /* |
||
161 | * On x86, we implement read-write locks as a 32-bit counter |
||
162 | * with the high bit (sign) being the "contended" bit. |
||
163 | * |
||
164 | * The inline assembly is non-obvious. Think about it. |
||
165 | * |
||
166 | * Changed to use the same technique as rw semaphores. See |
||
167 | * semaphore.h for details. -ben |
||
168 | */ |
||
169 | /* the spinlock helpers are in arch/i386/kernel/semaphore.c */ |
||
170 | |||
171 | static inline void _raw_read_lock(rwlock_t *rw) |
||
172 | { |
||
173 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
174 | BUG_ON(rw->magic != RWLOCK_MAGIC); |
||
175 | #endif |
||
176 | __build_read_lock(rw, "__read_lock_failed"); |
||
177 | } |
||
178 | |||
179 | static inline void _raw_write_lock(rwlock_t *rw) |
||
180 | { |
||
181 | #ifdef CONFIG_DEBUG_SPINLOCK |
||
182 | BUG_ON(rw->magic != RWLOCK_MAGIC); |
||
183 | #endif |
||
184 | __build_write_lock(rw, "__write_lock_failed"); |
||
185 | } |
||
186 | |||
187 | #define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") |
||
188 | #define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") |
||
189 | |||
190 | static inline int _raw_write_trylock(rwlock_t *lock) |
||
191 | { |
||
192 | atomic_t *count = (atomic_t *)lock; |
||
193 | if (atomic_sub_and_test(RW_LOCK_BIAS, count)) |
||
194 | return 1; |
||
195 | atomic_add(RW_LOCK_BIAS, count); |
||
196 | return 0; |
||
197 | } |
||
198 | |||
199 | #endif /* __ASM_SPINLOCK_H */ |