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 consequtive 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 void __down_write_nested(struct rw_semaphore *sem, int subclass) 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 if (old != 0) 108 rwsem_down_write_failed(sem); 109} 110 111static inline void __down_write(struct rw_semaphore *sem) 112{ 113 __down_write_nested(sem, 0); 114} 115 116/* 117 * trylock for writing -- returns 1 if successful, 0 if contention 118 */ 119static inline int __down_write_trylock(struct rw_semaphore *sem) 120{ 121 signed long old; 122 123 asm volatile( 124 " lg %0,%1\n" 125 "0: ltgr %0,%0\n" 126 " jnz 1f\n" 127 " csg %0,%3,%1\n" 128 " jl 0b\n" 129 "1:" 130 : "=&d" (old), "=Q" (sem->count) 131 : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS) 132 : "cc", "memory"); 133 return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0; 134} 135 136/* 137 * unlock after reading 138 */ 139static inline void __up_read(struct rw_semaphore *sem) 140{ 141 signed long old, new; 142 143 asm volatile( 144 " lg %0,%2\n" 145 "0: lgr %1,%0\n" 146 " aghi %1,%4\n" 147 " csg %0,%1,%2\n" 148 " jl 0b" 149 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 150 : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS) 151 : "cc", "memory"); 152 if (new < 0) 153 if ((new & RWSEM_ACTIVE_MASK) == 0) 154 rwsem_wake(sem); 155} 156 157/* 158 * unlock after writing 159 */ 160static inline void __up_write(struct rw_semaphore *sem) 161{ 162 signed long old, new, tmp; 163 164 tmp = -RWSEM_ACTIVE_WRITE_BIAS; 165 asm volatile( 166 " lg %0,%2\n" 167 "0: lgr %1,%0\n" 168 " ag %1,%4\n" 169 " csg %0,%1,%2\n" 170 " jl 0b" 171 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 172 : "Q" (sem->count), "m" (tmp) 173 : "cc", "memory"); 174 if (new < 0) 175 if ((new & RWSEM_ACTIVE_MASK) == 0) 176 rwsem_wake(sem); 177} 178 179/* 180 * downgrade write lock to read lock 181 */ 182static inline void __downgrade_write(struct rw_semaphore *sem) 183{ 184 signed long old, new, tmp; 185 186 tmp = -RWSEM_WAITING_BIAS; 187 asm volatile( 188 " lg %0,%2\n" 189 "0: lgr %1,%0\n" 190 " ag %1,%4\n" 191 " csg %0,%1,%2\n" 192 " jl 0b" 193 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 194 : "Q" (sem->count), "m" (tmp) 195 : "cc", "memory"); 196 if (new > 1) 197 rwsem_downgrade_wake(sem); 198} 199 200/* 201 * implement atomic add functionality 202 */ 203static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) 204{ 205 signed long old, new; 206 207 asm volatile( 208 " lg %0,%2\n" 209 "0: lgr %1,%0\n" 210 " agr %1,%4\n" 211 " csg %0,%1,%2\n" 212 " jl 0b" 213 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 214 : "Q" (sem->count), "d" (delta) 215 : "cc", "memory"); 216} 217 218/* 219 * implement exchange and add functionality 220 */ 221static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) 222{ 223 signed long old, new; 224 225 asm volatile( 226 " lg %0,%2\n" 227 "0: lgr %1,%0\n" 228 " agr %1,%4\n" 229 " csg %0,%1,%2\n" 230 " jl 0b" 231 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 232 : "Q" (sem->count), "d" (delta) 233 : "cc", "memory"); 234 return new; 235} 236 237#endif /* _S390_RWSEM_H */ 238