diff options
Diffstat (limited to 'arch/sparc/lib/debuglocks.c')
-rw-r--r-- | arch/sparc/lib/debuglocks.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c new file mode 100644 index 00000000000..fb182352782 --- /dev/null +++ b/arch/sparc/lib/debuglocks.c @@ -0,0 +1,202 @@ +/* $Id: debuglocks.c,v 1.11 2001/09/20 00:35:31 davem Exp $ + * debuglocks.c: Debugging versions of SMP locking primitives. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/threads.h> /* For NR_CPUS */ +#include <linux/spinlock.h> +#include <asm/psr.h> +#include <asm/system.h> + +#ifdef CONFIG_SMP + +/* Some notes on how these debugging routines work. When a lock is acquired + * an extra debugging member lock->owner_pc is set to the caller of the lock + * acquisition routine. Right before releasing a lock, the debugging program + * counter is cleared to zero. + * + * Furthermore, since PC's are 4 byte aligned on Sparc, we stuff the CPU + * number of the owner in the lowest two bits. + */ + +#define STORE_CALLER(A) __asm__ __volatile__("mov %%i7, %0" : "=r" (A)); + +static inline void show(char *str, spinlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); +} + +static inline void show_read(char *str, rwlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); +} + +static inline void show_write(char *str, rwlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + int i; + + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)", str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); + + for(i = 0; i < NR_CPUS; i++) + printk(" reader[%d]=%08lx", i, lock->reader_pc[i]); + + printk("\n"); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +void _do_spin_lock(spinlock_t *lock, char *str) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + STORE_CALLER(caller); + +again: + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); + if(val) { + while(lock->lock) { + if (!--stuck) { + show(str, lock, caller); + stuck = INIT_STUCK; + } + barrier(); + } + goto again; + } + lock->owner_pc = (cpu & 3) | (caller & ~3); +} + +int _spin_trylock(spinlock_t *lock) +{ + unsigned long val; + unsigned long caller; + int cpu = smp_processor_id(); + + STORE_CALLER(caller); + + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); + if(!val) { + /* We got it, record our identity for debugging. */ + lock->owner_pc = (cpu & 3) | (caller & ~3); + } + return val == 0; +} + +void _do_spin_unlock(spinlock_t *lock) +{ + lock->owner_pc = 0; + barrier(); + lock->lock = 0; +} + +void _do_read_lock(rwlock_t *rw, char *str) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + STORE_CALLER(caller); + +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } + barrier(); + } + goto wlock_again; + } + + rw->reader_pc[cpu] = caller; + barrier(); + rw->lock++; +} + +void _do_read_unlock(rwlock_t *rw, char *str) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + STORE_CALLER(caller); + +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { + while(rw->lock & 0xff) { + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } + barrier(); + } + goto wlock_again; + } + + rw->reader_pc[cpu] = 0; + barrier(); + rw->lock -= 0x1ff; +} + +void _do_write_lock(rwlock_t *rw, char *str) +{ + unsigned long caller; + unsigned long val; + int cpu = smp_processor_id(); + int stuck = INIT_STUCK; + + STORE_CALLER(caller); + +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); + if(val) { +wlock_wait: + while(rw->lock) { + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + barrier(); + } + goto wlock_again; + } + + if (rw->lock & ~0xff) { + *(((unsigned char *)&rw->lock)+3) = 0; + barrier(); + goto wlock_wait; + } + + barrier(); + rw->owner_pc = (cpu & 3) | (caller & ~3); +} + +void _do_write_unlock(rwlock_t *rw) +{ + rw->owner_pc = 0; + barrier(); + rw->lock = 0; +} + +#endif /* SMP */ |