linux/arch/s390/include/asm/rwsem.h
<<
>>
Prefs
   1#ifndef _S390_RWSEM_H
   2#define _S390_RWSEM_H
   3
   4/*
   5 *  S390 version
   6 *    Copyright IBM Corp. 2002
   7 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
   8 *
   9 *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
  10 */
  11
  12/*
  13 *
  14 * The MSW of the count is the negated number of active writers and waiting
  15 * lockers, and the LSW is the total number of active locks
  16 *
  17 * The lock count is initialized to 0 (no active and no waiting lockers).
  18 *
  19 * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
  20 * uncontended lock. This can be determined because XADD returns the old value.
  21 * Readers increment by 1 and see a positive value when uncontended, negative
  22 * if there are writers (and maybe) readers waiting (in which case it goes to
  23 * sleep).
  24 *
  25 * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
  26 * be extended to 65534 by manually checking the whole MSW rather than relying
  27 * on the S flag.
  28 *
  29 * The value of ACTIVE_BIAS supports up to 65535 active processes.
  30 *
  31 * This should be totally fair - if anything is waiting, a process that wants a
  32 * lock will go to the back of the queue. When the currently active lock is
  33 * released, if there's a writer at the front of the queue, then that and only
  34 * that will be woken up; if there's a bunch of consecutive readers at the
  35 * front, then they'll all be woken up, but no other readers will be.
  36 */
  37
  38#ifndef _LINUX_RWSEM_H
  39#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  40#endif
  41
  42#define RWSEM_UNLOCKED_VALUE    0x0000000000000000L
  43#define RWSEM_ACTIVE_BIAS       0x0000000000000001L
  44#define RWSEM_ACTIVE_MASK       0x00000000ffffffffL
  45#define RWSEM_WAITING_BIAS      (-0x0000000100000000L)
  46#define RWSEM_ACTIVE_READ_BIAS  RWSEM_ACTIVE_BIAS
  47#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  48
  49/*
  50 * lock for reading
  51 */
  52static inline void __down_read(struct rw_semaphore *sem)
  53{
  54        signed long old, new;
  55
  56        asm volatile(
  57                "       lg      %0,%2\n"
  58                "0:     lgr     %1,%0\n"
  59                "       aghi    %1,%4\n"
  60                "       csg     %0,%1,%2\n"
  61                "       jl      0b"
  62                : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  63                : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  64                : "cc", "memory");
  65        if (old < 0)
  66                rwsem_down_read_failed(sem);
  67}
  68
  69/*
  70 * trylock for reading -- returns 1 if successful, 0 if contention
  71 */
  72static inline int __down_read_trylock(struct rw_semaphore *sem)
  73{
  74        signed long old, new;
  75
  76        asm volatile(
  77                "       lg      %0,%2\n"
  78                "0:     ltgr    %1,%0\n"
  79                "       jm      1f\n"
  80                "       aghi    %1,%4\n"
  81                "       csg     %0,%1,%2\n"
  82                "       jl      0b\n"
  83                "1:"
  84                : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  85                : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  86                : "cc", "memory");
  87        return old >= 0 ? 1 : 0;
  88}
  89
  90/*
  91 * lock for writing
  92 */
  93static inline long ___down_write(struct rw_semaphore *sem)
  94{
  95        signed long old, new, tmp;
  96
  97        tmp = RWSEM_ACTIVE_WRITE_BIAS;
  98        asm volatile(
  99                "       lg      %0,%2\n"
 100                "0:     lgr     %1,%0\n"
 101                "       ag      %1,%4\n"
 102                "       csg     %0,%1,%2\n"
 103                "       jl      0b"
 104                : "=&d" (old), "=&d" (new), "=Q" (sem->count)
 105                : "Q" (sem->count), "m" (tmp)
 106                : "cc", "memory");
 107
 108        return old;
 109}
 110
 111static inline void __down_write(struct rw_semaphore *sem)
 112{
 113        if (___down_write(sem))
 114                rwsem_down_write_failed(sem);
 115}
 116
 117static inline int __down_write_killable(struct rw_semaphore *sem)
 118{
 119        if (___down_write(sem))
 120                if (IS_ERR(rwsem_down_write_failed_killable(sem)))
 121                        return -EINTR;
 122
 123        return 0;
 124}
 125
 126/*
 127 * trylock for writing -- returns 1 if successful, 0 if contention
 128 */
 129static inline int __down_write_trylock(struct rw_semaphore *sem)
 130{
 131        signed long old;
 132
 133        asm volatile(
 134                "       lg      %0,%1\n"
 135                "0:     ltgr    %0,%0\n"
 136                "       jnz     1f\n"
 137                "       csg     %0,%3,%1\n"
 138                "       jl      0b\n"
 139                "1:"
 140                : "=&d" (old), "=Q" (sem->count)
 141                : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
 142                : "cc", "memory");
 143        return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
 144}
 145
 146/*
 147 * unlock after reading
 148 */
 149static inline void __up_read(struct rw_semaphore *sem)
 150{
 151        signed long old, new;
 152
 153        asm volatile(
 154                "       lg      %0,%2\n"
 155                "0:     lgr     %1,%0\n"
 156                "       aghi    %1,%4\n"
 157                "       csg     %0,%1,%2\n"
 158                "       jl      0b"
 159                : "=&d" (old), "=&d" (new), "=Q" (sem->count)
 160                : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
 161                : "cc", "memory");
 162        if (new < 0)
 163                if ((new & RWSEM_ACTIVE_MASK) == 0)
 164                        rwsem_wake(sem);
 165}
 166
 167/*
 168 * unlock after writing
 169 */
 170static inline void __up_write(struct rw_semaphore *sem)
 171{
 172        signed long old, new, tmp;
 173
 174        tmp = -RWSEM_ACTIVE_WRITE_BIAS;
 175        asm volatile(
 176                "       lg      %0,%2\n"
 177                "0:     lgr     %1,%0\n"
 178                "       ag      %1,%4\n"
 179                "       csg     %0,%1,%2\n"
 180                "       jl      0b"
 181                : "=&d" (old), "=&d" (new), "=Q" (sem->count)
 182                : "Q" (sem->count), "m" (tmp)
 183                : "cc", "memory");
 184        if (new < 0)
 185                if ((new & RWSEM_ACTIVE_MASK) == 0)
 186                        rwsem_wake(sem);
 187}
 188
 189/*
 190 * downgrade write lock to read lock
 191 */
 192static inline void __downgrade_write(struct rw_semaphore *sem)
 193{
 194        signed long old, new, tmp;
 195
 196        tmp = -RWSEM_WAITING_BIAS;
 197        asm volatile(
 198                "       lg      %0,%2\n"
 199                "0:     lgr     %1,%0\n"
 200                "       ag      %1,%4\n"
 201                "       csg     %0,%1,%2\n"
 202                "       jl      0b"
 203                : "=&d" (old), "=&d" (new), "=Q" (sem->count)
 204                : "Q" (sem->count), "m" (tmp)
 205                : "cc", "memory");
 206        if (new > 1)
 207                rwsem_downgrade_wake(sem);
 208}
 209
 210#endif /* _S390_RWSEM_H */
 211