Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $ |
2 | * debuglocks.c: Debugging versions of SMP locking primitives. | |
3 | * | |
4 | * Copyright (C) 1998 David S. Miller (davem@redhat.com) | |
5 | */ | |
6 | ||
7 | #include <linux/config.h> | |
8 | #include <linux/kernel.h> | |
9 | #include <linux/sched.h> | |
10 | #include <linux/spinlock.h> | |
11 | #include <asm/system.h> | |
12 | ||
13 | #ifdef CONFIG_SMP | |
14 | ||
1da177e4 LT |
15 | static inline void show (char *str, spinlock_t *lock, unsigned long caller) |
16 | { | |
17 | int cpu = smp_processor_id(); | |
18 | ||
19 | printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n", | |
20 | str, lock, cpu, (unsigned int) caller, | |
21 | lock->owner_pc, lock->owner_cpu); | |
22 | } | |
23 | ||
24 | static inline void show_read (char *str, rwlock_t *lock, unsigned long caller) | |
25 | { | |
26 | int cpu = smp_processor_id(); | |
27 | ||
28 | printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n", | |
29 | str, lock, cpu, (unsigned int) caller, | |
30 | lock->writer_pc, lock->writer_cpu); | |
31 | } | |
32 | ||
33 | static inline void show_write (char *str, rwlock_t *lock, unsigned long caller) | |
34 | { | |
35 | int cpu = smp_processor_id(); | |
36 | int i; | |
37 | ||
38 | printk("%s(%p) CPU#%d stuck at %08x\n", | |
39 | str, lock, cpu, (unsigned int) caller); | |
40 | printk("Writer: PC(%08x):CPU(%x)\n", | |
41 | lock->writer_pc, lock->writer_cpu); | |
42 | printk("Readers:"); | |
43 | for (i = 0; i < NR_CPUS; i++) | |
44 | if (lock->reader_pc[i]) | |
45 | printk(" %d[%08x]", i, lock->reader_pc[i]); | |
46 | printk("\n"); | |
47 | } | |
48 | ||
49 | #undef INIT_STUCK | |
50 | #define INIT_STUCK 100000000 | |
51 | ||
442464a5 | 52 | void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller) |
1da177e4 | 53 | { |
442464a5 | 54 | unsigned long val; |
1da177e4 LT |
55 | int stuck = INIT_STUCK; |
56 | int cpu = get_cpu(); | |
57 | int shown = 0; | |
58 | ||
1da177e4 LT |
59 | again: |
60 | __asm__ __volatile__("ldstub [%1], %0" | |
61 | : "=r" (val) | |
62 | : "r" (&(lock->lock)) | |
63 | : "memory"); | |
4f07118f | 64 | membar_storeload_storestore(); |
1da177e4 LT |
65 | if (val) { |
66 | while (lock->lock) { | |
67 | if (!--stuck) { | |
68 | if (shown++ <= 2) | |
69 | show(str, lock, caller); | |
70 | stuck = INIT_STUCK; | |
71 | } | |
4f07118f | 72 | rmb(); |
1da177e4 LT |
73 | } |
74 | goto again; | |
75 | } | |
76 | lock->owner_pc = ((unsigned int)caller); | |
77 | lock->owner_cpu = cpu; | |
78 | current->thread.smp_lock_count++; | |
79 | current->thread.smp_lock_pc = ((unsigned int)caller); | |
80 | ||
81 | put_cpu(); | |
82 | } | |
83 | ||
442464a5 | 84 | int _do_spin_trylock(spinlock_t *lock, unsigned long caller) |
1da177e4 | 85 | { |
442464a5 | 86 | unsigned long val; |
1da177e4 LT |
87 | int cpu = get_cpu(); |
88 | ||
1da177e4 LT |
89 | __asm__ __volatile__("ldstub [%1], %0" |
90 | : "=r" (val) | |
91 | : "r" (&(lock->lock)) | |
92 | : "memory"); | |
4f07118f | 93 | membar_storeload_storestore(); |
1da177e4 LT |
94 | if (!val) { |
95 | lock->owner_pc = ((unsigned int)caller); | |
96 | lock->owner_cpu = cpu; | |
97 | current->thread.smp_lock_count++; | |
98 | current->thread.smp_lock_pc = ((unsigned int)caller); | |
99 | } | |
100 | ||
101 | put_cpu(); | |
102 | ||
103 | return val == 0; | |
104 | } | |
105 | ||
106 | void _do_spin_unlock(spinlock_t *lock) | |
107 | { | |
108 | lock->owner_pc = 0; | |
109 | lock->owner_cpu = NO_PROC_ID; | |
4f07118f | 110 | membar_storestore_loadstore(); |
1da177e4 LT |
111 | lock->lock = 0; |
112 | current->thread.smp_lock_count--; | |
113 | } | |
114 | ||
115 | /* Keep INIT_STUCK the same... */ | |
116 | ||
442464a5 | 117 | void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller) |
1da177e4 | 118 | { |
442464a5 | 119 | unsigned long val; |
1da177e4 LT |
120 | int stuck = INIT_STUCK; |
121 | int cpu = get_cpu(); | |
122 | int shown = 0; | |
123 | ||
1da177e4 LT |
124 | wlock_again: |
125 | /* Wait for any writer to go away. */ | |
126 | while (((long)(rw->lock)) < 0) { | |
127 | if (!--stuck) { | |
128 | if (shown++ <= 2) | |
129 | show_read(str, rw, caller); | |
130 | stuck = INIT_STUCK; | |
131 | } | |
4f07118f | 132 | rmb(); |
1da177e4 LT |
133 | } |
134 | /* Try once to increment the counter. */ | |
135 | __asm__ __volatile__( | |
136 | " ldx [%0], %%g1\n" | |
137 | " brlz,a,pn %%g1, 2f\n" | |
138 | " mov 1, %0\n" | |
139 | " add %%g1, 1, %%g7\n" | |
140 | " casx [%0], %%g1, %%g7\n" | |
141 | " sub %%g1, %%g7, %0\n" | |
142 | "2:" : "=r" (val) | |
143 | : "0" (&(rw->lock)) | |
144 | : "g1", "g7", "memory"); | |
4f07118f | 145 | membar_storeload_storestore(); |
1da177e4 LT |
146 | if (val) |
147 | goto wlock_again; | |
148 | rw->reader_pc[cpu] = ((unsigned int)caller); | |
149 | current->thread.smp_lock_count++; | |
150 | current->thread.smp_lock_pc = ((unsigned int)caller); | |
151 | ||
152 | put_cpu(); | |
153 | } | |
154 | ||
442464a5 | 155 | void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller) |
1da177e4 | 156 | { |
442464a5 | 157 | unsigned long val; |
1da177e4 LT |
158 | int stuck = INIT_STUCK; |
159 | int cpu = get_cpu(); | |
160 | int shown = 0; | |
161 | ||
1da177e4 LT |
162 | /* Drop our identity _first_. */ |
163 | rw->reader_pc[cpu] = 0; | |
164 | current->thread.smp_lock_count--; | |
165 | runlock_again: | |
166 | /* Spin trying to decrement the counter using casx. */ | |
167 | __asm__ __volatile__( | |
168 | " membar #StoreLoad | #LoadLoad\n" | |
169 | " ldx [%0], %%g1\n" | |
170 | " sub %%g1, 1, %%g7\n" | |
171 | " casx [%0], %%g1, %%g7\n" | |
172 | " membar #StoreLoad | #StoreStore\n" | |
173 | " sub %%g1, %%g7, %0\n" | |
174 | : "=r" (val) | |
175 | : "0" (&(rw->lock)) | |
176 | : "g1", "g7", "memory"); | |
177 | if (val) { | |
178 | if (!--stuck) { | |
179 | if (shown++ <= 2) | |
180 | show_read(str, rw, caller); | |
181 | stuck = INIT_STUCK; | |
182 | } | |
183 | goto runlock_again; | |
184 | } | |
185 | ||
186 | put_cpu(); | |
187 | } | |
188 | ||
442464a5 | 189 | void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller) |
1da177e4 | 190 | { |
442464a5 | 191 | unsigned long val; |
1da177e4 LT |
192 | int stuck = INIT_STUCK; |
193 | int cpu = get_cpu(); | |
194 | int shown = 0; | |
195 | ||
1da177e4 LT |
196 | wlock_again: |
197 | /* Spin while there is another writer. */ | |
198 | while (((long)rw->lock) < 0) { | |
199 | if (!--stuck) { | |
200 | if (shown++ <= 2) | |
201 | show_write(str, rw, caller); | |
202 | stuck = INIT_STUCK; | |
203 | } | |
4f07118f | 204 | rmb(); |
1da177e4 LT |
205 | } |
206 | ||
207 | /* Try to acuire the write bit. */ | |
208 | __asm__ __volatile__( | |
209 | " mov 1, %%g3\n" | |
210 | " sllx %%g3, 63, %%g3\n" | |
211 | " ldx [%0], %%g1\n" | |
212 | " brlz,pn %%g1, 1f\n" | |
213 | " or %%g1, %%g3, %%g7\n" | |
214 | " casx [%0], %%g1, %%g7\n" | |
215 | " membar #StoreLoad | #StoreStore\n" | |
216 | " ba,pt %%xcc, 2f\n" | |
217 | " sub %%g1, %%g7, %0\n" | |
218 | "1: mov 1, %0\n" | |
219 | "2:" : "=r" (val) | |
220 | : "0" (&(rw->lock)) | |
221 | : "g3", "g1", "g7", "memory"); | |
222 | if (val) { | |
223 | /* We couldn't get the write bit. */ | |
224 | if (!--stuck) { | |
225 | if (shown++ <= 2) | |
226 | show_write(str, rw, caller); | |
227 | stuck = INIT_STUCK; | |
228 | } | |
229 | goto wlock_again; | |
230 | } | |
231 | if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { | |
232 | /* Readers still around, drop the write | |
233 | * lock, spin, and try again. | |
234 | */ | |
235 | if (!--stuck) { | |
236 | if (shown++ <= 2) | |
237 | show_write(str, rw, caller); | |
238 | stuck = INIT_STUCK; | |
239 | } | |
240 | __asm__ __volatile__( | |
241 | " mov 1, %%g3\n" | |
242 | " sllx %%g3, 63, %%g3\n" | |
243 | "1: ldx [%0], %%g1\n" | |
244 | " andn %%g1, %%g3, %%g7\n" | |
245 | " casx [%0], %%g1, %%g7\n" | |
246 | " cmp %%g1, %%g7\n" | |
b445e26c | 247 | " membar #StoreLoad | #StoreStore\n" |
1da177e4 | 248 | " bne,pn %%xcc, 1b\n" |
b445e26c | 249 | " nop" |
1da177e4 LT |
250 | : /* no outputs */ |
251 | : "r" (&(rw->lock)) | |
252 | : "g3", "g1", "g7", "cc", "memory"); | |
253 | while(rw->lock != 0) { | |
254 | if (!--stuck) { | |
255 | if (shown++ <= 2) | |
256 | show_write(str, rw, caller); | |
257 | stuck = INIT_STUCK; | |
258 | } | |
4f07118f | 259 | rmb(); |
1da177e4 LT |
260 | } |
261 | goto wlock_again; | |
262 | } | |
263 | ||
264 | /* We have it, say who we are. */ | |
265 | rw->writer_pc = ((unsigned int)caller); | |
266 | rw->writer_cpu = cpu; | |
267 | current->thread.smp_lock_count++; | |
268 | current->thread.smp_lock_pc = ((unsigned int)caller); | |
269 | ||
270 | put_cpu(); | |
271 | } | |
272 | ||
442464a5 | 273 | void _do_write_unlock(rwlock_t *rw, unsigned long caller) |
1da177e4 | 274 | { |
442464a5 | 275 | unsigned long val; |
1da177e4 LT |
276 | int stuck = INIT_STUCK; |
277 | int shown = 0; | |
278 | ||
1da177e4 LT |
279 | /* Drop our identity _first_ */ |
280 | rw->writer_pc = 0; | |
281 | rw->writer_cpu = NO_PROC_ID; | |
282 | current->thread.smp_lock_count--; | |
283 | wlock_again: | |
284 | __asm__ __volatile__( | |
285 | " membar #StoreLoad | #LoadLoad\n" | |
286 | " mov 1, %%g3\n" | |
287 | " sllx %%g3, 63, %%g3\n" | |
288 | " ldx [%0], %%g1\n" | |
289 | " andn %%g1, %%g3, %%g7\n" | |
290 | " casx [%0], %%g1, %%g7\n" | |
291 | " membar #StoreLoad | #StoreStore\n" | |
292 | " sub %%g1, %%g7, %0\n" | |
293 | : "=r" (val) | |
294 | : "0" (&(rw->lock)) | |
295 | : "g3", "g1", "g7", "memory"); | |
296 | if (val) { | |
297 | if (!--stuck) { | |
298 | if (shown++ <= 2) | |
299 | show_write("write_unlock", rw, caller); | |
300 | stuck = INIT_STUCK; | |
301 | } | |
302 | goto wlock_again; | |
303 | } | |
304 | } | |
305 | ||
442464a5 | 306 | int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller) |
1da177e4 | 307 | { |
442464a5 | 308 | unsigned long val; |
1da177e4 LT |
309 | int cpu = get_cpu(); |
310 | ||
1da177e4 LT |
311 | /* Try to acuire the write bit. */ |
312 | __asm__ __volatile__( | |
313 | " mov 1, %%g3\n" | |
314 | " sllx %%g3, 63, %%g3\n" | |
315 | " ldx [%0], %%g1\n" | |
316 | " brlz,pn %%g1, 1f\n" | |
317 | " or %%g1, %%g3, %%g7\n" | |
318 | " casx [%0], %%g1, %%g7\n" | |
319 | " membar #StoreLoad | #StoreStore\n" | |
320 | " ba,pt %%xcc, 2f\n" | |
321 | " sub %%g1, %%g7, %0\n" | |
322 | "1: mov 1, %0\n" | |
323 | "2:" : "=r" (val) | |
324 | : "0" (&(rw->lock)) | |
325 | : "g3", "g1", "g7", "memory"); | |
326 | ||
327 | if (val) { | |
328 | put_cpu(); | |
329 | return 0; | |
330 | } | |
331 | ||
332 | if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { | |
333 | /* Readers still around, drop the write | |
334 | * lock, return failure. | |
335 | */ | |
336 | __asm__ __volatile__( | |
337 | " mov 1, %%g3\n" | |
338 | " sllx %%g3, 63, %%g3\n" | |
339 | "1: ldx [%0], %%g1\n" | |
340 | " andn %%g1, %%g3, %%g7\n" | |
341 | " casx [%0], %%g1, %%g7\n" | |
342 | " cmp %%g1, %%g7\n" | |
b445e26c | 343 | " membar #StoreLoad | #StoreStore\n" |
1da177e4 | 344 | " bne,pn %%xcc, 1b\n" |
b445e26c | 345 | " nop" |
1da177e4 LT |
346 | : /* no outputs */ |
347 | : "r" (&(rw->lock)) | |
348 | : "g3", "g1", "g7", "cc", "memory"); | |
349 | ||
350 | put_cpu(); | |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
355 | /* We have it, say who we are. */ | |
356 | rw->writer_pc = ((unsigned int)caller); | |
357 | rw->writer_cpu = cpu; | |
358 | current->thread.smp_lock_count++; | |
359 | current->thread.smp_lock_pc = ((unsigned int)caller); | |
360 | ||
361 | put_cpu(); | |
362 | ||
363 | return 1; | |
364 | } | |
365 | ||
366 | #endif /* CONFIG_SMP */ |