blob: 487f9b64efb9a5f8d64d7a25fea34ae40e1faa29 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#ifndef _S390_RWSEM_H
2#define _S390_RWSEM_H
3
4/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * S390 version
Heiko Carstensa53c8fa2012-07-20 11:15:04 +02006 * Copyright IBM Corp. 2002
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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
Heiko Carstensf4815ac2012-05-23 16:24:51 +020042#ifndef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define RWSEM_UNLOCKED_VALUE 0x00000000
44#define RWSEM_ACTIVE_BIAS 0x00000001
45#define RWSEM_ACTIVE_MASK 0x0000ffff
46#define RWSEM_WAITING_BIAS (-0x00010000)
Heiko Carstensf4815ac2012-05-23 16:24:51 +020047#else /* CONFIG_64BIT */
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
49#define RWSEM_ACTIVE_BIAS 0x0000000000000001L
50#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
51#define RWSEM_WAITING_BIAS (-0x0000000100000000L)
Heiko Carstensf4815ac2012-05-23 16:24:51 +020052#endif /* CONFIG_64BIT */
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
54#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
55
56/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 * lock for reading
58 */
59static inline void __down_read(struct rw_semaphore *sem)
60{
61 signed long old, new;
62
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020063 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +020064#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010065 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020066 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010067 " ahi %1,%4\n"
68 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020069 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +020070#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010071 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020072 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010073 " aghi %1,%4\n"
74 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020075 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +020076#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010077 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
78 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
79 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 if (old < 0)
81 rwsem_down_read_failed(sem);
82}
83
84/*
85 * trylock for reading -- returns 1 if successful, 0 if contention
86 */
87static inline int __down_read_trylock(struct rw_semaphore *sem)
88{
89 signed long old, new;
90
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020091 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +020092#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010093 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020094 "0: ltr %1,%0\n"
95 " jm 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010096 " ahi %1,%4\n"
97 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020098 " jl 0b\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 "1:"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200100#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100101 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200102 "0: ltgr %1,%0\n"
103 " jm 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100104 " aghi %1,%4\n"
105 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200106 " jl 0b\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 "1:"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200108#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100109 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
110 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
111 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 return old >= 0 ? 1 : 0;
113}
114
115/*
116 * lock for writing
117 */
Ingo Molnar4ea21762006-07-03 00:24:53 -0700118static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
120 signed long old, new, tmp;
121
122 tmp = RWSEM_ACTIVE_WRITE_BIAS;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200123 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200124#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100125 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200126 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100127 " a %1,%4\n"
128 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200129 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200130#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100131 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200132 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100133 " ag %1,%4\n"
134 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200135 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200136#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100137 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
138 : "Q" (sem->count), "m" (tmp)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200139 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 if (old != 0)
141 rwsem_down_write_failed(sem);
142}
143
Ingo Molnar4ea21762006-07-03 00:24:53 -0700144static inline void __down_write(struct rw_semaphore *sem)
145{
146 __down_write_nested(sem, 0);
147}
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149/*
150 * trylock for writing -- returns 1 if successful, 0 if contention
151 */
152static inline int __down_write_trylock(struct rw_semaphore *sem)
153{
154 signed long old;
155
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200156 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200157#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100158 " l %0,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200159 "0: ltr %0,%0\n"
160 " jnz 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100161 " cs %0,%3,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200162 " jl 0b\n"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200163#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100164 " lg %0,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200165 "0: ltgr %0,%0\n"
166 " jnz 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100167 " csg %0,%3,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200168 " jl 0b\n"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200169#endif /* CONFIG_64BIT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 "1:"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100171 : "=&d" (old), "=Q" (sem->count)
172 : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
173 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
175}
176
177/*
178 * unlock after reading
179 */
180static inline void __up_read(struct rw_semaphore *sem)
181{
182 signed long old, new;
183
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200184 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200185#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100186 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200187 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100188 " ahi %1,%4\n"
189 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200190 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200191#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100192 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200193 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100194 " aghi %1,%4\n"
195 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200196 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200197#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100198 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
199 : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200200 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 if (new < 0)
202 if ((new & RWSEM_ACTIVE_MASK) == 0)
203 rwsem_wake(sem);
204}
205
206/*
207 * unlock after writing
208 */
209static inline void __up_write(struct rw_semaphore *sem)
210{
211 signed long old, new, tmp;
212
213 tmp = -RWSEM_ACTIVE_WRITE_BIAS;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200214 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200215#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100216 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200217 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100218 " a %1,%4\n"
219 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200220 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200221#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100222 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200223 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100224 " ag %1,%4\n"
225 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200226 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200227#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100228 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
229 : "Q" (sem->count), "m" (tmp)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200230 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 if (new < 0)
232 if ((new & RWSEM_ACTIVE_MASK) == 0)
233 rwsem_wake(sem);
234}
235
236/*
237 * downgrade write lock to read lock
238 */
239static inline void __downgrade_write(struct rw_semaphore *sem)
240{
241 signed long old, new, tmp;
242
243 tmp = -RWSEM_WAITING_BIAS;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200244 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200245#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100246 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200247 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100248 " a %1,%4\n"
249 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200250 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200251#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100252 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200253 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100254 " ag %1,%4\n"
255 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200256 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200257#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100258 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
259 : "Q" (sem->count), "m" (tmp)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200260 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 if (new > 1)
262 rwsem_downgrade_wake(sem);
263}
264
265/*
266 * implement atomic add functionality
267 */
268static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
269{
270 signed long old, new;
271
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200272 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200273#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100274 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200275 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100276 " ar %1,%4\n"
277 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200278 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200279#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100280 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200281 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100282 " agr %1,%4\n"
283 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200284 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200285#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100286 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
287 : "Q" (sem->count), "d" (delta)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200288 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289}
290
291/*
292 * implement exchange and add functionality
293 */
294static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
295{
296 signed long old, new;
297
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200298 asm volatile(
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200299#ifndef CONFIG_64BIT
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100300 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200301 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100302 " ar %1,%4\n"
303 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200304 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200305#else /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100306 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200307 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100308 " agr %1,%4\n"
309 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200310 " jl 0b"
Heiko Carstensf4815ac2012-05-23 16:24:51 +0200311#endif /* CONFIG_64BIT */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100312 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
313 : "Q" (sem->count), "d" (delta)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200314 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 return new;
316}
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318#endif /* _S390_RWSEM_H */