vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc / lib / locks.c
index 0eaffa9..694163d 100644 (file)
@@ -91,44 +91,57 @@ void _raw_spin_unlock(spinlock_t *lp)
 }
 EXPORT_SYMBOL(_raw_spin_unlock);
 
-
 /*
- * Just like x86, implement read-write locks as a 32-bit counter
- * with the high bit (sign) being the "write" bit.
- * -- Cort
+ * For rwlocks, zero is unlocked, -1 is write-locked,
+ * positive is read-locked.
  */
-void _raw_read_lock(rwlock_t *rw)
+static __inline__ int __read_trylock(rwlock_t *rw)
 {
-       unsigned long stuck = INIT_STUCK;
-       int cpu = smp_processor_id();
+       signed int tmp;
+
+       __asm__ __volatile__(
+"2:    lwarx   %0,0,%1         # __read_trylock\n\
+       addic.  %0,%0,1\n\
+       ble-    1f\n"
+       PPC405_ERR77(0,%1)
+"      stwcx.  %0,0,%1\n\
+       bne-    2b\n\
+       isync\n\
+1:"
+       : "=&r"(tmp)
+       : "r"(&rw->lock)
+       : "cr0", "memory");
 
-again:
-       /* get our read lock in there */
-       atomic_inc((atomic_t *) &(rw)->lock);
-       if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */
-       {
-               /* turn off our read lock */
-               atomic_dec((atomic_t *) &(rw)->lock);
-               /* wait for the write lock to go away */
-               while ((signed long)((rw)->lock) < 0)
-               {
-                       if(!--stuck)
-                       {
-                               printk("_read_lock(%p) CPU#%d\n", rw, cpu);
+       return tmp;
+}
+
+int _raw_read_trylock(rwlock_t *rw)
+{
+       return __read_trylock(rw) > 0;
+}
+EXPORT_SYMBOL(_raw_read_trylock);
+
+void _raw_read_lock(rwlock_t *rw)
+{
+       unsigned int stuck;
+
+       while (__read_trylock(rw) <= 0) {
+               stuck = INIT_STUCK;
+               while (!read_can_lock(rw)) {
+                       if (--stuck == 0) {
+                               printk("_read_lock(%p) CPU#%d lock %d\n",
+                                      rw, _smp_processor_id(), rw->lock);
                                stuck = INIT_STUCK;
                        }
                }
-               /* try to get the read lock again */
-               goto again;
        }
-       wmb();
 }
 EXPORT_SYMBOL(_raw_read_lock);
 
 void _raw_read_unlock(rwlock_t *rw)
 {
        if ( rw->lock == 0 )
-               printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n",
+               printk("_read_unlock(): %s/%d (nip %08lX) lock %d\n",
                       current->comm,current->pid,current->thread.regs->nip,
                      rw->lock);
        wmb();
@@ -138,40 +151,17 @@ EXPORT_SYMBOL(_raw_read_unlock);
 
 void _raw_write_lock(rwlock_t *rw)
 {
-       unsigned long stuck = INIT_STUCK;
-       int cpu = smp_processor_id();
-
-again:
-       if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
-       {
-               while ( (rw)->lock & (1<<31) ) /* wait for write lock */
-               {
-                       if(!--stuck)
-                       {
-                               printk("write_lock(%p) CPU#%d lock %lx)\n",
-                                      rw, cpu,rw->lock);
-                               stuck = INIT_STUCK;
-                       }
-                       barrier();
-               }
-               goto again;
-       }
-
-       if ( (rw)->lock & ~(1<<31)) /* someone has a read lock */
-       {
-               /* clear our write lock and wait for reads to go away */
-               clear_bit(31,&(rw)->lock);
-               while ( (rw)->lock & ~(1<<31) )
-               {
-                       if(!--stuck)
-                       {
-                               printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
-                                      rw, cpu,rw->lock);
+       unsigned int stuck;
+
+       while (cmpxchg(&rw->lock, 0, -1) != 0) {
+               stuck = INIT_STUCK;
+               while (!write_can_lock(rw)) {
+                       if (--stuck == 0) {
+                               printk("write_lock(%p) CPU#%d lock %d)\n",
+                                      rw, _smp_processor_id(), rw->lock);
                                stuck = INIT_STUCK;
                        }
-                       barrier();
                }
-               goto again;
        }
        wmb();
 }
@@ -179,14 +169,8 @@ EXPORT_SYMBOL(_raw_write_lock);
 
 int _raw_write_trylock(rwlock_t *rw)
 {
-       if (test_and_set_bit(31, &(rw)->lock)) /* someone has a write lock */
+       if (cmpxchg(&rw->lock, 0, -1) != 0)
                return 0;
-
-       if ((rw)->lock & ~(1<<31)) {    /* someone has a read lock */
-               /* clear our write lock and wait for reads to go away */
-               clear_bit(31,&(rw)->lock);
-               return 0;
-       }
        wmb();
        return 1;
 }
@@ -194,12 +178,12 @@ EXPORT_SYMBOL(_raw_write_trylock);
 
 void _raw_write_unlock(rwlock_t *rw)
 {
-       if ( !(rw->lock & (1<<31)) )
-               printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n",
+       if (rw->lock >= 0)
+               printk("_write_lock(): %s/%d (nip %08lX) lock %d\n",
                      current->comm,current->pid,current->thread.regs->nip,
                      rw->lock);
        wmb();
-       clear_bit(31,&(rw)->lock);
+       rw->lock = 0;
 }
 EXPORT_SYMBOL(_raw_write_unlock);