ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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 = smp_processor_id();
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
85 int _spin_trylock(spinlock_t *lock)
86 {
87         unsigned long val, caller;
88         int cpu = smp_processor_id();
89
90         GET_CALLER(caller);
91         __asm__ __volatile__("ldstub [%1], %0"
92                              : "=r" (val)
93                              : "r" (&(lock->lock))
94                              : "memory");
95         membar("#StoreLoad | #StoreStore");
96         if (!val) {
97                 lock->owner_pc = ((unsigned int)caller);
98                 lock->owner_cpu = cpu;
99                 current->thread.smp_lock_count++;
100                 current->thread.smp_lock_pc = ((unsigned int)caller);
101         }
102         return val == 0;
103 }
104
105 void _do_spin_unlock(spinlock_t *lock)
106 {
107         lock->owner_pc = 0;
108         lock->owner_cpu = NO_PROC_ID;
109         membar("#StoreStore | #LoadStore");
110         lock->lock = 0;
111         current->thread.smp_lock_count--;
112 }
113
114 /* Keep INIT_STUCK the same... */
115
116 void _do_read_lock (rwlock_t *rw, char *str)
117 {
118         unsigned long caller, val;
119         int stuck = INIT_STUCK;
120         int cpu = smp_processor_id();
121         int shown = 0;
122
123         GET_CALLER(caller);
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                 }
132                 membar("#LoadLoad");
133         }
134         /* Try once to increment the counter.  */
135         __asm__ __volatile__(
136 "       ldx             [%0], %%g5\n"
137 "       brlz,a,pn       %%g5, 2f\n"
138 "        mov            1, %0\n"
139 "       add             %%g5, 1, %%g7\n"
140 "       casx            [%0], %%g5, %%g7\n"
141 "       sub             %%g5, %%g7, %0\n"
142 "2:"    : "=r" (val)
143         : "0" (&(rw->lock))
144         : "g5", "g7", "memory");
145         membar("#StoreLoad | #StoreStore");
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
153 void _do_read_unlock (rwlock_t *rw, char *str)
154 {
155         unsigned long caller, val;
156         int stuck = INIT_STUCK;
157         int cpu = smp_processor_id();
158         int shown = 0;
159
160         GET_CALLER(caller);
161
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 "       ldx     [%0], %%g5\n"
169 "       sub     %%g5, 1, %%g7\n"
170 "       casx    [%0], %%g5, %%g7\n"
171 "       membar  #StoreLoad | #StoreStore\n"
172 "       sub     %%g5, %%g7, %0\n"
173         : "=r" (val)
174         : "0" (&(rw->lock))
175         : "g5", "g7", "memory");
176         if (val) {
177                 if (!--stuck) {
178                         if (shown++ <= 2)
179                                 show_read(str, rw, caller);
180                         stuck = INIT_STUCK;
181                 }
182                 goto runlock_again;
183         }
184 }
185
186 void _do_write_lock (rwlock_t *rw, char *str)
187 {
188         unsigned long caller, val;
189         int stuck = INIT_STUCK;
190         int cpu = smp_processor_id();
191         int shown = 0;
192
193         GET_CALLER(caller);
194 wlock_again:
195         /* Spin while there is another writer. */
196         while (((long)rw->lock) < 0) {
197                 if (!--stuck) {
198                         if (shown++ <= 2)
199                                 show_write(str, rw, caller);
200                         stuck = INIT_STUCK;
201                 }
202                 membar("#LoadLoad");
203         }
204
205         /* Try to acuire the write bit.  */
206         __asm__ __volatile__(
207 "       mov     1, %%g3\n"
208 "       sllx    %%g3, 63, %%g3\n"
209 "       ldx     [%0], %%g5\n"
210 "       brlz,pn %%g5, 1f\n"
211 "        or     %%g5, %%g3, %%g7\n"
212 "       casx    [%0], %%g5, %%g7\n"
213 "       membar  #StoreLoad | #StoreStore\n"
214 "       ba,pt   %%xcc, 2f\n"
215 "        sub    %%g5, %%g7, %0\n"
216 "1:     mov     1, %0\n"
217 "2:"    : "=r" (val)
218         : "0" (&(rw->lock))
219         : "g3", "g5", "g7", "memory");
220         if (val) {
221                 /* We couldn't get the write bit. */
222                 if (!--stuck) {
223                         if (shown++ <= 2)
224                                 show_write(str, rw, caller);
225                         stuck = INIT_STUCK;
226                 }
227                 goto wlock_again;
228         }
229         if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
230                 /* Readers still around, drop the write
231                  * lock, spin, and try again.
232                  */
233                 if (!--stuck) {
234                         if (shown++ <= 2)
235                                 show_write(str, rw, caller);
236                         stuck = INIT_STUCK;
237                 }
238                 __asm__ __volatile__(
239 "               mov     1, %%g3\n"
240 "               sllx    %%g3, 63, %%g3\n"
241 "1:             ldx     [%0], %%g5\n"
242 "               andn    %%g5, %%g3, %%g7\n"
243 "               casx    [%0], %%g5, %%g7\n"
244 "               cmp     %%g5, %%g7\n"
245 "               bne,pn  %%xcc, 1b\n"
246 "                membar #StoreLoad | #StoreStore"
247                 : /* no outputs */
248                 : "r" (&(rw->lock))
249                 : "g3", "g5", "g7", "cc", "memory");
250                 while(rw->lock != 0) {
251                         if (!--stuck) {
252                                 if (shown++ <= 2)
253                                         show_write(str, rw, caller);
254                                 stuck = INIT_STUCK;
255                         }
256                         membar("#LoadLoad");
257                 }
258                 goto wlock_again;
259         }
260
261         /* We have it, say who we are. */
262         rw->writer_pc = ((unsigned int)caller);
263         rw->writer_cpu = cpu;
264         current->thread.smp_lock_count++;
265         current->thread.smp_lock_pc = ((unsigned int)caller);
266 }
267
268 void _do_write_unlock(rwlock_t *rw)
269 {
270         unsigned long caller, val;
271         int stuck = INIT_STUCK;
272         int shown = 0;
273
274         GET_CALLER(caller);
275
276         /* Drop our identity _first_ */
277         rw->writer_pc = 0;
278         rw->writer_cpu = NO_PROC_ID;
279         current->thread.smp_lock_count--;
280 wlock_again:
281         __asm__ __volatile__(
282 "       mov     1, %%g3\n"
283 "       sllx    %%g3, 63, %%g3\n"
284 "       ldx     [%0], %%g5\n"
285 "       andn    %%g5, %%g3, %%g7\n"
286 "       casx    [%0], %%g5, %%g7\n"
287 "       membar  #StoreLoad | #StoreStore\n"
288 "       sub     %%g5, %%g7, %0\n"
289         : "=r" (val)
290         : "0" (&(rw->lock))
291         : "g3", "g5", "g7", "memory");
292         if (val) {
293                 if (!--stuck) {
294                         if (shown++ <= 2)
295                                 show_write("write_unlock", rw, caller);
296                         stuck = INIT_STUCK;
297                 }
298                 goto wlock_again;
299         }
300 }
301
302 #endif /* CONFIG_SMP */