Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 : /* 3 : * Queued spinlock 4 : * 5 : * A 'generic' spinlock implementation that is based on MCS locks. For an 6 : * architecture that's looking for a 'generic' spinlock, please first consider 7 : * ticket-lock.h and only come looking here when you've considered all the 8 : * constraints below and can show your hardware does actually perform better 9 : * with qspinlock. 10 : * 11 : * qspinlock relies on atomic_*_release()/atomic_*_acquire() to be RCsc (or no 12 : * weaker than RCtso if you're power), where regular code only expects atomic_t 13 : * to be RCpc. 14 : * 15 : * qspinlock relies on a far greater (compared to asm-generic/spinlock.h) set 16 : * of atomic operations to behave well together, please audit them carefully to 17 : * ensure they all have forward progress. Many atomic operations may default to 18 : * cmpxchg() loops which will not have good forward progress properties on 19 : * LL/SC architectures. 20 : * 21 : * One notable example is atomic_fetch_or_acquire(), which x86 cannot (cheaply) 22 : * do. Carefully read the patches that introduced 23 : * queued_fetch_set_pending_acquire(). 24 : * 25 : * qspinlock also heavily relies on mixed size atomic operations, in specific 26 : * it requires architectures to have xchg16; something which many LL/SC 27 : * architectures need to implement as a 32bit and+or in order to satisfy the 28 : * forward progress guarantees mentioned above. 29 : * 30 : * Further reading on mixed size atomics that might be relevant: 31 : * 32 : * http://www.cl.cam.ac.uk/~pes20/popl17/mixed-size.pdf 33 : * 34 : * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P. 35 : * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP 36 : * 37 : * Authors: Waiman Long <waiman.long@hpe.com> 38 : */ 39 : #ifndef __ASM_GENERIC_QSPINLOCK_H 40 : #define __ASM_GENERIC_QSPINLOCK_H 41 : 42 : #include <asm-generic/qspinlock_types.h> 43 : #include <linux/atomic.h> 44 : 45 : #ifndef queued_spin_is_locked 46 : /** 47 : * queued_spin_is_locked - is the spinlock locked? 48 : * @lock: Pointer to queued spinlock structure 49 : * Return: 1 if it is locked, 0 otherwise 50 : */ 51 : static __always_inline int queued_spin_is_locked(struct qspinlock *lock) 52 : { 53 : /* 54 : * Any !0 state indicates it is locked, even if _Q_LOCKED_VAL 55 : * isn't immediately observable. 56 : */ 57 616826226 : return atomic_read(&lock->val); 58 : } 59 : #endif 60 : 61 : /** 62 : * queued_spin_value_unlocked - is the spinlock structure unlocked? 63 : * @lock: queued spinlock structure 64 : * Return: 1 if it is unlocked, 0 otherwise 65 : * 66 : * N.B. Whenever there are tasks waiting for the lock, it is considered 67 : * locked wrt the lockref code to avoid lock stealing by the lockref 68 : * code and change things underneath the lock. This also allows some 69 : * optimizations to be applied without conflict with lockref. 70 : */ 71 : static __always_inline int queued_spin_value_unlocked(struct qspinlock lock) 72 : { 73 : return !atomic_read(&lock.val); 74 : } 75 : 76 : /** 77 : * queued_spin_is_contended - check if the lock is contended 78 : * @lock : Pointer to queued spinlock structure 79 : * Return: 1 if lock contended, 0 otherwise 80 : */ 81 : static __always_inline int queued_spin_is_contended(struct qspinlock *lock) 82 : { 83 0 : return atomic_read(&lock->val) & ~_Q_LOCKED_MASK; 84 : } 85 : /** 86 : * queued_spin_trylock - try to acquire the queued spinlock 87 : * @lock : Pointer to queued spinlock structure 88 : * Return: 1 if lock acquired, 0 if failed 89 : */ 90 : static __always_inline int queued_spin_trylock(struct qspinlock *lock) 91 : { 92 : int val = atomic_read(&lock->val); 93 : 94 : if (unlikely(val)) 95 : return 0; 96 : 97 : return likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL)); 98 : } 99 : 100 : extern void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val); 101 : 102 : #ifndef queued_spin_lock 103 : /** 104 : * queued_spin_lock - acquire a queued spinlock 105 : * @lock: Pointer to queued spinlock structure 106 : */ 107 : static __always_inline void queued_spin_lock(struct qspinlock *lock) 108 : { 109 : int val = 0; 110 : 111 : if (likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL))) 112 : return; 113 : 114 : queued_spin_lock_slowpath(lock, val); 115 : } 116 : #endif 117 : 118 : #ifndef queued_spin_unlock 119 : /** 120 : * queued_spin_unlock - release a queued spinlock 121 : * @lock : Pointer to queued spinlock structure 122 : */ 123 : static __always_inline void queued_spin_unlock(struct qspinlock *lock) 124 : { 125 : /* 126 : * unlock() needs release semantics: 127 : */ 128 : smp_store_release(&lock->locked, 0); 129 : } 130 : #endif 131 : 132 : #ifndef virt_spin_lock 133 : static __always_inline bool virt_spin_lock(struct qspinlock *lock) 134 : { 135 : return false; 136 : } 137 : #endif 138 : 139 : /* 140 : * Remapping spinlock architecture specific functions to the corresponding 141 : * queued spinlock functions. 142 : */ 143 : #define arch_spin_is_locked(l) queued_spin_is_locked(l) 144 : #define arch_spin_is_contended(l) queued_spin_is_contended(l) 145 : #define arch_spin_value_unlocked(l) queued_spin_value_unlocked(l) 146 : #define arch_spin_lock(l) queued_spin_lock(l) 147 : #define arch_spin_trylock(l) queued_spin_trylock(l) 148 : #define arch_spin_unlock(l) queued_spin_unlock(l) 149 : 150 : #endif /* __ASM_GENERIC_QSPINLOCK_H */