Logo Search packages:      
Sourcecode: linux version File versions  Download package

locks.c

/*
 * Locks for smp ppc
 *
 * Written by Cort Dougan (cort@cs.nmt.edu)
 */

#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <asm/ppc_asm.h>
#include <asm/smp.h>

#ifdef CONFIG_DEBUG_SPINLOCK

#undef INIT_STUCK
#define INIT_STUCK 200000000 /*0xffffffff*/

/*
 * Try to acquire a spinlock.
 * Only does the stwcx. if the load returned 0 - the Programming
 * Environments Manual suggests not doing unnecessary stcwx.'s
 * since they may inhibit forward progress by other CPUs in getting
 * a lock.
 */
static inline unsigned long __spin_trylock(volatile unsigned long *lock)
{
      unsigned long ret;

      __asm__ __volatile__ ("\n\
1:    lwarx %0,0,%1\n\
      cmpwi 0,%0,0\n\
      bne   2f\n"
      PPC405_ERR77(0,%1)
"     stwcx.      %2,0,%1\n\
      bne-  1b\n\
      isync\n\
2:"
      : "=&r"(ret)
      : "r"(lock), "r"(1)
      : "cr0", "memory");

      return ret;
}

void _raw_spin_lock(spinlock_t *lock)
{
      int cpu = smp_processor_id();
      unsigned int stuck = INIT_STUCK;
      while (__spin_trylock(&lock->lock)) {
            while ((unsigned volatile long)lock->lock != 0) {
                  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);*/
                  }
            }
      }
      lock->owner_pc = (unsigned long)__builtin_return_address(0);
      lock->owner_cpu = cpu;
}
EXPORT_SYMBOL(_raw_spin_lock);

int _raw_spin_trylock(spinlock_t *lock)
{
      if (__spin_trylock(&lock->lock))
            return 0;
      lock->owner_cpu = smp_processor_id();
      lock->owner_pc = (unsigned long)__builtin_return_address(0);
      return 1;
}
EXPORT_SYMBOL(_raw_spin_trylock);

void _raw_spin_unlock(spinlock_t *lp)
{
      if ( !lp->lock )
            printk("_spin_unlock(%p): no lock cpu %d curr PC %p %s/%d\n",
                   lp, smp_processor_id(), __builtin_return_address(0),
                   current->comm, current->pid);
      if ( lp->owner_cpu != smp_processor_id() )
            printk("_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);
      lp->owner_pc = lp->owner_cpu = 0;
      wmb();
      lp->lock = 0;
}
EXPORT_SYMBOL(_raw_spin_unlock);

/*
 * For rwlocks, zero is unlocked, -1 is write-locked,
 * positive is read-locked.
 */
static __inline__ int __read_trylock(rwlock_t *rw)
{
      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");

      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, raw_smp_processor_id(), rw->lock);
                        stuck = INIT_STUCK;
                  }
            }
      }
}
EXPORT_SYMBOL(_raw_read_lock);

void _raw_read_unlock(rwlock_t *rw)
{
      if ( rw->lock == 0 )
            printk("_read_unlock(): %s/%d (nip %08lX) lock %d\n",
                   current->comm,current->pid,current->thread.regs->nip,
                  rw->lock);
      wmb();
      atomic_dec((atomic_t *) &(rw)->lock);
}
EXPORT_SYMBOL(_raw_read_unlock);

void _raw_write_lock(rwlock_t *rw)
{
      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, raw_smp_processor_id(), rw->lock);
                        stuck = INIT_STUCK;
                  }
            }
      }
      wmb();
}
EXPORT_SYMBOL(_raw_write_lock);

int _raw_write_trylock(rwlock_t *rw)
{
      if (cmpxchg(&rw->lock, 0, -1) != 0)
            return 0;
      wmb();
      return 1;
}
EXPORT_SYMBOL(_raw_write_trylock);

void _raw_write_unlock(rwlock_t *rw)
{
      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();
      rw->lock = 0;
}
EXPORT_SYMBOL(_raw_write_unlock);

#endif

Generated by  Doxygen 1.6.0   Back to index