patch-2.1.97 linux/arch/ppc/lib/locks.c

Next file: linux/arch/ppc/mbx_defconfig
Previous file: linux/arch/ppc/kernel/traps.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.96/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c
@@ -1,5 +1,5 @@
 /*
- * $Id: locks.c,v 1.7 1998/01/06 06:44:59 cort Exp $
+ * $Id: locks.c,v 1.17 1998/03/26 22:19:38 cort Exp $
  *
  * Locks for smp ppc 
  * 
@@ -9,53 +9,78 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/spinlock.h>
+#include <asm/io.h>
 
 #define DEBUG_LOCKS 1
 
 #undef INIT_STUCK
-#define INIT_STUCK 10000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock(%p) CPU#%d nip %08lx\n", lock, cpu, nip); stuck = INIT_STUCK; }
+#define INIT_STUCK 1000000
 
 void _spin_lock(spinlock_t *lock)
 {
-	unsigned long val, nip = (unsigned long)__builtin_return_address(0);
 	int cpu = smp_processor_id();
+#ifdef DEBUG_LOCKS
 	int stuck = INIT_STUCK;
-	
-again:	
+#endif /* DEBUG_LOCKS */
 	/* try expensive atomic load/store to get lock */
-	__asm__ __volatile__(
-		"10: \n\t"
-		"lwarx %0,0,%1 \n\t"
-		"stwcx. %2,0,%1 \n\t"
-		"bne- 10b \n\t"
-		: "=r" (val)
-		: "r" (&(lock->lock)), "r" ( (cpu&3)|(nip&~3L) ));
-	if(val) {
+	while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) {
 		/* try cheap load until it's free */
 		while(lock->lock) {
-			STUCK;
+#ifdef DEBUG_LOCKS
+			if(!--stuck)
+			{
+				printk("_spin_lock(%p) CPU#%d NIP %p"
+				       " holder: cpu %ld pc %08lX\n",
+				       lock, cpu, __builtin_return_address(0),
+				       lock->owner_cpu,lock->owner_pc);
+				stuck = INIT_STUCK;
+				/* steal the lock */
+				/*xchg_u32((void *)&lock->lock,0);*/
+			}
+#endif /* DEBUG_LOCKS */
 			barrier();
 		}
-		goto again;
 	}
+	lock->owner_pc = (unsigned long)__builtin_return_address(0);
+	lock->owner_cpu = cpu;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+	unsigned long result;
+
+	result = (unsigned long )xchg_u32((void *)&lock->lock,0xffffffff);
+	if ( !result ) 
+	{ 
+		lock->owner_cpu = smp_processor_id(); 
+		lock->owner_pc = (unsigned long)__builtin_return_address(0);
+	} 
+	return (result == 0);
 }
 
+
+
 void _spin_unlock(spinlock_t *lp)
 {
+#ifdef DEBUG_LOCKS
+	if ( !lp->lock )
+		panic("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp,
+		       smp_processor_id(),current->comm,current->pid);
+	if ( lp->owner_cpu != smp_processor_id() )
+		panic("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
+		       lp, smp_processor_id(), (int)lp->owner_cpu,
+		       lp->owner_pc,lp->lock);
+#endif /* DEBUG_LOCKS */
+	lp->owner_pc = lp->owner_cpu = 0;
+	eieio();
 	lp->lock = 0;
+	eieio();
 }
 		
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("_read_lock(%p) CPU#%d\n", rw, cpu); stuck = INIT_STUCK; }
-
 /*
  * Just like x86, implement read-write locks as a 32-bit counter
  * with the high bit (sign) being the "write" bit.
@@ -63,8 +88,10 @@
  */
 void _read_lock(rwlock_t *rw)
 {
+#ifdef DEBUG_LOCKS
 	unsigned long stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+#endif /* DEBUG_LOCKS */		  
 
 again:	
 	/* get our read lock in there */
@@ -76,7 +103,13 @@
 		/* wait for the write lock to go away */
 		while ((signed long)((rw)->lock) < 0)
 		{
-			STUCK;
+#ifdef DEBUG_LOCKS
+			if(!--stuck)
+			{
+				printk("_read_lock(%p) CPU#%d\n", rw, cpu);
+				stuck = INIT_STUCK;
+			}
+#endif /* DEBUG_LOCKS */
 		}
 		/* try to get the read lock again */
 		goto again;
@@ -87,33 +120,34 @@
 {
 #ifdef DEBUG_LOCKS
 	if ( rw->lock == 0 )
-	{
-		if ( current)
 		printk("_read_unlock(): %s/%d (nip %08lX) lock %lx",
-		      current->comm,current->pid,current->tss.regs->nip,
+		       current->comm,current->pid,current->tss.regs->nip,
 		      rw->lock);
-		else
-		  printk("no current\n");
-	}
 #endif /* DEBUG_LOCKS */
 	atomic_dec((atomic_t *) &(rw)->lock);
 }
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock(%p) CPU#%d lock %lx)\n", rw, cpu,rw->lock); stuck = INIT_STUCK; }
-
 void _write_lock(rwlock_t *rw)
 {
+#ifdef DEBUG_LOCKS
 	unsigned long stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+#endif /* DEBUG_LOCKS */		  
 
 again:	
 	if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
 	{
 		while ( (rw)->lock & (1<<31) ) /* wait for write lock */
 		{
-			STUCK;
+#ifdef DEBUG_LOCKS
+			if(!--stuck)
+			{
+				printk("write_lock(%p) CPU#%d lock %lx)\n",
+				       rw, cpu,rw->lock);
+				stuck = INIT_STUCK;
+			}
+#endif /* DEBUG_LOCKS */		  
+			barrier();
 		}
 		goto again;
 	}
@@ -124,7 +158,15 @@
 		clear_bit(31,&(rw)->lock);
 		while ( (rw)->lock & ~(1<<31) )
 		{
-			STUCK;
+#ifdef DEBUG_LOCKS
+			if(!--stuck)
+			{
+				printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
+				       rw, cpu,rw->lock);
+				stuck = INIT_STUCK;
+			}
+#endif /* DEBUG_LOCKS */
+			barrier();
 		}
 		goto again;
 	}
