1 /* SPDX-License-Identifier: GPL-2.0 2 * 3 * include/asm-sh/spinlock-cas.h 4 * 5 * Copyright (C) 2015 SEI 6 */ 7 #ifndef __ASM_SH_SPINLOCK_CAS_H 8 #define __ASM_SH_SPINLOCK_CAS_H 9 10 #include <asm/barrier.h> 11 #include <asm/processor.h> 12 13 static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new) 14 { 15 __asm__ __volatile__("cas.l %1,%0,@r0" 16 : "+r"(new) 17 : "r"(old), "z"(p) 18 : "t", "memory" ); 19 return new; 20 } 21 22 /* 23 * Your basic SMP spinlocks, allowing only a single CPU anywhere 24 */ 25 26 #define arch_spin_is_locked(x) ((x)->lock <= 0) 27 28 static inline void arch_spin_lock(arch_spinlock_t *lock) 29 { 30 while (!__sl_cas(&lock->lock, 1, 0)); 31 } 32 33 static inline void arch_spin_unlock(arch_spinlock_t *lock) 34 { 35 __sl_cas(&lock->lock, 0, 1); 36 } 37 38 static inline int arch_spin_trylock(arch_spinlock_t *lock) 39 { 40 return __sl_cas(&lock->lock, 1, 0); 41 } 42 43 /* 44 * Read-write spinlocks, allowing multiple readers but only one writer. 45 * 46 * NOTE! it is quite common to have readers in interrupts but no interrupt 47 * writers. For those circumstances we can "mix" irq-safe locks - any writer 48 * needs to get a irq-safe write-lock, but readers can get non-irqsafe 49 * read-locks. 50 */ 51 52 static inline void arch_read_lock(arch_rwlock_t *rw) 53 { 54 unsigned old; 55 do old = rw->lock; 56 while (!old || __sl_cas(&rw->lock, old, old-1) != old); 57 } 58 59 static inline void arch_read_unlock(arch_rwlock_t *rw) 60 { 61 unsigned old; 62 do old = rw->lock; 63 while (__sl_cas(&rw->lock, old, old+1) != old); 64 } 65 66 static inline void arch_write_lock(arch_rwlock_t *rw) 67 { 68 while (__sl_cas(&rw->lock, RW_LOCK_BIAS, 0) != RW_LOCK_BIAS); 69 } 70 71 static inline void arch_write_unlock(arch_rwlock_t *rw) 72 { 73 __sl_cas(&rw->lock, 0, RW_LOCK_BIAS); 74 } 75 76 static inline int arch_read_trylock(arch_rwlock_t *rw) 77 { 78 unsigned old; 79 do old = rw->lock; 80 while (old && __sl_cas(&rw->lock, old, old-1) != old); 81 return !!old; 82 } 83 84 static inline int arch_write_trylock(arch_rwlock_t *rw) 85 { 86 return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS; 87 } 88 89 #endif /* __ASM_SH_SPINLOCK_CAS_H */ 90