Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */ 2 : : #ifndef __LINUX_BIT_SPINLOCK_H 3 : : #define __LINUX_BIT_SPINLOCK_H 4 : : 5 : : #include <linux/kernel.h> 6 : : #include <linux/preempt.h> 7 : : #include <linux/atomic.h> 8 : : #include <linux/bug.h> 9 : : 10 : : /* 11 : : * bit-based spin_lock() 12 : : * 13 : : * Don't use this unless you really need to: spin_lock() and spin_unlock() 14 : : * are significantly faster. 15 : : */ 16 : 1015738 : static inline void bit_spin_lock(int bitnum, unsigned long *addr) 17 : : { 18 : : /* 19 : : * Assuming the lock is uncontended, this never enters 20 : : * the body of the outer loop. If it is contended, then 21 : : * within the inner loop a non-atomic test is used to 22 : : * busywait with less bus contention for a good time to 23 : : * attempt to acquire the lock bit. 24 : : */ 25 : 1015738 : preempt_disable(); 26 : : #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) 27 [ - + ]: 1015738 : while (unlikely(test_and_set_bit_lock(bitnum, addr))) { 28 : 0 : preempt_enable(); 29 : 0 : do { 30 : 0 : cpu_relax(); 31 [ # # # # ]: 0 : } while (test_bit(bitnum, addr)); 32 : 0 : preempt_disable(); 33 : : } 34 : : #endif 35 : 1015738 : __acquire(bitlock); 36 : 1015738 : } 37 : : 38 : : /* 39 : : * Return true if it was acquired 40 : : */ 41 : : static inline int bit_spin_trylock(int bitnum, unsigned long *addr) 42 : : { 43 : : preempt_disable(); 44 : : #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) 45 : : if (unlikely(test_and_set_bit_lock(bitnum, addr))) { 46 : : preempt_enable(); 47 : : return 0; 48 : : } 49 : : #endif 50 : : __acquire(bitlock); 51 : : return 1; 52 : : } 53 : : 54 : : /* 55 : : * bit-based spin_unlock() 56 : : */ 57 : 17760 : static inline void bit_spin_unlock(int bitnum, unsigned long *addr) 58 : : { 59 : : #ifdef CONFIG_DEBUG_SPINLOCK 60 : : BUG_ON(!test_bit(bitnum, addr)); 61 : : #endif 62 : : #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) 63 : 17760 : clear_bit_unlock(bitnum, addr); 64 : : #endif 65 : 11230 : preempt_enable(); 66 [ - + ]: 11730 : __release(bitlock); 67 : : } 68 : : 69 : : /* 70 : : * bit-based spin_unlock() 71 : : * non-atomic version, which can be used eg. if the bit lock itself is 72 : : * protecting the rest of the flags in the word. 73 : : */ 74 : 996031 : static inline void __bit_spin_unlock(int bitnum, unsigned long *addr) 75 : : { 76 : : #ifdef CONFIG_DEBUG_SPINLOCK 77 : : BUG_ON(!test_bit(bitnum, addr)); 78 : : #endif 79 : : #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) 80 : 996031 : __clear_bit_unlock(bitnum, addr); 81 : : #endif 82 : 687139 : preempt_enable(); 83 [ # # ]: 308929 : __release(bitlock); 84 : : } 85 : : 86 : : /* 87 : : * Return true if the lock is held. 88 : : */ 89 : : static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) 90 : : { 91 : : #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) 92 : : return test_bit(bitnum, addr); 93 : : #elif defined CONFIG_PREEMPT_COUNT 94 : : return preempt_count(); 95 : : #else 96 : : return 1; 97 : : #endif 98 : : } 99 : : 100 : : #endif /* __LINUX_BIT_SPINLOCK_H */ 101 : :