]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/s390/include/asm/rwsem.h
Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block
[karo-tx-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 consecutive 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 long ___down_write(struct rw_semaphore *sem)
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
108         return old;
109 }
110
111 static inline void __down_write(struct rw_semaphore *sem)
112 {
113         if (___down_write(sem))
114                 rwsem_down_write_failed(sem);
115 }
116
117 static inline int __down_write_killable(struct rw_semaphore *sem)
118 {
119         if (___down_write(sem))
120                 if (IS_ERR(rwsem_down_write_failed_killable(sem)))
121                         return -EINTR;
122
123         return 0;
124 }
125
126 /*
127  * trylock for writing -- returns 1 if successful, 0 if contention
128  */
129 static inline int __down_write_trylock(struct rw_semaphore *sem)
130 {
131         signed long old;
132
133         asm volatile(
134                 "       lg      %0,%1\n"
135                 "0:     ltgr    %0,%0\n"
136                 "       jnz     1f\n"
137                 "       csg     %0,%3,%1\n"
138                 "       jl      0b\n"
139                 "1:"
140                 : "=&d" (old), "=Q" (sem->count)
141                 : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
142                 : "cc", "memory");
143         return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
144 }
145
146 /*
147  * unlock after reading
148  */
149 static inline void __up_read(struct rw_semaphore *sem)
150 {
151         signed long old, new;
152
153         asm volatile(
154                 "       lg      %0,%2\n"
155                 "0:     lgr     %1,%0\n"
156                 "       aghi    %1,%4\n"
157                 "       csg     %0,%1,%2\n"
158                 "       jl      0b"
159                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
160                 : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
161                 : "cc", "memory");
162         if (new < 0)
163                 if ((new & RWSEM_ACTIVE_MASK) == 0)
164                         rwsem_wake(sem);
165 }
166
167 /*
168  * unlock after writing
169  */
170 static inline void __up_write(struct rw_semaphore *sem)
171 {
172         signed long old, new, tmp;
173
174         tmp = -RWSEM_ACTIVE_WRITE_BIAS;
175         asm volatile(
176                 "       lg      %0,%2\n"
177                 "0:     lgr     %1,%0\n"
178                 "       ag      %1,%4\n"
179                 "       csg     %0,%1,%2\n"
180                 "       jl      0b"
181                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
182                 : "Q" (sem->count), "m" (tmp)
183                 : "cc", "memory");
184         if (new < 0)
185                 if ((new & RWSEM_ACTIVE_MASK) == 0)
186                         rwsem_wake(sem);
187 }
188
189 /*
190  * downgrade write lock to read lock
191  */
192 static inline void __downgrade_write(struct rw_semaphore *sem)
193 {
194         signed long old, new, tmp;
195
196         tmp = -RWSEM_WAITING_BIAS;
197         asm volatile(
198                 "       lg      %0,%2\n"
199                 "0:     lgr     %1,%0\n"
200                 "       ag      %1,%4\n"
201                 "       csg     %0,%1,%2\n"
202                 "       jl      0b"
203                 : "=&d" (old), "=&d" (new), "=Q" (sem->count)
204                 : "Q" (sem->count), "m" (tmp)
205                 : "cc", "memory");
206         if (new > 1)
207                 rwsem_downgrade_wake(sem);
208 }
209
210 #endif /* _S390_RWSEM_H */