]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - arch/s390/include/asm/rwsem.h
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[mirror_ubuntu-hirsute-kernel.git] / arch / s390 / include / asm / rwsem.h
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 */
53 static 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 */
73 static 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 */
94 static 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
112 static inline void __down_write(struct rw_semaphore *sem)
113 {
114 if (___down_write(sem))
115 rwsem_down_write_failed(sem);
116 }
117
118 static 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 */
130 static 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 */
150 static 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 */
171 static 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 */
193 static 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 */