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