linux/arch/parisc/include/asm/spinlock.h
<<
>>
Prefs
   1#ifndef __ASM_SPINLOCK_H
   2#define __ASM_SPINLOCK_H
   3
   4#include <asm/system.h>
   5#include <asm/processor.h>
   6#include <asm/spinlock_types.h>
   7
   8static inline int __raw_spin_is_locked(raw_spinlock_t *x)
   9{
  10        volatile unsigned int *a = __ldcw_align(x);
  11        return *a == 0;
  12}
  13
  14#define __raw_spin_lock(lock) __raw_spin_lock_flags(lock, 0)
  15#define __raw_spin_unlock_wait(x) \
  16                do { cpu_relax(); } while (__raw_spin_is_locked(x))
  17
  18static inline void __raw_spin_lock_flags(raw_spinlock_t *x,
  19                                         unsigned long flags)
  20{
  21        volatile unsigned int *a;
  22
  23        mb();
  24        a = __ldcw_align(x);
  25        while (__ldcw(a) == 0)
  26                while (*a == 0)
  27                        if (flags & PSW_SM_I) {
  28                                local_irq_enable();
  29                                cpu_relax();
  30                                local_irq_disable();
  31                        } else
  32                                cpu_relax();
  33        mb();
  34}
  35
  36static inline void __raw_spin_unlock(raw_spinlock_t *x)
  37{
  38        volatile unsigned int *a;
  39        mb();
  40        a = __ldcw_align(x);
  41        *a = 1;
  42        mb();
  43}
  44
  45static inline int __raw_spin_trylock(raw_spinlock_t *x)
  46{
  47        volatile unsigned int *a;
  48        int ret;
  49
  50        mb();
  51        a = __ldcw_align(x);
  52        ret = __ldcw(a) != 0;
  53        mb();
  54
  55        return ret;
  56}
  57
  58/*
  59 * Read-write spinlocks, allowing multiple readers but only one writer.
  60 * Linux rwlocks are unfair to writers; they can be starved for an indefinite
  61 * time by readers.  With care, they can also be taken in interrupt context.
  62 *
  63 * In the PA-RISC implementation, we have a spinlock and a counter.
  64 * Readers use the lock to serialise their access to the counter (which
  65 * records how many readers currently hold the lock).
  66 * Writers hold the spinlock, preventing any readers or other writers from
  67 * grabbing the rwlock.
  68 */
  69
  70/* Note that we have to ensure interrupts are disabled in case we're
  71 * interrupted by some other code that wants to grab the same read lock */
  72static  __inline__ void __raw_read_lock(raw_rwlock_t *rw)
  73{
  74        unsigned long flags;
  75        local_irq_save(flags);
  76        __raw_spin_lock_flags(&rw->lock, flags);
  77        rw->counter++;
  78        __raw_spin_unlock(&rw->lock);
  79        local_irq_restore(flags);
  80}
  81
  82/* Note that we have to ensure interrupts are disabled in case we're
  83 * interrupted by some other code that wants to grab the same read lock */
  84static  __inline__ void __raw_read_unlock(raw_rwlock_t *rw)
  85{
  86        unsigned long flags;
  87        local_irq_save(flags);
  88        __raw_spin_lock_flags(&rw->lock, flags);
  89        rw->counter--;
  90        __raw_spin_unlock(&rw->lock);
  91        local_irq_restore(flags);
  92}
  93
  94/* Note that we have to ensure interrupts are disabled in case we're
  95 * interrupted by some other code that wants to grab the same read lock */
  96static __inline__ int __raw_read_trylock(raw_rwlock_t *rw)
  97{
  98        unsigned long flags;
  99 retry:
 100        local_irq_save(flags);
 101        if (__raw_spin_trylock(&rw->lock)) {
 102                rw->counter++;
 103                __raw_spin_unlock(&rw->lock);
 104                local_irq_restore(flags);
 105                return 1;
 106        }
 107
 108        local_irq_restore(flags);
 109        /* If write-locked, we fail to acquire the lock */
 110        if (rw->counter < 0)
 111                return 0;
 112
 113        /* Wait until we have a realistic chance at the lock */
 114        while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0)
 115                cpu_relax();
 116
 117        goto retry;
 118}
 119
 120/* Note that we have to ensure interrupts are disabled in case we're
 121 * interrupted by some other code that wants to read_trylock() this lock */
 122static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
 123{
 124        unsigned long flags;
 125retry:
 126        local_irq_save(flags);
 127        __raw_spin_lock_flags(&rw->lock, flags);
 128
 129        if (rw->counter != 0) {
 130                __raw_spin_unlock(&rw->lock);
 131                local_irq_restore(flags);
 132
 133                while (rw->counter != 0)
 134                        cpu_relax();
 135
 136                goto retry;
 137        }
 138
 139        rw->counter = -1; /* mark as write-locked */
 140        mb();
 141        local_irq_restore(flags);
 142}
 143
 144static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
 145{
 146        rw->counter = 0;
 147        __raw_spin_unlock(&rw->lock);
 148}
 149
 150/* Note that we have to ensure interrupts are disabled in case we're
 151 * interrupted by some other code that wants to read_trylock() this lock */
 152static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
 153{
 154        unsigned long flags;
 155        int result = 0;
 156
 157        local_irq_save(flags);
 158        if (__raw_spin_trylock(&rw->lock)) {
 159                if (rw->counter == 0) {
 160                        rw->counter = -1;
 161                        result = 1;
 162                } else {
 163                        /* Read-locked.  Oh well. */
 164                        __raw_spin_unlock(&rw->lock);
 165                }
 166        }
 167        local_irq_restore(flags);
 168
 169        return result;
 170}
 171
 172/*
 173 * read_can_lock - would read_trylock() succeed?
 174 * @lock: the rwlock in question.
 175 */
 176static __inline__ int __raw_read_can_lock(raw_rwlock_t *rw)
 177{
 178        return rw->counter >= 0;
 179}
 180
 181/*
 182 * write_can_lock - would write_trylock() succeed?
 183 * @lock: the rwlock in question.
 184 */
 185static __inline__ int __raw_write_can_lock(raw_rwlock_t *rw)
 186{
 187        return !rw->counter;
 188}
 189
 190#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
 191#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
 192
 193#define _raw_spin_relax(lock)   cpu_relax()
 194#define _raw_read_relax(lock)   cpu_relax()
 195#define _raw_write_relax(lock)  cpu_relax()
 196
 197#endif /* __ASM_SPINLOCK_H */
 198