at v2.6.13-rc4 378 lines 8.2 kB view raw
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 17static 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 26static 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 35static 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 54void _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); 62again: 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 87int _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 110void _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 121void _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); 129wlock_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 160void _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--; 172runlock_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 196void _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); 204wlock_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" membar #StoreLoad | #StoreStore\n" 256" bne,pn %%xcc, 1b\n" 257" nop" 258 : /* no outputs */ 259 : "r" (&(rw->lock)) 260 : "g3", "g1", "g7", "cc", "memory"); 261 while(rw->lock != 0) { 262 if (!--stuck) { 263 if (shown++ <= 2) 264 show_write(str, rw, caller); 265 stuck = INIT_STUCK; 266 } 267 membar("#LoadLoad"); 268 } 269 goto wlock_again; 270 } 271 272 /* We have it, say who we are. */ 273 rw->writer_pc = ((unsigned int)caller); 274 rw->writer_cpu = cpu; 275 current->thread.smp_lock_count++; 276 current->thread.smp_lock_pc = ((unsigned int)caller); 277 278 put_cpu(); 279} 280 281void _do_write_unlock(rwlock_t *rw) 282{ 283 unsigned long caller, val; 284 int stuck = INIT_STUCK; 285 int shown = 0; 286 287 GET_CALLER(caller); 288 289 /* Drop our identity _first_ */ 290 rw->writer_pc = 0; 291 rw->writer_cpu = NO_PROC_ID; 292 current->thread.smp_lock_count--; 293wlock_again: 294 __asm__ __volatile__( 295" membar #StoreLoad | #LoadLoad\n" 296" mov 1, %%g3\n" 297" sllx %%g3, 63, %%g3\n" 298" ldx [%0], %%g1\n" 299" andn %%g1, %%g3, %%g7\n" 300" casx [%0], %%g1, %%g7\n" 301" membar #StoreLoad | #StoreStore\n" 302" sub %%g1, %%g7, %0\n" 303 : "=r" (val) 304 : "0" (&(rw->lock)) 305 : "g3", "g1", "g7", "memory"); 306 if (val) { 307 if (!--stuck) { 308 if (shown++ <= 2) 309 show_write("write_unlock", rw, caller); 310 stuck = INIT_STUCK; 311 } 312 goto wlock_again; 313 } 314} 315 316int _do_write_trylock (rwlock_t *rw, char *str) 317{ 318 unsigned long caller, val; 319 int cpu = get_cpu(); 320 321 GET_CALLER(caller); 322 323 /* Try to acuire the write bit. */ 324 __asm__ __volatile__( 325" mov 1, %%g3\n" 326" sllx %%g3, 63, %%g3\n" 327" ldx [%0], %%g1\n" 328" brlz,pn %%g1, 1f\n" 329" or %%g1, %%g3, %%g7\n" 330" casx [%0], %%g1, %%g7\n" 331" membar #StoreLoad | #StoreStore\n" 332" ba,pt %%xcc, 2f\n" 333" sub %%g1, %%g7, %0\n" 334"1: mov 1, %0\n" 335"2:" : "=r" (val) 336 : "0" (&(rw->lock)) 337 : "g3", "g1", "g7", "memory"); 338 339 if (val) { 340 put_cpu(); 341 return 0; 342 } 343 344 if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { 345 /* Readers still around, drop the write 346 * lock, return failure. 347 */ 348 __asm__ __volatile__( 349" mov 1, %%g3\n" 350" sllx %%g3, 63, %%g3\n" 351"1: ldx [%0], %%g1\n" 352" andn %%g1, %%g3, %%g7\n" 353" casx [%0], %%g1, %%g7\n" 354" cmp %%g1, %%g7\n" 355" membar #StoreLoad | #StoreStore\n" 356" bne,pn %%xcc, 1b\n" 357" nop" 358 : /* no outputs */ 359 : "r" (&(rw->lock)) 360 : "g3", "g1", "g7", "cc", "memory"); 361 362 put_cpu(); 363 364 return 0; 365 } 366 367 /* We have it, say who we are. */ 368 rw->writer_pc = ((unsigned int)caller); 369 rw->writer_cpu = cpu; 370 current->thread.smp_lock_count++; 371 current->thread.smp_lock_pc = ((unsigned int)caller); 372 373 put_cpu(); 374 375 return 1; 376} 377 378#endif /* CONFIG_SMP */