Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
1da177e4 LT |
2 | #ifndef _S390_RWSEM_H |
3 | #define _S390_RWSEM_H | |
4 | ||
5 | /* | |
1da177e4 | 6 | * S390 version |
a53c8fab | 7 | * Copyright IBM Corp. 2002 |
1da177e4 LT |
8 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
9 | * | |
10 | * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h | |
11 | */ | |
12 | ||
13 | /* | |
14 | * | |
15 | * The MSW of the count is the negated number of active writers and waiting | |
16 | * lockers, and the LSW is the total number of active locks | |
17 | * | |
18 | * The lock count is initialized to 0 (no active and no waiting lockers). | |
19 | * | |
20 | * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an | |
21 | * uncontended lock. This can be determined because XADD returns the old value. | |
22 | * Readers increment by 1 and see a positive value when uncontended, negative | |
23 | * if there are writers (and maybe) readers waiting (in which case it goes to | |
24 | * sleep). | |
25 | * | |
26 | * The value of WAITING_BIAS supports up to 32766 waiting processes. This can | |
27 | * be extended to 65534 by manually checking the whole MSW rather than relying | |
28 | * on the S flag. | |
29 | * | |
30 | * The value of ACTIVE_BIAS supports up to 65535 active processes. | |
31 | * | |
32 | * This should be totally fair - if anything is waiting, a process that wants a | |
33 | * lock will go to the back of the queue. When the currently active lock is | |
34 | * released, if there's a writer at the front of the queue, then that and only | |
7eb792bf | 35 | * that will be woken up; if there's a bunch of consecutive readers at the |
1da177e4 LT |
36 | * front, then they'll all be woken up, but no other readers will be. |
37 | */ | |
38 | ||
39 | #ifndef _LINUX_RWSEM_H | |
40 | #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" | |
41 | #endif | |
42 | ||
1da177e4 LT |
43 | #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L |
44 | #define RWSEM_ACTIVE_BIAS 0x0000000000000001L | |
45 | #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL | |
46 | #define RWSEM_WAITING_BIAS (-0x0000000100000000L) | |
1da177e4 LT |
47 | #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS |
48 | #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) | |
49 | ||
1da177e4 LT |
50 | /* |
51 | * lock for reading | |
52 | */ | |
53 | static inline void __down_read(struct rw_semaphore *sem) | |
54 | { | |
55 | signed long old, new; | |
56 | ||
94c12cc7 | 57 | asm volatile( |
987bcdac | 58 | " lg %0,%2\n" |
94c12cc7 | 59 | "0: lgr %1,%0\n" |
987bcdac MS |
60 | " aghi %1,%4\n" |
61 | " csg %0,%1,%2\n" | |
94c12cc7 | 62 | " jl 0b" |
987bcdac MS |
63 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
64 | : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) | |
65 | : "cc", "memory"); | |
1da177e4 LT |
66 | if (old < 0) |
67 | rwsem_down_read_failed(sem); | |
68 | } | |
69 | ||
70 | /* | |
71 | * trylock for reading -- returns 1 if successful, 0 if contention | |
72 | */ | |
73 | static inline int __down_read_trylock(struct rw_semaphore *sem) | |
74 | { | |
75 | signed long old, new; | |
76 | ||
94c12cc7 | 77 | asm volatile( |
987bcdac | 78 | " lg %0,%2\n" |
94c12cc7 MS |
79 | "0: ltgr %1,%0\n" |
80 | " jm 1f\n" | |
987bcdac MS |
81 | " aghi %1,%4\n" |
82 | " csg %0,%1,%2\n" | |
94c12cc7 | 83 | " jl 0b\n" |
1da177e4 | 84 | "1:" |
987bcdac MS |
85 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
86 | : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) | |
87 | : "cc", "memory"); | |
1da177e4 LT |
88 | return old >= 0 ? 1 : 0; |
89 | } | |
90 | ||
91 | /* | |
92 | * lock for writing | |
93 | */ | |
4edab14e | 94 | static inline long ___down_write(struct rw_semaphore *sem) |
1da177e4 LT |
95 | { |
96 | signed long old, new, tmp; | |
97 | ||
98 | tmp = RWSEM_ACTIVE_WRITE_BIAS; | |
94c12cc7 | 99 | asm volatile( |
987bcdac | 100 | " lg %0,%2\n" |
94c12cc7 | 101 | "0: lgr %1,%0\n" |
987bcdac MS |
102 | " ag %1,%4\n" |
103 | " csg %0,%1,%2\n" | |
94c12cc7 | 104 | " jl 0b" |
987bcdac MS |
105 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
106 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 107 | : "cc", "memory"); |
4edab14e MH |
108 | |
109 | return old; | |
110 | } | |
111 | ||
112 | static inline void __down_write(struct rw_semaphore *sem) | |
113 | { | |
114 | if (___down_write(sem)) | |
1da177e4 LT |
115 | rwsem_down_write_failed(sem); |
116 | } | |
117 | ||
4edab14e MH |
118 | static inline int __down_write_killable(struct rw_semaphore *sem) |
119 | { | |
120 | if (___down_write(sem)) | |
121 | if (IS_ERR(rwsem_down_write_failed_killable(sem))) | |
122 | return -EINTR; | |
123 | ||
124 | return 0; | |
125 | } | |
126 | ||
1da177e4 LT |
127 | /* |
128 | * trylock for writing -- returns 1 if successful, 0 if contention | |
129 | */ | |
130 | static inline int __down_write_trylock(struct rw_semaphore *sem) | |
131 | { | |
132 | signed long old; | |
133 | ||
94c12cc7 | 134 | asm volatile( |
987bcdac | 135 | " lg %0,%1\n" |
94c12cc7 MS |
136 | "0: ltgr %0,%0\n" |
137 | " jnz 1f\n" | |
987bcdac | 138 | " csg %0,%3,%1\n" |
94c12cc7 | 139 | " jl 0b\n" |
1da177e4 | 140 | "1:" |
987bcdac MS |
141 | : "=&d" (old), "=Q" (sem->count) |
142 | : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS) | |
143 | : "cc", "memory"); | |
1da177e4 LT |
144 | return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0; |
145 | } | |
146 | ||
147 | /* | |
148 | * unlock after reading | |
149 | */ | |
150 | static inline void __up_read(struct rw_semaphore *sem) | |
151 | { | |
152 | signed long old, new; | |
153 | ||
94c12cc7 | 154 | asm volatile( |
987bcdac | 155 | " lg %0,%2\n" |
94c12cc7 | 156 | "0: lgr %1,%0\n" |
987bcdac MS |
157 | " aghi %1,%4\n" |
158 | " csg %0,%1,%2\n" | |
94c12cc7 | 159 | " jl 0b" |
987bcdac MS |
160 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
161 | : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS) | |
94c12cc7 | 162 | : "cc", "memory"); |
1da177e4 LT |
163 | if (new < 0) |
164 | if ((new & RWSEM_ACTIVE_MASK) == 0) | |
165 | rwsem_wake(sem); | |
166 | } | |
167 | ||
168 | /* | |
169 | * unlock after writing | |
170 | */ | |
171 | static inline void __up_write(struct rw_semaphore *sem) | |
172 | { | |
173 | signed long old, new, tmp; | |
174 | ||
175 | tmp = -RWSEM_ACTIVE_WRITE_BIAS; | |
94c12cc7 | 176 | asm volatile( |
987bcdac | 177 | " lg %0,%2\n" |
94c12cc7 | 178 | "0: lgr %1,%0\n" |
987bcdac MS |
179 | " ag %1,%4\n" |
180 | " csg %0,%1,%2\n" | |
94c12cc7 | 181 | " jl 0b" |
987bcdac MS |
182 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
183 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 184 | : "cc", "memory"); |
1da177e4 LT |
185 | if (new < 0) |
186 | if ((new & RWSEM_ACTIVE_MASK) == 0) | |
187 | rwsem_wake(sem); | |
188 | } | |
189 | ||
190 | /* | |
191 | * downgrade write lock to read lock | |
192 | */ | |
193 | static inline void __downgrade_write(struct rw_semaphore *sem) | |
194 | { | |
195 | signed long old, new, tmp; | |
196 | ||
197 | tmp = -RWSEM_WAITING_BIAS; | |
94c12cc7 | 198 | asm volatile( |
987bcdac | 199 | " lg %0,%2\n" |
94c12cc7 | 200 | "0: lgr %1,%0\n" |
987bcdac MS |
201 | " ag %1,%4\n" |
202 | " csg %0,%1,%2\n" | |
94c12cc7 | 203 | " jl 0b" |
987bcdac MS |
204 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
205 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 206 | : "cc", "memory"); |
1da177e4 LT |
207 | if (new > 1) |
208 | rwsem_downgrade_wake(sem); | |
209 | } | |
210 | ||
1da177e4 | 211 | #endif /* _S390_RWSEM_H */ |