summaryrefslogtreecommitdiff
path: root/arch/sparc/lib/debuglocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/lib/debuglocks.c')
-rw-r--r--arch/sparc/lib/debuglocks.c202
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 */