]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 | 2 | * S390 version |
a53c8fab | 3 | * Copyright IBM Corp. 1999 |
1da177e4 LT |
4 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
5 | * | |
6 | * Derived from "include/asm-i386/spinlock.h" | |
7 | */ | |
8 | ||
9 | #ifndef __ASM_SPINLOCK_H | |
10 | #define __ASM_SPINLOCK_H | |
11 | ||
3c1fcfe2 | 12 | #include <linux/smp.h> |
02c503ff | 13 | #include <asm/atomic_ops.h> |
726328d9 PZ |
14 | #include <asm/barrier.h> |
15 | #include <asm/processor.h> | |
3c1fcfe2 | 16 | |
6c8cd5bb PH |
17 | #define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval) |
18 | ||
638ad34a MS |
19 | extern int spin_retry; |
20 | ||
760928c0 CB |
21 | #ifndef CONFIG_SMP |
22 | static inline bool arch_vcpu_is_preempted(int cpu) { return false; } | |
23 | #else | |
24 | bool arch_vcpu_is_preempted(int cpu); | |
25 | #endif | |
26 | ||
27 | #define vcpu_is_preempted arch_vcpu_is_preempted | |
28 | ||
1da177e4 LT |
29 | /* |
30 | * Simple spin lock operations. There are two variants, one clears IRQ's | |
31 | * on the local processor, one does not. | |
32 | * | |
33 | * We make no fairness assumptions. They have a cost. | |
fb1c8f93 IM |
34 | * |
35 | * (the type definitions are in asm/spinlock_types.h) | |
1da177e4 LT |
36 | */ |
37 | ||
02c503ff | 38 | void arch_lock_relax(int cpu); |
d59b93da | 39 | |
5b3f683e PH |
40 | void arch_spin_lock_wait(arch_spinlock_t *); |
41 | int arch_spin_trylock_retry(arch_spinlock_t *); | |
5b3f683e | 42 | void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags); |
951f22d5 | 43 | |
d59b93da MS |
44 | static inline void arch_spin_relax(arch_spinlock_t *lock) |
45 | { | |
46 | arch_lock_relax(lock->lock); | |
47 | } | |
48 | ||
6c8cd5bb PH |
49 | static inline u32 arch_spin_lockval(int cpu) |
50 | { | |
51 | return ~cpu; | |
52 | } | |
53 | ||
efc1d23b HC |
54 | static inline int arch_spin_value_unlocked(arch_spinlock_t lock) |
55 | { | |
5b3f683e | 56 | return lock.lock == 0; |
efc1d23b HC |
57 | } |
58 | ||
5b3f683e PH |
59 | static inline int arch_spin_is_locked(arch_spinlock_t *lp) |
60 | { | |
187b5f41 | 61 | return READ_ONCE(lp->lock) != 0; |
5b3f683e PH |
62 | } |
63 | ||
64 | static inline int arch_spin_trylock_once(arch_spinlock_t *lp) | |
1da177e4 | 65 | { |
bae8f567 MS |
66 | barrier(); |
67 | return likely(arch_spin_value_unlocked(*lp) && | |
02c503ff | 68 | __atomic_cmpxchg_bool(&lp->lock, 0, SPINLOCK_LOCKVAL)); |
1da177e4 LT |
69 | } |
70 | ||
5b3f683e | 71 | static inline void arch_spin_lock(arch_spinlock_t *lp) |
1da177e4 | 72 | { |
bae8f567 | 73 | if (!arch_spin_trylock_once(lp)) |
5b3f683e PH |
74 | arch_spin_lock_wait(lp); |
75 | } | |
951f22d5 | 76 | |
5b3f683e PH |
77 | static inline void arch_spin_lock_flags(arch_spinlock_t *lp, |
78 | unsigned long flags) | |
79 | { | |
bae8f567 | 80 | if (!arch_spin_trylock_once(lp)) |
5b3f683e PH |
81 | arch_spin_lock_wait_flags(lp, flags); |
82 | } | |
83 | ||
84 | static inline int arch_spin_trylock(arch_spinlock_t *lp) | |
85 | { | |
bae8f567 | 86 | if (!arch_spin_trylock_once(lp)) |
5b3f683e PH |
87 | return arch_spin_trylock_retry(lp); |
88 | return 1; | |
1da177e4 LT |
89 | } |
90 | ||
0199c4e6 | 91 | static inline void arch_spin_unlock(arch_spinlock_t *lp) |
1da177e4 | 92 | { |
02c503ff | 93 | typecheck(int, lp->lock); |
44230282 | 94 | asm volatile( |
44230282 HC |
95 | "st %1,%0\n" |
96 | : "+Q" (lp->lock) | |
97 | : "d" (0) | |
98 | : "cc", "memory"); | |
1da177e4 | 99 | } |
5b3f683e PH |
100 | |
101 | static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) | |
102 | { | |
103 | while (arch_spin_is_locked(lock)) | |
104 | arch_spin_relax(lock); | |
726328d9 | 105 | smp_acquire__after_ctrl_dep(); |
5b3f683e PH |
106 | } |
107 | ||
1da177e4 LT |
108 | /* |
109 | * Read-write spinlocks, allowing multiple readers | |
110 | * but only one writer. | |
111 | * | |
112 | * NOTE! it is quite common to have readers in interrupts | |
113 | * but no interrupt writers. For those circumstances we | |
114 | * can "mix" irq-safe locks - any writer needs to get a | |
115 | * irq-safe write-lock, but readers can get non-irqsafe | |
116 | * read-locks. | |
117 | */ | |
1da177e4 LT |
118 | |
119 | /** | |
120 | * read_can_lock - would read_trylock() succeed? | |
121 | * @lock: the rwlock in question. | |
122 | */ | |
e5931943 | 123 | #define arch_read_can_lock(x) ((int)(x)->lock >= 0) |
1da177e4 LT |
124 | |
125 | /** | |
126 | * write_can_lock - would write_trylock() succeed? | |
127 | * @lock: the rwlock in question. | |
128 | */ | |
e5931943 | 129 | #define arch_write_can_lock(x) ((x)->lock == 0) |
1da177e4 | 130 | |
2684e73a | 131 | extern int _raw_read_trylock_retry(arch_rwlock_t *lp); |
fb3a6bbc TG |
132 | extern int _raw_write_trylock_retry(arch_rwlock_t *lp); |
133 | ||
2684e73a MS |
134 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) |
135 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | |
136 | ||
bae8f567 MS |
137 | static inline int arch_read_trylock_once(arch_rwlock_t *rw) |
138 | { | |
02c503ff MS |
139 | int old = ACCESS_ONCE(rw->lock); |
140 | return likely(old >= 0 && | |
141 | __atomic_cmpxchg_bool(&rw->lock, old, old + 1)); | |
bae8f567 MS |
142 | } |
143 | ||
144 | static inline int arch_write_trylock_once(arch_rwlock_t *rw) | |
145 | { | |
02c503ff | 146 | int old = ACCESS_ONCE(rw->lock); |
bae8f567 | 147 | return likely(old == 0 && |
02c503ff | 148 | __atomic_cmpxchg_bool(&rw->lock, 0, 0x80000000)); |
bae8f567 MS |
149 | } |
150 | ||
bbae71bf MS |
151 | #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES |
152 | ||
153 | #define __RAW_OP_OR "lao" | |
154 | #define __RAW_OP_AND "lan" | |
155 | #define __RAW_OP_ADD "laa" | |
156 | ||
157 | #define __RAW_LOCK(ptr, op_val, op_string) \ | |
158 | ({ \ | |
02c503ff | 159 | int old_val; \ |
bbae71bf | 160 | \ |
02c503ff | 161 | typecheck(int *, ptr); \ |
bbae71bf MS |
162 | asm volatile( \ |
163 | op_string " %0,%2,%1\n" \ | |
164 | "bcr 14,0\n" \ | |
165 | : "=d" (old_val), "+Q" (*ptr) \ | |
166 | : "d" (op_val) \ | |
167 | : "cc", "memory"); \ | |
168 | old_val; \ | |
169 | }) | |
170 | ||
171 | #define __RAW_UNLOCK(ptr, op_val, op_string) \ | |
172 | ({ \ | |
02c503ff | 173 | int old_val; \ |
bbae71bf | 174 | \ |
02c503ff | 175 | typecheck(int *, ptr); \ |
bbae71bf | 176 | asm volatile( \ |
bbae71bf MS |
177 | op_string " %0,%2,%1\n" \ |
178 | : "=d" (old_val), "+Q" (*ptr) \ | |
179 | : "d" (op_val) \ | |
180 | : "cc", "memory"); \ | |
181 | old_val; \ | |
182 | }) | |
183 | ||
184 | extern void _raw_read_lock_wait(arch_rwlock_t *lp); | |
02c503ff | 185 | extern void _raw_write_lock_wait(arch_rwlock_t *lp, int prev); |
bbae71bf MS |
186 | |
187 | static inline void arch_read_lock(arch_rwlock_t *rw) | |
188 | { | |
02c503ff | 189 | int old; |
bbae71bf MS |
190 | |
191 | old = __RAW_LOCK(&rw->lock, 1, __RAW_OP_ADD); | |
02c503ff | 192 | if (old < 0) |
bbae71bf MS |
193 | _raw_read_lock_wait(rw); |
194 | } | |
195 | ||
196 | static inline void arch_read_unlock(arch_rwlock_t *rw) | |
197 | { | |
198 | __RAW_UNLOCK(&rw->lock, -1, __RAW_OP_ADD); | |
199 | } | |
200 | ||
201 | static inline void arch_write_lock(arch_rwlock_t *rw) | |
202 | { | |
02c503ff | 203 | int old; |
bbae71bf MS |
204 | |
205 | old = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR); | |
206 | if (old != 0) | |
207 | _raw_write_lock_wait(rw, old); | |
208 | rw->owner = SPINLOCK_LOCKVAL; | |
209 | } | |
210 | ||
211 | static inline void arch_write_unlock(arch_rwlock_t *rw) | |
212 | { | |
213 | rw->owner = 0; | |
214 | __RAW_UNLOCK(&rw->lock, 0x7fffffff, __RAW_OP_AND); | |
215 | } | |
216 | ||
217 | #else /* CONFIG_HAVE_MARCH_Z196_FEATURES */ | |
218 | ||
219 | extern void _raw_read_lock_wait(arch_rwlock_t *lp); | |
220 | extern void _raw_write_lock_wait(arch_rwlock_t *lp); | |
221 | ||
e5931943 | 222 | static inline void arch_read_lock(arch_rwlock_t *rw) |
951f22d5 | 223 | { |
bae8f567 | 224 | if (!arch_read_trylock_once(rw)) |
951f22d5 MS |
225 | _raw_read_lock_wait(rw); |
226 | } | |
227 | ||
e5931943 | 228 | static inline void arch_read_unlock(arch_rwlock_t *rw) |
951f22d5 | 229 | { |
02c503ff | 230 | int old; |
951f22d5 | 231 | |
951f22d5 | 232 | do { |
5b3f683e | 233 | old = ACCESS_ONCE(rw->lock); |
02c503ff | 234 | } while (!__atomic_cmpxchg_bool(&rw->lock, old, old - 1)); |
951f22d5 MS |
235 | } |
236 | ||
e5931943 | 237 | static inline void arch_write_lock(arch_rwlock_t *rw) |
951f22d5 | 238 | { |
bae8f567 | 239 | if (!arch_write_trylock_once(rw)) |
951f22d5 | 240 | _raw_write_lock_wait(rw); |
d59b93da | 241 | rw->owner = SPINLOCK_LOCKVAL; |
951f22d5 MS |
242 | } |
243 | ||
e5931943 | 244 | static inline void arch_write_unlock(arch_rwlock_t *rw) |
951f22d5 | 245 | { |
02c503ff | 246 | typecheck(int, rw->lock); |
d59b93da MS |
247 | |
248 | rw->owner = 0; | |
44230282 | 249 | asm volatile( |
44230282 HC |
250 | "st %1,%0\n" |
251 | : "+Q" (rw->lock) | |
252 | : "d" (0) | |
253 | : "cc", "memory"); | |
951f22d5 MS |
254 | } |
255 | ||
bbae71bf MS |
256 | #endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */ |
257 | ||
e5931943 | 258 | static inline int arch_read_trylock(arch_rwlock_t *rw) |
951f22d5 | 259 | { |
bae8f567 MS |
260 | if (!arch_read_trylock_once(rw)) |
261 | return _raw_read_trylock_retry(rw); | |
262 | return 1; | |
951f22d5 MS |
263 | } |
264 | ||
e5931943 | 265 | static inline int arch_write_trylock(arch_rwlock_t *rw) |
1da177e4 | 266 | { |
d59b93da MS |
267 | if (!arch_write_trylock_once(rw) && !_raw_write_trylock_retry(rw)) |
268 | return 0; | |
269 | rw->owner = SPINLOCK_LOCKVAL; | |
bae8f567 | 270 | return 1; |
1da177e4 LT |
271 | } |
272 | ||
d59b93da MS |
273 | static inline void arch_read_relax(arch_rwlock_t *rw) |
274 | { | |
275 | arch_lock_relax(rw->owner); | |
276 | } | |
277 | ||
278 | static inline void arch_write_relax(arch_rwlock_t *rw) | |
279 | { | |
280 | arch_lock_relax(rw->owner); | |
281 | } | |
ef6edc97 | 282 | |
1da177e4 | 283 | #endif /* __ASM_SPINLOCK_H */ |