Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 #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  */
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  */
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  */
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
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  */
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  */
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  */
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  */
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  */
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  */
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 */