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