blob: 9cc8592b33bb647499a9f59c0efba0e361af0ee1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#ifndef _S390_RWSEM_H
2#define _S390_RWSEM_H
3
4/*
5 * include/asm-s390/rwsem.h
6 *
7 * S390 version
8 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
9 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
10 *
11 * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
12 */
13
14/*
15 *
16 * The MSW of the count is the negated number of active writers and waiting
17 * lockers, and the LSW is the total number of active locks
18 *
19 * The lock count is initialized to 0 (no active and no waiting lockers).
20 *
21 * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
22 * uncontended lock. This can be determined because XADD returns the old value.
23 * Readers increment by 1 and see a positive value when uncontended, negative
24 * if there are writers (and maybe) readers waiting (in which case it goes to
25 * sleep).
26 *
27 * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
28 * be extended to 65534 by manually checking the whole MSW rather than relying
29 * on the S flag.
30 *
31 * The value of ACTIVE_BIAS supports up to 65535 active processes.
32 *
33 * This should be totally fair - if anything is waiting, a process that wants a
34 * lock will go to the back of the queue. When the currently active lock is
35 * released, if there's a writer at the front of the queue, then that and only
36 * that will be woken up; if there's a bunch of consequtive readers at the
37 * front, then they'll all be woken up, but no other readers will be.
38 */
39
40#ifndef _LINUX_RWSEM_H
41#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
42#endif
43
44#ifdef __KERNEL__
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *);
47extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *);
48extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
49extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *);
50extern struct rw_semaphore *rwsem_downgrade_write(struct rw_semaphore *);
51
52/*
53 * the semaphore definition
54 */
55struct rw_semaphore {
56 signed long count;
57 spinlock_t wait_lock;
58 struct list_head wait_list;
Ingo Molnar4ea21762006-07-03 00:24:53 -070059#ifdef CONFIG_DEBUG_LOCK_ALLOC
60 struct lockdep_map dep_map;
61#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070062};
63
64#ifndef __s390x__
65#define RWSEM_UNLOCKED_VALUE 0x00000000
66#define RWSEM_ACTIVE_BIAS 0x00000001
67#define RWSEM_ACTIVE_MASK 0x0000ffff
68#define RWSEM_WAITING_BIAS (-0x00010000)
69#else /* __s390x__ */
70#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
71#define RWSEM_ACTIVE_BIAS 0x0000000000000001L
72#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
73#define RWSEM_WAITING_BIAS (-0x0000000100000000L)
74#endif /* __s390x__ */
75#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
76#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
77
78/*
79 * initialisation
80 */
Ingo Molnar4ea21762006-07-03 00:24:53 -070081
82#ifdef CONFIG_DEBUG_LOCK_ALLOC
83# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
84#else
85# define __RWSEM_DEP_MAP_INIT(lockname)
86#endif
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#define __RWSEM_INITIALIZER(name) \
Heiko Carstens519580f2008-01-26 14:11:04 +010089 { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
90 LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92#define DECLARE_RWSEM(name) \
93 struct rw_semaphore name = __RWSEM_INITIALIZER(name)
94
95static inline void init_rwsem(struct rw_semaphore *sem)
96{
97 sem->count = RWSEM_UNLOCKED_VALUE;
98 spin_lock_init(&sem->wait_lock);
99 INIT_LIST_HEAD(&sem->wait_list);
100}
101
Ingo Molnar4ea21762006-07-03 00:24:53 -0700102extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
103 struct lock_class_key *key);
104
105#define init_rwsem(sem) \
106do { \
107 static struct lock_class_key __key; \
108 \
109 __init_rwsem((sem), #sem, &__key); \
110} while (0)
111
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*
114 * lock for reading
115 */
116static inline void __down_read(struct rw_semaphore *sem)
117{
118 signed long old, new;
119
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200120 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100122 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200123 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100124 " ahi %1,%4\n"
125 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200126 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100128 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200129 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100130 " aghi %1,%4\n"
131 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200132 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100134 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
135 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
136 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 if (old < 0)
138 rwsem_down_read_failed(sem);
139}
140
141/*
142 * trylock for reading -- returns 1 if successful, 0 if contention
143 */
144static inline int __down_read_trylock(struct rw_semaphore *sem)
145{
146 signed long old, new;
147
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200148 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100150 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200151 "0: ltr %1,%0\n"
152 " jm 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100153 " ahi %1,%4\n"
154 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200155 " jl 0b\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 "1:"
157#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100158 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200159 "0: ltgr %1,%0\n"
160 " jm 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100161 " aghi %1,%4\n"
162 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200163 " jl 0b\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 "1:"
165#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100166 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
167 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
168 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 return old >= 0 ? 1 : 0;
170}
171
172/*
173 * lock for writing
174 */
Ingo Molnar4ea21762006-07-03 00:24:53 -0700175static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
177 signed long old, new, tmp;
178
179 tmp = RWSEM_ACTIVE_WRITE_BIAS;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200180 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100182 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200183 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100184 " a %1,%4\n"
185 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200186 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100188 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200189 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100190 " ag %1,%4\n"
191 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200192 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100194 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
195 : "Q" (sem->count), "m" (tmp)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200196 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 if (old != 0)
198 rwsem_down_write_failed(sem);
199}
200
Ingo Molnar4ea21762006-07-03 00:24:53 -0700201static inline void __down_write(struct rw_semaphore *sem)
202{
203 __down_write_nested(sem, 0);
204}
205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206/*
207 * trylock for writing -- returns 1 if successful, 0 if contention
208 */
209static inline int __down_write_trylock(struct rw_semaphore *sem)
210{
211 signed long old;
212
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200213 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100215 " l %0,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200216 "0: ltr %0,%0\n"
217 " jnz 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100218 " cs %0,%3,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200219 " jl 0b\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100221 " lg %0,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200222 "0: ltgr %0,%0\n"
223 " jnz 1f\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100224 " csg %0,%3,%1\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200225 " jl 0b\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226#endif /* __s390x__ */
227 "1:"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100228 : "=&d" (old), "=Q" (sem->count)
229 : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
230 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
232}
233
234/*
235 * unlock after reading
236 */
237static inline void __up_read(struct rw_semaphore *sem)
238{
239 signed long old, new;
240
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200241 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100243 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200244 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100245 " ahi %1,%4\n"
246 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200247 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100249 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200250 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100251 " aghi %1,%4\n"
252 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200253 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100255 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
256 : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200257 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 if (new < 0)
259 if ((new & RWSEM_ACTIVE_MASK) == 0)
260 rwsem_wake(sem);
261}
262
263/*
264 * unlock after writing
265 */
266static inline void __up_write(struct rw_semaphore *sem)
267{
268 signed long old, new, tmp;
269
270 tmp = -RWSEM_ACTIVE_WRITE_BIAS;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200271 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100273 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200274 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100275 " a %1,%4\n"
276 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200277 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100279 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200280 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100281 " ag %1,%4\n"
282 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200283 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100285 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
286 : "Q" (sem->count), "m" (tmp)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200287 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if (new < 0)
289 if ((new & RWSEM_ACTIVE_MASK) == 0)
290 rwsem_wake(sem);
291}
292
293/*
294 * downgrade write lock to read lock
295 */
296static inline void __downgrade_write(struct rw_semaphore *sem)
297{
298 signed long old, new, tmp;
299
300 tmp = -RWSEM_WAITING_BIAS;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200301 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100303 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200304 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100305 " a %1,%4\n"
306 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200307 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100309 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200310 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100311 " ag %1,%4\n"
312 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200313 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100315 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
316 : "Q" (sem->count), "m" (tmp)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200317 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 if (new > 1)
319 rwsem_downgrade_wake(sem);
320}
321
322/*
323 * implement atomic add functionality
324 */
325static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
326{
327 signed long old, new;
328
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200329 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100331 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200332 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100333 " ar %1,%4\n"
334 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200335 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100337 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200338 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100339 " agr %1,%4\n"
340 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200341 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100343 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
344 : "Q" (sem->count), "d" (delta)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200345 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346}
347
348/*
349 * implement exchange and add functionality
350 */
351static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
352{
353 signed long old, new;
354
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200355 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356#ifndef __s390x__
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100357 " l %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200358 "0: lr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100359 " ar %1,%4\n"
360 " cs %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200361 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362#else /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100363 " lg %0,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200364 "0: lgr %1,%0\n"
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100365 " agr %1,%4\n"
366 " csg %0,%1,%2\n"
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200367 " jl 0b"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368#endif /* __s390x__ */
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100369 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
370 : "Q" (sem->count), "d" (delta)
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200371 : "cc", "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return new;
373}
374
Rik Van Rieleb92f4e2005-10-29 18:15:44 -0700375static inline int rwsem_is_locked(struct rw_semaphore *sem)
376{
377 return (sem->count != 0);
378}
379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380#endif /* __KERNEL__ */
381#endif /* _S390_RWSEM_H */