• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _S390_RWSEM_H
2 #define _S390_RWSEM_H
3 
4 /*
5  *  S390 version
6  *    Copyright IBM Corp. 2002
7  *    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 
42 #define RWSEM_UNLOCKED_VALUE	0x0000000000000000L
43 #define RWSEM_ACTIVE_BIAS	0x0000000000000001L
44 #define RWSEM_ACTIVE_MASK	0x00000000ffffffffL
45 #define RWSEM_WAITING_BIAS	(-0x0000000100000000L)
46 #define RWSEM_ACTIVE_READ_BIAS	RWSEM_ACTIVE_BIAS
47 #define RWSEM_ACTIVE_WRITE_BIAS	(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
48 
49 /*
50  * lock for reading
51  */
__down_read(struct rw_semaphore * sem)52 static inline void __down_read(struct rw_semaphore *sem)
53 {
54 	signed long old, new;
55 
56 	asm volatile(
57 		"	lg	%0,%2\n"
58 		"0:	lgr	%1,%0\n"
59 		"	aghi	%1,%4\n"
60 		"	csg	%0,%1,%2\n"
61 		"	jl	0b"
62 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
63 		: "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
64 		: "cc", "memory");
65 	if (old < 0)
66 		rwsem_down_read_failed(sem);
67 }
68 
69 /*
70  * trylock for reading -- returns 1 if successful, 0 if contention
71  */
__down_read_trylock(struct rw_semaphore * sem)72 static inline int __down_read_trylock(struct rw_semaphore *sem)
73 {
74 	signed long old, new;
75 
76 	asm volatile(
77 		"	lg	%0,%2\n"
78 		"0:	ltgr	%1,%0\n"
79 		"	jm	1f\n"
80 		"	aghi	%1,%4\n"
81 		"	csg	%0,%1,%2\n"
82 		"	jl	0b\n"
83 		"1:"
84 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
85 		: "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
86 		: "cc", "memory");
87 	return old >= 0 ? 1 : 0;
88 }
89 
90 /*
91  * lock for writing
92  */
__down_write_nested(struct rw_semaphore * sem,int subclass)93 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
94 {
95 	signed long old, new, tmp;
96 
97 	tmp = RWSEM_ACTIVE_WRITE_BIAS;
98 	asm volatile(
99 		"	lg	%0,%2\n"
100 		"0:	lgr	%1,%0\n"
101 		"	ag	%1,%4\n"
102 		"	csg	%0,%1,%2\n"
103 		"	jl	0b"
104 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
105 		: "Q" (sem->count), "m" (tmp)
106 		: "cc", "memory");
107 	if (old != 0)
108 		rwsem_down_write_failed(sem);
109 }
110 
__down_write(struct rw_semaphore * sem)111 static inline void __down_write(struct rw_semaphore *sem)
112 {
113 	__down_write_nested(sem, 0);
114 }
115 
116 /*
117  * trylock for writing -- returns 1 if successful, 0 if contention
118  */
__down_write_trylock(struct rw_semaphore * sem)119 static inline int __down_write_trylock(struct rw_semaphore *sem)
120 {
121 	signed long old;
122 
123 	asm volatile(
124 		"	lg	%0,%1\n"
125 		"0:	ltgr	%0,%0\n"
126 		"	jnz	1f\n"
127 		"	csg	%0,%3,%1\n"
128 		"	jl	0b\n"
129 		"1:"
130 		: "=&d" (old), "=Q" (sem->count)
131 		: "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
132 		: "cc", "memory");
133 	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
134 }
135 
136 /*
137  * unlock after reading
138  */
__up_read(struct rw_semaphore * sem)139 static inline void __up_read(struct rw_semaphore *sem)
140 {
141 	signed long old, new;
142 
143 	asm volatile(
144 		"	lg	%0,%2\n"
145 		"0:	lgr	%1,%0\n"
146 		"	aghi	%1,%4\n"
147 		"	csg	%0,%1,%2\n"
148 		"	jl	0b"
149 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
150 		: "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
151 		: "cc", "memory");
152 	if (new < 0)
153 		if ((new & RWSEM_ACTIVE_MASK) == 0)
154 			rwsem_wake(sem);
155 }
156 
157 /*
158  * unlock after writing
159  */
__up_write(struct rw_semaphore * sem)160 static inline void __up_write(struct rw_semaphore *sem)
161 {
162 	signed long old, new, tmp;
163 
164 	tmp = -RWSEM_ACTIVE_WRITE_BIAS;
165 	asm volatile(
166 		"	lg	%0,%2\n"
167 		"0:	lgr	%1,%0\n"
168 		"	ag	%1,%4\n"
169 		"	csg	%0,%1,%2\n"
170 		"	jl	0b"
171 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
172 		: "Q" (sem->count), "m" (tmp)
173 		: "cc", "memory");
174 	if (new < 0)
175 		if ((new & RWSEM_ACTIVE_MASK) == 0)
176 			rwsem_wake(sem);
177 }
178 
179 /*
180  * downgrade write lock to read lock
181  */
__downgrade_write(struct rw_semaphore * sem)182 static inline void __downgrade_write(struct rw_semaphore *sem)
183 {
184 	signed long old, new, tmp;
185 
186 	tmp = -RWSEM_WAITING_BIAS;
187 	asm volatile(
188 		"	lg	%0,%2\n"
189 		"0:	lgr	%1,%0\n"
190 		"	ag	%1,%4\n"
191 		"	csg	%0,%1,%2\n"
192 		"	jl	0b"
193 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
194 		: "Q" (sem->count), "m" (tmp)
195 		: "cc", "memory");
196 	if (new > 1)
197 		rwsem_downgrade_wake(sem);
198 }
199 
200 /*
201  * implement atomic add functionality
202  */
rwsem_atomic_add(long delta,struct rw_semaphore * sem)203 static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
204 {
205 	signed long old, new;
206 
207 	asm volatile(
208 		"	lg	%0,%2\n"
209 		"0:	lgr	%1,%0\n"
210 		"	agr	%1,%4\n"
211 		"	csg	%0,%1,%2\n"
212 		"	jl	0b"
213 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
214 		: "Q" (sem->count), "d" (delta)
215 		: "cc", "memory");
216 }
217 
218 /*
219  * implement exchange and add functionality
220  */
rwsem_atomic_update(long delta,struct rw_semaphore * sem)221 static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
222 {
223 	signed long old, new;
224 
225 	asm volatile(
226 		"	lg	%0,%2\n"
227 		"0:	lgr	%1,%0\n"
228 		"	agr	%1,%4\n"
229 		"	csg	%0,%1,%2\n"
230 		"	jl	0b"
231 		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
232 		: "Q" (sem->count), "d" (delta)
233 		: "cc", "memory");
234 	return new;
235 }
236 
237 #endif /* _S390_RWSEM_H */
238