Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / arch / s390 / include / asm / rwsem.h
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 #ifndef CONFIG_64BIT
43 #define RWSEM_UNLOCKED_VALUE    0x00000000
44 #define RWSEM_ACTIVE_BIAS       0x00000001
45 #define RWSEM_ACTIVE_MASK       0x0000ffff
46 #define RWSEM_WAITING_BIAS      (-0x00010000)
47 #else /* CONFIG_64BIT */
48 #define RWSEM_UNLOCKED_VALUE    0x0000000000000000L
49 #define RWSEM_ACTIVE_BIAS       0x0000000000000001L
50 #define RWSEM_ACTIVE_MASK       0x00000000ffffffffL
51 #define RWSEM_WAITING_BIAS      (-0x0000000100000000L)
52 #endif /* CONFIG_64BIT */
53 #define RWSEM_ACTIVE_READ_BIAS  RWSEM_ACTIVE_BIAS
54 #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
55
56 /*
57  * lock for reading
58  */
59 static inline void __down_read(struct rw_semaphore *sem)
60 {
61         signed long old, new;
62
63         asm volatile(
64 #ifndef CONFIG_64BIT
65                 "       l       %0,%2\n"
66                 "0:     lr      %1,%0\n"
67                 "       ahi     %1,%4\n"
68                 "       cs      %0,%1,%2\n"
69                 "       jl      0b"
70 #else /* CONFIG_64BIT */
71                 "       lg      %0,%2\n"
72                 "0:     lgr     %1,%0\n"
73                 "       aghi    %1,%4\n"
74                 "       csg     %0,%1,%2\n"
75                 "       jl      0b"
76 #endif /* CONFIG_64BIT */
77                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
78                 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
79                 : "cc", "memory");
80         if (old < 0)
81                 rwsem_down_read_failed(sem);
82 }
83
84 /*
85  * trylock for reading -- returns 1 if successful, 0 if contention
86  */
87 static inline int __down_read_trylock(struct rw_semaphore *sem)
88 {
89         signed long old, new;
90
91         asm volatile(
92 #ifndef CONFIG_64BIT
93                 "       l       %0,%2\n"
94                 "0:     ltr     %1,%0\n"
95                 "       jm      1f\n"
96                 "       ahi     %1,%4\n"
97                 "       cs      %0,%1,%2\n"
98                 "       jl      0b\n"
99                 "1:"
100 #else /* CONFIG_64BIT */
101                 "       lg      %0,%2\n"
102                 "0:     ltgr    %1,%0\n"
103                 "       jm      1f\n"
104                 "       aghi    %1,%4\n"
105                 "       csg     %0,%1,%2\n"
106                 "       jl      0b\n"
107                 "1:"
108 #endif /* CONFIG_64BIT */
109                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
110                 : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
111                 : "cc", "memory");
112         return old >= 0 ? 1 : 0;
113 }
114
115 /*
116  * lock for writing
117  */
118 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
119 {
120         signed long old, new, tmp;
121
122         tmp = RWSEM_ACTIVE_WRITE_BIAS;
123         asm volatile(
124 #ifndef CONFIG_64BIT
125                 "       l       %0,%2\n"
126                 "0:     lr      %1,%0\n"
127                 "       a       %1,%4\n"
128                 "       cs      %0,%1,%2\n"
129                 "       jl      0b"
130 #else /* CONFIG_64BIT */
131                 "       lg      %0,%2\n"
132                 "0:     lgr     %1,%0\n"
133                 "       ag      %1,%4\n"
134                 "       csg     %0,%1,%2\n"
135                 "       jl      0b"
136 #endif /* CONFIG_64BIT */
137                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
138                 : "Q" (sem->count), "m" (tmp)
139                 : "cc", "memory");
140         if (old != 0)
141                 rwsem_down_write_failed(sem);
142 }
143
144 static inline void __down_write(struct rw_semaphore *sem)
145 {
146         __down_write_nested(sem, 0);
147 }
148
149 /*
150  * trylock for writing -- returns 1 if successful, 0 if contention
151  */
152 static inline int __down_write_trylock(struct rw_semaphore *sem)
153 {
154         signed long old;
155
156         asm volatile(
157 #ifndef CONFIG_64BIT
158                 "       l       %0,%1\n"
159                 "0:     ltr     %0,%0\n"
160                 "       jnz     1f\n"
161                 "       cs      %0,%3,%1\n"
162                 "       jl      0b\n"
163 #else /* CONFIG_64BIT */
164                 "       lg      %0,%1\n"
165                 "0:     ltgr    %0,%0\n"
166                 "       jnz     1f\n"
167                 "       csg     %0,%3,%1\n"
168                 "       jl      0b\n"
169 #endif /* CONFIG_64BIT */
170                 "1:"
171                 : "=&d" (old), "=Q" (sem->count)
172                 : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
173                 : "cc", "memory");
174         return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
175 }
176
177 /*
178  * unlock after reading
179  */
180 static inline void __up_read(struct rw_semaphore *sem)
181 {
182         signed long old, new;
183
184         asm volatile(
185 #ifndef CONFIG_64BIT
186                 "       l       %0,%2\n"
187                 "0:     lr      %1,%0\n"
188                 "       ahi     %1,%4\n"
189                 "       cs      %0,%1,%2\n"
190                 "       jl      0b"
191 #else /* CONFIG_64BIT */
192                 "       lg      %0,%2\n"
193                 "0:     lgr     %1,%0\n"
194                 "       aghi    %1,%4\n"
195                 "       csg     %0,%1,%2\n"
196                 "       jl      0b"
197 #endif /* CONFIG_64BIT */
198                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
199                 : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
200                 : "cc", "memory");
201         if (new < 0)
202                 if ((new & RWSEM_ACTIVE_MASK) == 0)
203                         rwsem_wake(sem);
204 }
205
206 /*
207  * unlock after writing
208  */
209 static inline void __up_write(struct rw_semaphore *sem)
210 {
211         signed long old, new, tmp;
212
213         tmp = -RWSEM_ACTIVE_WRITE_BIAS;
214         asm volatile(
215 #ifndef CONFIG_64BIT
216                 "       l       %0,%2\n"
217                 "0:     lr      %1,%0\n"
218                 "       a       %1,%4\n"
219                 "       cs      %0,%1,%2\n"
220                 "       jl      0b"
221 #else /* CONFIG_64BIT */
222                 "       lg      %0,%2\n"
223                 "0:     lgr     %1,%0\n"
224                 "       ag      %1,%4\n"
225                 "       csg     %0,%1,%2\n"
226                 "       jl      0b"
227 #endif /* CONFIG_64BIT */
228                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
229                 : "Q" (sem->count), "m" (tmp)
230                 : "cc", "memory");
231         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  */
239 static inline void __downgrade_write(struct rw_semaphore *sem)
240 {
241         signed long old, new, tmp;
242
243         tmp = -RWSEM_WAITING_BIAS;
244         asm volatile(
245 #ifndef CONFIG_64BIT
246                 "       l       %0,%2\n"
247                 "0:     lr      %1,%0\n"
248                 "       a       %1,%4\n"
249                 "       cs      %0,%1,%2\n"
250                 "       jl      0b"
251 #else /* CONFIG_64BIT */
252                 "       lg      %0,%2\n"
253                 "0:     lgr     %1,%0\n"
254                 "       ag      %1,%4\n"
255                 "       csg     %0,%1,%2\n"
256                 "       jl      0b"
257 #endif /* CONFIG_64BIT */
258                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
259                 : "Q" (sem->count), "m" (tmp)
260                 : "cc", "memory");
261         if (new > 1)
262                 rwsem_downgrade_wake(sem);
263 }
264
265 /*
266  * implement atomic add functionality
267  */
268 static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
269 {
270         signed long old, new;
271
272         asm volatile(
273 #ifndef CONFIG_64BIT
274                 "       l       %0,%2\n"
275                 "0:     lr      %1,%0\n"
276                 "       ar      %1,%4\n"
277                 "       cs      %0,%1,%2\n"
278                 "       jl      0b"
279 #else /* CONFIG_64BIT */
280                 "       lg      %0,%2\n"
281                 "0:     lgr     %1,%0\n"
282                 "       agr     %1,%4\n"
283                 "       csg     %0,%1,%2\n"
284                 "       jl      0b"
285 #endif /* CONFIG_64BIT */
286                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
287                 : "Q" (sem->count), "d" (delta)
288                 : "cc", "memory");
289 }
290
291 /*
292  * implement exchange and add functionality
293  */
294 static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
295 {
296         signed long old, new;
297
298         asm volatile(
299 #ifndef CONFIG_64BIT
300                 "       l       %0,%2\n"
301                 "0:     lr      %1,%0\n"
302                 "       ar      %1,%4\n"
303                 "       cs      %0,%1,%2\n"
304                 "       jl      0b"
305 #else /* CONFIG_64BIT */
306                 "       lg      %0,%2\n"
307                 "0:     lgr     %1,%0\n"
308                 "       agr     %1,%4\n"
309                 "       csg     %0,%1,%2\n"
310                 "       jl      0b"
311 #endif /* CONFIG_64BIT */
312                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
313                 : "Q" (sem->count), "d" (delta)
314                 : "cc", "memory");
315         return new;
316 }
317
318 #endif /* _S390_RWSEM_H */