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