@@ -134,14 +176,9 @@
 {
 #ifdef DEBUG_LOCKS
 	if ( !(rw->lock & (1<<31)) )
-	{
-		if ( current)
 		printk("_write_lock(): %s/%d (nip %08lX) lock %lx",
 		      current->comm,current->pid,current->tss.regs->nip,
 		      rw->lock);
-		else
-		  printk("no current\n");
-	}
 #endif /* DEBUG_LOCKS */
 	clear_bit(31,&(rw)->lock);
 }
@@ -149,6 +186,8 @@
 void __lock_kernel(struct task_struct *task)
 {
 #ifdef DEBUG_LOCKS
+	unsigned long stuck = INIT_STUCK;
+	
 	if ( (signed long)(task->lock_depth) < 0 )
 	{
 		printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
@@ -156,20 +195,40 @@
 		      task->lock_depth);
 	}
 #endif /* DEBUG_LOCKS */
+
+	if ( atomic_inc_return((atomic_t *) &task->lock_depth) != 1 )
+		return;
 	/* mine! */
-	if ( atomic_inc_return((atomic_t *) &task->lock_depth) == 1 )
-		klock_info.akp = smp_processor_id();
+	while ( xchg_u32( (void *)&klock_info.kernel_flag, KLOCK_HELD) )
+	{
+		/* try cheap load until it's free */
+		while(klock_info.kernel_flag) {
+#ifdef DEBUG_LOCKS
+			if(!--stuck)
+			{
+				printk("_lock_kernel() CPU#%d NIP %p\n",
+				       smp_processor_id(),
+				       __builtin_return_address(0));
+				stuck = INIT_STUCK;
+			}
+#endif /* DEBUG_LOCKS */
+			barrier();
+		}
+	}
+	
+	klock_info.akp = smp_processor_id();
 	/* my kernel mode! mine!!! */
 }
- 
+
 void __unlock_kernel(struct task_struct *task)
 {
 #ifdef DEBUG_LOCKS
- 	if ( task->lock_depth == 0 )
+ 	if ( (task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD) )
 	{
-		printk("__unlock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
-		      task->comm,task->pid,task->tss.regs->nip,
-		      task->lock_depth);
+		printk("__unlock_kernel(): %s/%d (nip %08lX) "
+		       "lock depth %x flags %lx\n",
+		       task->comm,task->pid,task->tss.regs->nip,
+		       task->lock_depth, klock_info.kernel_flag);
 		klock_info.akp = NO_PROC_ID;		
 		klock_info.kernel_flag = 0;
 		return;
@@ -177,8 +236,8 @@
 #endif /* DEBUG_LOCKS */
 	if ( atomic_dec_and_test((atomic_t *) &task->lock_depth) )
 	{
-		klock_info.akp = NO_PROC_ID;		
-		klock_info.kernel_flag = 0;
+		klock_info.akp = NO_PROC_ID;
+		klock_info.kernel_flag = KLOCK_CLEAR;
 	}
 }	
 
@@ -192,4 +251,3 @@
 		__sti();
        }
 }
-

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov