• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #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 
46 #include <linux/list.h>
47 #include <linux/spinlock.h>
48 
49 struct rwsem_waiter;
50 
51 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *);
52 extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *);
53 extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
54 extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *);
55 extern struct rw_semaphore *rwsem_downgrade_write(struct rw_semaphore *);
56 
57 /*
58  * the semaphore definition
59  */
60 struct rw_semaphore {
61 	signed long		count;
62 	spinlock_t		wait_lock;
63 	struct list_head	wait_list;
64 #ifdef CONFIG_DEBUG_LOCK_ALLOC
65 	struct lockdep_map	dep_map;
66 #endif
67 };
68 
69 #ifndef __s390x__
70 #define RWSEM_UNLOCKED_VALUE	0x00000000
71 #define RWSEM_ACTIVE_BIAS	0x00000001
72 #define RWSEM_ACTIVE_MASK	0x0000ffff
73 #define RWSEM_WAITING_BIAS	(-0x00010000)
74 #else /* __s390x__ */
75 #define RWSEM_UNLOCKED_VALUE	0x0000000000000000L
76 #define RWSEM_ACTIVE_BIAS	0x0000000000000001L
77 #define RWSEM_ACTIVE_MASK	0x00000000ffffffffL
78 #define RWSEM_WAITING_BIAS	(-0x0000000100000000L)
79 #endif /* __s390x__ */
80 #define RWSEM_ACTIVE_READ_BIAS	RWSEM_ACTIVE_BIAS
81 #define RWSEM_ACTIVE_WRITE_BIAS	(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
82 
83 /*
84  * initialisation
85  */
86 
87 #ifdef CONFIG_DEBUG_LOCK_ALLOC
88 # define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
89 #else
90 # define __RWSEM_DEP_MAP_INIT(lockname)
91 #endif
92 
93 #define __RWSEM_INITIALIZER(name) \
94  { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
95    LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
96 
97 #define DECLARE_RWSEM(name) \
98 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
99 
init_rwsem(struct rw_semaphore * sem)100 static inline void init_rwsem(struct rw_semaphore *sem)
101 {
102 	sem->count = RWSEM_UNLOCKED_VALUE;
103 	spin_lock_init(&sem->wait_lock);
104 	INIT_LIST_HEAD(&sem->wait_list);
105 }
106 
107 extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
108 			 struct lock_class_key *key);
109 
110 #define init_rwsem(sem)				\
111 do {						\
112 	static struct lock_class_key __key;	\
113 						\
114 	__init_rwsem((sem), #sem, &__key);	\
115 } while (0)
116 
117 
118 /*
119  * lock for reading
120  */
__down_read(struct rw_semaphore * sem)121 static inline void __down_read(struct rw_semaphore *sem)
122 {
123 	signed long old, new;
124 
125 	asm volatile(
126 #ifndef __s390x__
127 		"	l	%0,0(%3)\n"
128 		"0:	lr	%1,%0\n"
129 		"	ahi	%1,%5\n"
130 		"	cs	%0,%1,0(%3)\n"
131 		"	jl	0b"
132 #else /* __s390x__ */
133 		"	lg	%0,0(%3)\n"
134 		"0:	lgr	%1,%0\n"
135 		"	aghi	%1,%5\n"
136 		"	csg	%0,%1,0(%3)\n"
137 		"	jl	0b"
138 #endif /* __s390x__ */
139 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
140 		: "a" (&sem->count), "m" (sem->count),
141 		  "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
142 	if (old < 0)
143 		rwsem_down_read_failed(sem);
144 }
145 
146 /*
147  * trylock for reading -- returns 1 if successful, 0 if contention
148  */
__down_read_trylock(struct rw_semaphore * sem)149 static inline int __down_read_trylock(struct rw_semaphore *sem)
150 {
151 	signed long old, new;
152 
153 	asm volatile(
154 #ifndef __s390x__
155 		"	l	%0,0(%3)\n"
156 		"0:	ltr	%1,%0\n"
157 		"	jm	1f\n"
158 		"	ahi	%1,%5\n"
159 		"	cs	%0,%1,0(%3)\n"
160 		"	jl	0b\n"
161 		"1:"
162 #else /* __s390x__ */
163 		"	lg	%0,0(%3)\n"
164 		"0:	ltgr	%1,%0\n"
165 		"	jm	1f\n"
166 		"	aghi	%1,%5\n"
167 		"	csg	%0,%1,0(%3)\n"
168 		"	jl	0b\n"
169 		"1:"
170 #endif /* __s390x__ */
171 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
172 		: "a" (&sem->count), "m" (sem->count),
173 		  "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
174 	return old >= 0 ? 1 : 0;
175 }
176 
177 /*
178  * lock for writing
179  */
__down_write_nested(struct rw_semaphore * sem,int subclass)180 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
181 {
182 	signed long old, new, tmp;
183 
184 	tmp = RWSEM_ACTIVE_WRITE_BIAS;
185 	asm volatile(
186 #ifndef __s390x__
187 		"	l	%0,0(%3)\n"
188 		"0:	lr	%1,%0\n"
189 		"	a	%1,%5\n"
190 		"	cs	%0,%1,0(%3)\n"
191 		"	jl	0b"
192 #else /* __s390x__ */
193 		"	lg	%0,0(%3)\n"
194 		"0:	lgr	%1,%0\n"
195 		"	ag	%1,%5\n"
196 		"	csg	%0,%1,0(%3)\n"
197 		"	jl	0b"
198 #endif /* __s390x__ */
199 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
200 		: "a" (&sem->count), "m" (sem->count), "m" (tmp)
201 		: "cc", "memory");
202 	if (old != 0)
203 		rwsem_down_write_failed(sem);
204 }
205 
__down_write(struct rw_semaphore * sem)206 static inline void __down_write(struct rw_semaphore *sem)
207 {
208 	__down_write_nested(sem, 0);
209 }
210 
211 /*
212  * trylock for writing -- returns 1 if successful, 0 if contention
213  */
__down_write_trylock(struct rw_semaphore * sem)214 static inline int __down_write_trylock(struct rw_semaphore *sem)
215 {
216 	signed long old;
217 
218 	asm volatile(
219 #ifndef __s390x__
220 		"	l	%0,0(%2)\n"
221 		"0:	ltr	%0,%0\n"
222 		"	jnz	1f\n"
223 		"	cs	%0,%4,0(%2)\n"
224 		"	jl	0b\n"
225 #else /* __s390x__ */
226 		"	lg	%0,0(%2)\n"
227 		"0:	ltgr	%0,%0\n"
228 		"	jnz	1f\n"
229 		"	csg	%0,%4,0(%2)\n"
230 		"	jl	0b\n"
231 #endif /* __s390x__ */
232 		"1:"
233 		: "=&d" (old), "=m" (sem->count)
234 		: "a" (&sem->count), "m" (sem->count),
235 		  "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory");
236 	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
237 }
238 
239 /*
240  * unlock after reading
241  */
__up_read(struct rw_semaphore * sem)242 static inline void __up_read(struct rw_semaphore *sem)
243 {
244 	signed long old, new;
245 
246 	asm volatile(
247 #ifndef __s390x__
248 		"	l	%0,0(%3)\n"
249 		"0:	lr	%1,%0\n"
250 		"	ahi	%1,%5\n"
251 		"	cs	%0,%1,0(%3)\n"
252 		"	jl	0b"
253 #else /* __s390x__ */
254 		"	lg	%0,0(%3)\n"
255 		"0:	lgr	%1,%0\n"
256 		"	aghi	%1,%5\n"
257 		"	csg	%0,%1,0(%3)\n"
258 		"	jl	0b"
259 #endif /* __s390x__ */
260 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
261 		: "a" (&sem->count), "m" (sem->count),
262 		  "i" (-RWSEM_ACTIVE_READ_BIAS)
263 		: "cc", "memory");
264 	if (new < 0)
265 		if ((new & RWSEM_ACTIVE_MASK) == 0)
266 			rwsem_wake(sem);
267 }
268 
269 /*
270  * unlock after writing
271  */
__up_write(struct rw_semaphore * sem)272 static inline void __up_write(struct rw_semaphore *sem)
273 {
274 	signed long old, new, tmp;
275 
276 	tmp = -RWSEM_ACTIVE_WRITE_BIAS;
277 	asm volatile(
278 #ifndef __s390x__
279 		"	l	%0,0(%3)\n"
280 		"0:	lr	%1,%0\n"
281 		"	a	%1,%5\n"
282 		"	cs	%0,%1,0(%3)\n"
283 		"	jl	0b"
284 #else /* __s390x__ */
285 		"	lg	%0,0(%3)\n"
286 		"0:	lgr	%1,%0\n"
287 		"	ag	%1,%5\n"
288 		"	csg	%0,%1,0(%3)\n"
289 		"	jl	0b"
290 #endif /* __s390x__ */
291 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
292 		: "a" (&sem->count), "m" (sem->count), "m" (tmp)
293 		: "cc", "memory");
294 	if (new < 0)
295 		if ((new & RWSEM_ACTIVE_MASK) == 0)
296 			rwsem_wake(sem);
297 }
298 
299 /*
300  * downgrade write lock to read lock
301  */
__downgrade_write(struct rw_semaphore * sem)302 static inline void __downgrade_write(struct rw_semaphore *sem)
303 {
304 	signed long old, new, tmp;
305 
306 	tmp = -RWSEM_WAITING_BIAS;
307 	asm volatile(
308 #ifndef __s390x__
309 		"	l	%0,0(%3)\n"
310 		"0:	lr	%1,%0\n"
311 		"	a	%1,%5\n"
312 		"	cs	%0,%1,0(%3)\n"
313 		"	jl	0b"
314 #else /* __s390x__ */
315 		"	lg	%0,0(%3)\n"
316 		"0:	lgr	%1,%0\n"
317 		"	ag	%1,%5\n"
318 		"	csg	%0,%1,0(%3)\n"
319 		"	jl	0b"
320 #endif /* __s390x__ */
321 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
322 		: "a" (&sem->count), "m" (sem->count), "m" (tmp)
323 		: "cc", "memory");
324 	if (new > 1)
325 		rwsem_downgrade_wake(sem);
326 }
327 
328 /*
329  * implement atomic add functionality
330  */
rwsem_atomic_add(long delta,struct rw_semaphore * sem)331 static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
332 {
333 	signed long old, new;
334 
335 	asm volatile(
336 #ifndef __s390x__
337 		"	l	%0,0(%3)\n"
338 		"0:	lr	%1,%0\n"
339 		"	ar	%1,%5\n"
340 		"	cs	%0,%1,0(%3)\n"
341 		"	jl	0b"
342 #else /* __s390x__ */
343 		"	lg	%0,0(%3)\n"
344 		"0:	lgr	%1,%0\n"
345 		"	agr	%1,%5\n"
346 		"	csg	%0,%1,0(%3)\n"
347 		"	jl	0b"
348 #endif /* __s390x__ */
349 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
350 		: "a" (&sem->count), "m" (sem->count), "d" (delta)
351 		: "cc", "memory");
352 }
353 
354 /*
355  * implement exchange and add functionality
356  */
rwsem_atomic_update(long delta,struct rw_semaphore * sem)357 static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
358 {
359 	signed long old, new;
360 
361 	asm volatile(
362 #ifndef __s390x__
363 		"	l	%0,0(%3)\n"
364 		"0:	lr	%1,%0\n"
365 		"	ar	%1,%5\n"
366 		"	cs	%0,%1,0(%3)\n"
367 		"	jl	0b"
368 #else /* __s390x__ */
369 		"	lg	%0,0(%3)\n"
370 		"0:	lgr	%1,%0\n"
371 		"	agr	%1,%5\n"
372 		"	csg	%0,%1,0(%3)\n"
373 		"	jl	0b"
374 #endif /* __s390x__ */
375 		: "=&d" (old), "=&d" (new), "=m" (sem->count)
376 		: "a" (&sem->count), "m" (sem->count), "d" (delta)
377 		: "cc", "memory");
378 	return new;
379 }
380 
rwsem_is_locked(struct rw_semaphore * sem)381 static inline int rwsem_is_locked(struct rw_semaphore *sem)
382 {
383 	return (sem->count != 0);
384 }
385 
386 #endif /* __KERNEL__ */
387 #endif /* _S390_RWSEM_H */
388