Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.7-rc2 247 lines 5.7 kB view raw
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/* 211 * implement atomic add functionality 212 */ 213static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) 214{ 215 signed long old, new; 216 217 asm volatile( 218 " lg %0,%2\n" 219 "0: lgr %1,%0\n" 220 " agr %1,%4\n" 221 " csg %0,%1,%2\n" 222 " jl 0b" 223 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 224 : "Q" (sem->count), "d" (delta) 225 : "cc", "memory"); 226} 227 228/* 229 * implement exchange and add functionality 230 */ 231static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) 232{ 233 signed long old, new; 234 235 asm volatile( 236 " lg %0,%2\n" 237 "0: lgr %1,%0\n" 238 " agr %1,%4\n" 239 " csg %0,%1,%2\n" 240 " jl 0b" 241 : "=&d" (old), "=&d" (new), "=Q" (sem->count) 242 : "Q" (sem->count), "d" (delta) 243 : "cc", "memory"); 244 return new; 245} 246 247#endif /* _S390_RWSEM_H */