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