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