License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[linux-2.6-block.git] / arch / s390 / include / asm / rwsem.h
CommitLineData
b2441318 1/* SPDX-License-Identifier: GPL-2.0 */
1da177e4
LT
2#ifndef _S390_RWSEM_H
3#define _S390_RWSEM_H
4
5/*
1da177e4 6 * S390 version
a53c8fab 7 * Copyright IBM Corp. 2002
1da177e4
LT
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
7eb792bf 35 * that will be woken up; if there's a bunch of consecutive readers at the
1da177e4
LT
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
1da177e4
LT
43#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
44#define RWSEM_ACTIVE_BIAS 0x0000000000000001L
45#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
46#define RWSEM_WAITING_BIAS (-0x0000000100000000L)
1da177e4
LT
47#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
48#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
49
1da177e4
LT
50/*
51 * lock for reading
52 */
53static inline void __down_read(struct rw_semaphore *sem)
54{
55 signed long old, new;
56
94c12cc7 57 asm volatile(
987bcdac 58 " lg %0,%2\n"
94c12cc7 59 "0: lgr %1,%0\n"
987bcdac
MS
60 " aghi %1,%4\n"
61 " csg %0,%1,%2\n"
94c12cc7 62 " jl 0b"
987bcdac
MS
63 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
64 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
65 : "cc", "memory");
1da177e4
LT
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
94c12cc7 77 asm volatile(
987bcdac 78 " lg %0,%2\n"
94c12cc7
MS
79 "0: ltgr %1,%0\n"
80 " jm 1f\n"
987bcdac
MS
81 " aghi %1,%4\n"
82 " csg %0,%1,%2\n"
94c12cc7 83 " jl 0b\n"
1da177e4 84 "1:"
987bcdac
MS
85 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
86 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
87 : "cc", "memory");
1da177e4
LT
88 return old >= 0 ? 1 : 0;
89}
90
91/*
92 * lock for writing
93 */
4edab14e 94static inline long ___down_write(struct rw_semaphore *sem)
1da177e4
LT
95{
96 signed long old, new, tmp;
97
98 tmp = RWSEM_ACTIVE_WRITE_BIAS;
94c12cc7 99 asm volatile(
987bcdac 100 " lg %0,%2\n"
94c12cc7 101 "0: lgr %1,%0\n"
987bcdac
MS
102 " ag %1,%4\n"
103 " csg %0,%1,%2\n"
94c12cc7 104 " jl 0b"
987bcdac
MS
105 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
106 : "Q" (sem->count), "m" (tmp)
94c12cc7 107 : "cc", "memory");
4edab14e
MH
108
109 return old;
110}
111
112static inline void __down_write(struct rw_semaphore *sem)
113{
114 if (___down_write(sem))
1da177e4
LT
115 rwsem_down_write_failed(sem);
116}
117
4edab14e
MH
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
1da177e4
LT
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
94c12cc7 134 asm volatile(
987bcdac 135 " lg %0,%1\n"
94c12cc7
MS
136 "0: ltgr %0,%0\n"
137 " jnz 1f\n"
987bcdac 138 " csg %0,%3,%1\n"
94c12cc7 139 " jl 0b\n"
1da177e4 140 "1:"
987bcdac
MS
141 : "=&d" (old), "=Q" (sem->count)
142 : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
143 : "cc", "memory");
1da177e4
LT
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
94c12cc7 154 asm volatile(
987bcdac 155 " lg %0,%2\n"
94c12cc7 156 "0: lgr %1,%0\n"
987bcdac
MS
157 " aghi %1,%4\n"
158 " csg %0,%1,%2\n"
94c12cc7 159 " jl 0b"
987bcdac
MS
160 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
161 : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
94c12cc7 162 : "cc", "memory");
1da177e4
LT
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;
94c12cc7 176 asm volatile(
987bcdac 177 " lg %0,%2\n"
94c12cc7 178 "0: lgr %1,%0\n"
987bcdac
MS
179 " ag %1,%4\n"
180 " csg %0,%1,%2\n"
94c12cc7 181 " jl 0b"
987bcdac
MS
182 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
183 : "Q" (sem->count), "m" (tmp)
94c12cc7 184 : "cc", "memory");
1da177e4
LT
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;
94c12cc7 198 asm volatile(
987bcdac 199 " lg %0,%2\n"
94c12cc7 200 "0: lgr %1,%0\n"
987bcdac
MS
201 " ag %1,%4\n"
202 " csg %0,%1,%2\n"
94c12cc7 203 " jl 0b"
987bcdac
MS
204 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
205 : "Q" (sem->count), "m" (tmp)
94c12cc7 206 : "cc", "memory");
1da177e4
LT
207 if (new > 1)
208 rwsem_downgrade_wake(sem);
209}
210
1da177e4 211#endif /* _S390_RWSEM_H */