Import changeset
[linux-flexiantxendom0-3.2.10.git] / arch / sparc64 / lib / debuglocks.c
1 /* $Id: debuglocks.c,v 1.5 2000/05/09 17:40:14 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 /* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
16 #ifdef SPIN_LOCK_DEBUG
17
18 #define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
19
20 static inline void show (char *str, spinlock_t *lock, unsigned long caller)
21 {
22         int cpu = smp_processor_id();
23
24         printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n",
25                str, lock, cpu, (unsigned int) caller,
26                lock->owner_pc, lock->owner_cpu);
27 }
28
29 static inline void show_read (char *str, rwlock_t *lock, unsigned long caller)
30 {
31         int cpu = smp_processor_id();
32
33         printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n",
34                str, lock, cpu, (unsigned int) caller,
35                lock->writer_pc, lock->writer_cpu);
36 }
37
38 static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
39 {
40         int cpu = smp_processor_id();
41
42         printk("%s(%p) CPU#%d stuck at %08x\n",
43                str, lock, cpu, (unsigned int) caller);
44         printk("Writer: PC(%08x):CPU(%x)\n",
45                lock->writer_pc, lock->writer_cpu);
46         printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n",
47                lock->reader_pc[0], lock->reader_pc[1],
48                lock->reader_pc[2], lock->reader_pc[3]);
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
60         GET_CALLER(caller);
61 again:
62         __asm__ __volatile__("ldstub [%1], %0"
63                              : "=r" (val)
64                              : "r" (&(lock->lock))
65                              : "memory");
66         membar("#StoreLoad | #StoreStore");
67         if (val) {
68                 while (lock->lock) {
69                         if (!--stuck) {
70                                 show(str, lock, caller);
71                                 stuck = INIT_STUCK;
72                         }
73                         membar("#LoadLoad");
74                 }
75                 goto again;
76         }
77         lock->owner_pc = ((unsigned int)caller);
78         lock->owner_cpu = cpu;
79 }
80
81 int _spin_trylock(spinlock_t *lock)
82 {
83         unsigned long val, caller;
84         int cpu = smp_processor_id();
85
86         GET_CALLER(caller);
87         __asm__ __volatile__("ldstub [%1], %0"
88                              : "=r" (val)
89                              : "r" (&(lock->lock))
90                              : "memory");
91         membar("#StoreLoad | #StoreStore");
92         if (!val) {
93                 lock->owner_pc = ((unsigned int)caller);
94                 lock->owner_cpu = cpu;
95         }
96         return val == 0;
97 }
98
99 void _do_spin_unlock(spinlock_t *lock)
100 {
101         lock->owner_pc = 0;
102         lock->owner_cpu = NO_PROC_ID;
103         membar("#StoreStore | #LoadStore");
104         lock->lock = 0;
105 }
106
107 /* Keep INIT_STUCK the same... */
108
109 void _do_read_lock (rwlock_t *rw, char *str)
110 {
111         unsigned long caller, val;
112         int stuck = INIT_STUCK;
113         int cpu = smp_processor_id();
114
115         GET_CALLER(caller);
116 wlock_again:
117         /* Wait for any writer to go away.  */
118         while (((long)(rw->lock)) < 0) {
119                 if (!--stuck) {
120                         show_read(str, rw, caller);
121                         stuck = INIT_STUCK;
122                 }
123                 membar("#LoadLoad");
124         }
125         /* Try once to increment the counter.  */
126         __asm__ __volatile__("
127         ldx             [%0], %%g5
128         brlz,a,pn       %%g5, 2f
129          mov            1, %0
130         add             %%g5, 1, %%g7
131         casx            [%0], %%g5, %%g7
132         sub             %%g5, %%g7, %0
133 2:"     : "=r" (val)
134         : "0" (&(rw->lock))
135         : "g5", "g7", "memory");
136         membar("#StoreLoad | #StoreStore");
137         if (val)
138                 goto wlock_again;
139         rw->reader_pc[cpu] = ((unsigned int)caller);
140 }
141
142 void _do_read_unlock (rwlock_t *rw, char *str)
143 {
144         unsigned long caller, val;
145         int stuck = INIT_STUCK;
146         int cpu = smp_processor_id();
147
148         GET_CALLER(caller);
149
150         /* Drop our identity _first_. */
151         rw->reader_pc[cpu] = 0;
152 runlock_again:
153         /* Spin trying to decrement the counter using casx.  */
154         __asm__ __volatile__("
155         ldx     [%0], %%g5
156         sub     %%g5, 1, %%g7
157         casx    [%0], %%g5, %%g7
158         membar  #StoreLoad | #StoreStore
159         sub     %%g5, %%g7, %0
160 "       : "=r" (val)
161         : "0" (&(rw->lock))
162         : "g5", "g7", "memory");
163         if (val) {
164                 if (!--stuck) {
165                         show_read(str, rw, caller);
166                         stuck = INIT_STUCK;
167                 }
168                 goto runlock_again;
169         }
170 }
171
172 void _do_write_lock (rwlock_t *rw, char *str)
173 {
174         unsigned long caller, val;
175         int stuck = INIT_STUCK;
176         int cpu = smp_processor_id();
177
178         GET_CALLER(caller);
179 wlock_again:
180         /* Spin while there is another writer. */
181         while (((long)rw->lock) < 0) {
182                 if (!--stuck) {
183                         show_write(str, rw, caller);
184                         stuck = INIT_STUCK;
185                 }
186                 membar("#LoadLoad");
187         }
188
189         /* Try to acuire the write bit.  */
190         __asm__ __volatile__("
191         mov     1, %%g3
192         sllx    %%g3, 63, %%g3
193         ldx     [%0], %%g5
194         brlz,pn %%g5, 1f
195          or     %%g5, %%g3, %%g7
196         casx    [%0], %%g5, %%g7
197         membar  #StoreLoad | #StoreStore
198         ba,pt   %%xcc, 2f
199          sub    %%g5, %%g7, %0
200 1:      mov     1, %0
201 2:"     : "=r" (val)
202         : "0" (&(rw->lock))
203         : "g3", "g5", "g7", "memory");
204         if (val) {
205                 /* We couldn't get the write bit. */
206                 if (!--stuck) {
207                         show_write(str, rw, caller);
208                         stuck = INIT_STUCK;
209                 }
210                 goto wlock_again;
211         }
212         if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
213                 /* Readers still around, drop the write
214                  * lock, spin, and try again.
215                  */
216                 if (!--stuck) {
217                         show_write(str, rw, caller);
218                         stuck = INIT_STUCK;
219                 }
220                 __asm__ __volatile__("
221                 mov     1, %%g3
222                 sllx    %%g3, 63, %%g3
223 1:              ldx     [%0], %%g5
224                 andn    %%g5, %%g3, %%g7
225                 casx    [%0], %%g5, %%g7
226                 cmp     %%g5, %%g7
227                 bne,pn  %%xcc, 1b
228                  membar #StoreLoad | #StoreStore"
229                 : /* no outputs */
230                 : "r" (&(rw->lock))
231                 : "g3", "g5", "g7", "cc", "memory");
232                 while(rw->lock != 0) {
233                         if (!--stuck) {
234                                 show_write(str, rw, caller);
235                                 stuck = INIT_STUCK;
236                         }
237                         membar("#LoadLoad");
238                 }
239                 goto wlock_again;
240         }
241
242         /* We have it, say who we are. */
243         rw->writer_pc = ((unsigned int)caller);
244         rw->writer_cpu = cpu;
245 }
246
247 void _do_write_unlock(rwlock_t *rw)
248 {
249         unsigned long caller, val;
250         int stuck = INIT_STUCK;
251
252         GET_CALLER(caller);
253
254         /* Drop our identity _first_ */
255         rw->writer_pc = 0;
256         rw->writer_cpu = NO_PROC_ID;
257 wlock_again:
258         __asm__ __volatile__("
259         mov     1, %%g3
260         sllx    %%g3, 63, %%g3
261         ldx     [%0], %%g5
262         andn    %%g5, %%g3, %%g7
263         casx    [%0], %%g5, %%g7
264         membar  #StoreLoad | #StoreStore
265         sub     %%g5, %%g7, %0
266 "       : "=r" (val)
267         : "0" (&(rw->lock))
268         : "g3", "g5", "g7", "memory");
269         if (val) {
270                 if (!--stuck) {
271                         show_write("write_unlock", rw, caller);
272                         stuck = INIT_STUCK;
273                 }
274                 goto wlock_again;
275         }
276 }
277
278 #endif /* SPIN_LOCK_DEBUG */
279 #endif /* CONFIG_SMP */