Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #ifndef _S390_RWSEM_H |
2 | #define _S390_RWSEM_H | |
3 | ||
4 | /* | |
1da177e4 | 5 | * S390 version |
a53c8fab | 6 | * Copyright IBM Corp. 2002 |
1da177e4 LT |
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 | |
7eb792bf | 34 | * that will be woken up; if there's a bunch of consecutive readers at the |
1da177e4 LT |
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 | ||
1da177e4 LT |
42 | #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L |
43 | #define RWSEM_ACTIVE_BIAS 0x0000000000000001L | |
44 | #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL | |
45 | #define RWSEM_WAITING_BIAS (-0x0000000100000000L) | |
1da177e4 LT |
46 | #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS |
47 | #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) | |
48 | ||
1da177e4 LT |
49 | /* |
50 | * lock for reading | |
51 | */ | |
52 | static inline void __down_read(struct rw_semaphore *sem) | |
53 | { | |
54 | signed long old, new; | |
55 | ||
94c12cc7 | 56 | asm volatile( |
987bcdac | 57 | " lg %0,%2\n" |
94c12cc7 | 58 | "0: lgr %1,%0\n" |
987bcdac MS |
59 | " aghi %1,%4\n" |
60 | " csg %0,%1,%2\n" | |
94c12cc7 | 61 | " jl 0b" |
987bcdac MS |
62 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
63 | : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) | |
64 | : "cc", "memory"); | |
1da177e4 LT |
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 | ||
94c12cc7 | 76 | asm volatile( |
987bcdac | 77 | " lg %0,%2\n" |
94c12cc7 MS |
78 | "0: ltgr %1,%0\n" |
79 | " jm 1f\n" | |
987bcdac MS |
80 | " aghi %1,%4\n" |
81 | " csg %0,%1,%2\n" | |
94c12cc7 | 82 | " jl 0b\n" |
1da177e4 | 83 | "1:" |
987bcdac MS |
84 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
85 | : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) | |
86 | : "cc", "memory"); | |
1da177e4 LT |
87 | return old >= 0 ? 1 : 0; |
88 | } | |
89 | ||
90 | /* | |
91 | * lock for writing | |
92 | */ | |
4ea2176d | 93 | static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) |
1da177e4 LT |
94 | { |
95 | signed long old, new, tmp; | |
96 | ||
97 | tmp = RWSEM_ACTIVE_WRITE_BIAS; | |
94c12cc7 | 98 | asm volatile( |
987bcdac | 99 | " lg %0,%2\n" |
94c12cc7 | 100 | "0: lgr %1,%0\n" |
987bcdac MS |
101 | " ag %1,%4\n" |
102 | " csg %0,%1,%2\n" | |
94c12cc7 | 103 | " jl 0b" |
987bcdac MS |
104 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
105 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 106 | : "cc", "memory"); |
1da177e4 LT |
107 | if (old != 0) |
108 | rwsem_down_write_failed(sem); | |
109 | } | |
110 | ||
4ea2176d IM |
111 | static inline void __down_write(struct rw_semaphore *sem) |
112 | { | |
113 | __down_write_nested(sem, 0); | |
114 | } | |
115 | ||
1da177e4 LT |
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 | ||
94c12cc7 | 123 | asm volatile( |
987bcdac | 124 | " lg %0,%1\n" |
94c12cc7 MS |
125 | "0: ltgr %0,%0\n" |
126 | " jnz 1f\n" | |
987bcdac | 127 | " csg %0,%3,%1\n" |
94c12cc7 | 128 | " jl 0b\n" |
1da177e4 | 129 | "1:" |
987bcdac MS |
130 | : "=&d" (old), "=Q" (sem->count) |
131 | : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS) | |
132 | : "cc", "memory"); | |
1da177e4 LT |
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 | ||
94c12cc7 | 143 | asm volatile( |
987bcdac | 144 | " lg %0,%2\n" |
94c12cc7 | 145 | "0: lgr %1,%0\n" |
987bcdac MS |
146 | " aghi %1,%4\n" |
147 | " csg %0,%1,%2\n" | |
94c12cc7 | 148 | " jl 0b" |
987bcdac MS |
149 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
150 | : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS) | |
94c12cc7 | 151 | : "cc", "memory"); |
1da177e4 LT |
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; | |
94c12cc7 | 165 | asm volatile( |
987bcdac | 166 | " lg %0,%2\n" |
94c12cc7 | 167 | "0: lgr %1,%0\n" |
987bcdac MS |
168 | " ag %1,%4\n" |
169 | " csg %0,%1,%2\n" | |
94c12cc7 | 170 | " jl 0b" |
987bcdac MS |
171 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
172 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 173 | : "cc", "memory"); |
1da177e4 LT |
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; | |
94c12cc7 | 187 | asm volatile( |
987bcdac | 188 | " lg %0,%2\n" |
94c12cc7 | 189 | "0: lgr %1,%0\n" |
987bcdac MS |
190 | " ag %1,%4\n" |
191 | " csg %0,%1,%2\n" | |
94c12cc7 | 192 | " jl 0b" |
987bcdac MS |
193 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
194 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 195 | : "cc", "memory"); |
1da177e4 LT |
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 | ||
94c12cc7 | 207 | asm volatile( |
987bcdac | 208 | " lg %0,%2\n" |
94c12cc7 | 209 | "0: lgr %1,%0\n" |
987bcdac MS |
210 | " agr %1,%4\n" |
211 | " csg %0,%1,%2\n" | |
94c12cc7 | 212 | " jl 0b" |
987bcdac MS |
213 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
214 | : "Q" (sem->count), "d" (delta) | |
94c12cc7 | 215 | : "cc", "memory"); |
1da177e4 LT |
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 | ||
94c12cc7 | 225 | asm volatile( |
987bcdac | 226 | " lg %0,%2\n" |
94c12cc7 | 227 | "0: lgr %1,%0\n" |
987bcdac MS |
228 | " agr %1,%4\n" |
229 | " csg %0,%1,%2\n" | |
94c12cc7 | 230 | " jl 0b" |
987bcdac MS |
231 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
232 | : "Q" (sem->count), "d" (delta) | |
94c12cc7 | 233 | : "cc", "memory"); |
1da177e4 LT |
234 | return new; |
235 | } | |
236 | ||
1da177e4 | 237 | #endif /* _S390_RWSEM_H */ |