]>
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 | */ | |
4edab14e | 93 | static inline long ___down_write(struct rw_semaphore *sem) |
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"); |
4edab14e MH |
107 | |
108 | return old; | |
109 | } | |
110 | ||
111 | static inline void __down_write(struct rw_semaphore *sem) | |
112 | { | |
113 | if (___down_write(sem)) | |
1da177e4 LT |
114 | rwsem_down_write_failed(sem); |
115 | } | |
116 | ||
4edab14e MH |
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 | ||
1da177e4 LT |
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 | ||
94c12cc7 | 133 | asm volatile( |
987bcdac | 134 | " lg %0,%1\n" |
94c12cc7 MS |
135 | "0: ltgr %0,%0\n" |
136 | " jnz 1f\n" | |
987bcdac | 137 | " csg %0,%3,%1\n" |
94c12cc7 | 138 | " jl 0b\n" |
1da177e4 | 139 | "1:" |
987bcdac MS |
140 | : "=&d" (old), "=Q" (sem->count) |
141 | : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS) | |
142 | : "cc", "memory"); | |
1da177e4 LT |
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 | ||
94c12cc7 | 153 | asm volatile( |
987bcdac | 154 | " lg %0,%2\n" |
94c12cc7 | 155 | "0: lgr %1,%0\n" |
987bcdac MS |
156 | " aghi %1,%4\n" |
157 | " csg %0,%1,%2\n" | |
94c12cc7 | 158 | " jl 0b" |
987bcdac MS |
159 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
160 | : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS) | |
94c12cc7 | 161 | : "cc", "memory"); |
1da177e4 LT |
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; | |
94c12cc7 | 175 | asm volatile( |
987bcdac | 176 | " lg %0,%2\n" |
94c12cc7 | 177 | "0: lgr %1,%0\n" |
987bcdac MS |
178 | " ag %1,%4\n" |
179 | " csg %0,%1,%2\n" | |
94c12cc7 | 180 | " jl 0b" |
987bcdac MS |
181 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
182 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 183 | : "cc", "memory"); |
1da177e4 LT |
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; | |
94c12cc7 | 197 | asm volatile( |
987bcdac | 198 | " lg %0,%2\n" |
94c12cc7 | 199 | "0: lgr %1,%0\n" |
987bcdac MS |
200 | " ag %1,%4\n" |
201 | " csg %0,%1,%2\n" | |
94c12cc7 | 202 | " jl 0b" |
987bcdac MS |
203 | : "=&d" (old), "=&d" (new), "=Q" (sem->count) |
204 | : "Q" (sem->count), "m" (tmp) | |
94c12cc7 | 205 | : "cc", "memory"); |
1da177e4 LT |
206 | if (new > 1) |
207 | rwsem_downgrade_wake(sem); | |
208 | } | |
209 | ||
1da177e4 | 210 | #endif /* _S390_RWSEM_H */ |