7c92819016a2ddfa2fa1b0eb4dba2cbee1320742
[linux-flexiantxendom0-3.2.10.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 #if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
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
39         printk("%s(%p) CPU#%d stuck at %08x\n",
40                str, lock, cpu, (unsigned int) caller);
41         printk("Writer: PC(%08x):CPU(%x)\n",
42                lock->writer_pc, lock->writer_cpu);
43         printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n",
44                lock->reader_pc[0], lock->reader_pc[1],
45                lock->reader_pc[2], lock->reader_pc[3]);
46 }
47
48 #undef INIT_STUCK
49 #define INIT_STUCK 100000000
50
51 void _do_spin_lock(spinlock_t *lock, char *str)
52 {
53         unsigned long caller, val;
54         int stuck = INIT_STUCK;
55         int cpu = smp_processor_id();
56         int shown = 0;
57
58         GET_CALLER(caller);
59 again:
60         __asm__ __volatile__("ldstub [%1], %0"
61                              : "=r" (val)
62                              : "r" (&(lock->lock))
63                              : "memory");
64         membar("#StoreLoad | #StoreStore");
65         if (val) {
66                 while (lock->lock) {
67                         if (!--stuck) {
68                                 if (shown++ <= 2)
69                                         show(str, lock, caller);
70                                 stuck = INIT_STUCK;
71                         }
72                         membar("#LoadLoad");
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
82 int _spin_trylock(spinlock_t *lock)
83 {
84         unsigned long val, caller;
85         int cpu = smp_processor_id();
86
87         GET_CALLER(caller);
88         __asm__ __volatile__("ldstub [%1], %0"
89                              : "=r" (val)
90                              : "r" (&(lock->lock))
91                              : "memory");
92         membar("#StoreLoad | #StoreStore");
93         if (!val) {
94                 lock->owner_pc = ((unsigned int)caller);
95                 lock->owner_cpu = cpu;
96                 current->thread.smp_lock_count++;
97                 current->thread.smp_lock_pc = ((unsigned int)caller);
98         }
99         return val == 0;
100 }
101
102 void _do_spin_unlock(spinlock_t *lock)
103 {
104         lock->owner_pc = 0;
105         lock->owner_cpu = NO_PROC_ID;
106         membar("#StoreStore | #LoadStore");
107         lock->lock = 0;
108         current->thread.smp_lock_count--;
109 }
110
111 /* Keep INIT_STUCK the same... */
112
113 void _do_read_lock (rwlock_t *rw, char *str)
114 {
115         unsigned long caller, val;
116         int stuck = INIT_STUCK;
117         int cpu = smp_processor_id();
118         int shown = 0;
119
120         GET_CALLER(caller);
121 wlock_again:
122         /* Wait for any writer to go away.  */
123         while (((long)(rw->lock)) < 0) {
124                 if (!--stuck) {
125                         if (shown++ <= 2)
126                                 show_read(str, rw, caller);
127                         stuck = INIT_STUCK;
128                 }
129                 membar("#LoadLoad");
130         }
131         /* Try once to increment the counter.  */
132         __asm__ __volatile__(
133 "       ldx             [%0], %%g5\n"
134 "       brlz,a,pn       %%g5, 2f\n"
135 "        mov            1, %0\n"
136 "       add             %%g5, 1, %%g7\n"
137 "       casx            [%0], %%g5, %%g7\n"
138 "       sub             %%g5, %%g7, %0\n"
139 "2:"    : "=r" (val)
140         : "0" (&(rw->lock))
141         : "g5", "g7", "memory");
142         membar("#StoreLoad | #StoreStore");
143         if (val)
144                 goto wlock_again;
145         rw->reader_pc[cpu] = ((unsigned int)caller);
146         current->thread.smp_lock_count++;
147         current->thread.smp_lock_pc = ((unsigned int)caller);
148 }
149
150 void _do_read_unlock (rwlock_t *rw, char *str)
151 {
152         unsigned long caller, val;
153         int stuck = INIT_STUCK;
154         int cpu = smp_processor_id();
155         int shown = 0;
156
157         GET_CALLER(caller);
158
159         /* Drop our identity _first_. */
160         rw->reader_pc[cpu] = 0;
161         current->thread.smp_lock_count--;
162 runlock_again:
163         /* Spin trying to decrement the counter using casx.  */
164         __asm__ __volatile__(
165 "       ldx     [%0], %%g5\n"
166 "       sub     %%g5, 1, %%g7\n"
167 "       casx    [%0], %%g5, %%g7\n"
168 "       membar  #StoreLoad | #StoreStore\n"
169 "       sub     %%g5, %%g7, %0\n"
170         : "=r" (val)
171         : "0" (&(rw->lock))
172         : "g5", "g7", "memory");
173         if (val) {
174                 if (!--stuck) {
175                         if (shown++ <= 2)
176                                 show_read(str, rw, caller);
177                         stuck = INIT_STUCK;
178                 }
179                 goto runlock_again;
180         }
181 }
182
183 void _do_write_lock (rwlock_t *rw, char *str)
184 {
185         unsigned long caller, val;
186         int stuck = INIT_STUCK;
187         int cpu = smp_processor_id();
188         int shown = 0;
189
190         GET_CALLER(caller);
191 wlock_again:
192         /* Spin while there is another writer. */
193         while (((long)rw->lock) < 0) {
194                 if (!--stuck) {
195                         if (shown++ <= 2)
196                                 show_write(str, rw, caller);
197                         stuck = INIT_STUCK;
198                 }
199                 membar("#LoadLoad");
200         }
201
202         /* Try to acuire the write bit.  */
203         __asm__ __volatile__(
204 "       mov     1, %%g3\n"
205 "       sllx    %%g3, 63, %%g3\n"
206 "       ldx     [%0], %%g5\n"
207 "       brlz,pn %%g5, 1f\n"
208 "        or     %%g5, %%g3, %%g7\n"
209 "       casx    [%0], %%g5, %%g7\n"
210 "       membar  #StoreLoad | #StoreStore\n"
211 "       ba,pt   %%xcc, 2f\n"
212 "        sub    %%g5, %%g7, %0\n"
213 "1:     mov     1, %0\n"
214 "2:"    : "=r" (val)
215         : "0" (&(rw->lock))
216         : "g3", "g5", "g7", "memory");
217         if (val) {
218                 /* We couldn't get the write bit. */
219                 if (!--stuck) {
220                         if (shown++ <= 2)
221                                 show_write(str, rw, caller);
222                         stuck = INIT_STUCK;
223                 }
224                 goto wlock_again;
225         }
226         if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
227                 /* Readers still around, drop the write
228                  * lock, spin, and try again.
229                  */
230                 if (!--stuck) {
231                         if (shown++ <= 2)
232                                 show_write(str, rw, caller);
233                         stuck = INIT_STUCK;
234                 }
235                 __asm__ __volatile__(
236 "               mov     1, %%g3\n"
237 "               sllx    %%g3, 63, %%g3\n"
238 "1:             ldx     [%0], %%g5\n"
239 "               andn    %%g5, %%g3, %%g7\n"
240 "               casx    [%0], %%g5, %%g7\n"
241 "               cmp     %%g5, %%g7\n"
242 "               bne,pn  %%xcc, 1b\n"
243 "                membar #StoreLoad | #StoreStore"
244                 : /* no outputs */
245                 : "r" (&(rw->lock))
246                 : "g3", "g5", "g7", "cc", "memory");
247                 while(rw->lock != 0) {
248                         if (!--stuck) {
249                                 if (shown++ <= 2)
250                                         show_write(str, rw, caller);
251                                 stuck = INIT_STUCK;
252                         }
253                         membar("#LoadLoad");
254                 }
255                 goto wlock_again;
256         }
257
258         /* We have it, say who we are. */
259         rw->writer_pc = ((unsigned int)caller);
260         rw->writer_cpu = cpu;
261         current->thread.smp_lock_count++;
262         current->thread.smp_lock_pc = ((unsigned int)caller);
263 }
264
265 void _do_write_unlock(rwlock_t *rw)
266 {
267         unsigned long caller, val;
268         int stuck = INIT_STUCK;
269         int shown = 0;
270
271         GET_CALLER(caller);
272
273         /* Drop our identity _first_ */
274         rw->writer_pc = 0;
275         rw->writer_cpu = NO_PROC_ID;
276         current->thread.smp_lock_count--;
277 wlock_again:
278         __asm__ __volatile__(
279 "       mov     1, %%g3\n"
280 "       sllx    %%g3, 63, %%g3\n"
281 "       ldx     [%0], %%g5\n"
282 "       andn    %%g5, %%g3, %%g7\n"
283 "       casx    [%0], %%g5, %%g7\n"
284 "       membar  #StoreLoad | #StoreStore\n"
285 "       sub     %%g5, %%g7, %0\n"
286         : "=r" (val)
287         : "0" (&(rw->lock))
288         : "g3", "g5", "g7", "memory");
289         if (val) {
290                 if (!--stuck) {
291                         if (shown++ <= 2)
292                                 show_write("write_unlock", rw, caller);
293                         stuck = INIT_STUCK;
294                 }
295                 goto wlock_again;
296         }
297 }
298
299 #endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */