xref: /openbmc/linux/arch/x86/include/asm/sync_bitops.h (revision 12eb4683)
1 #ifndef _ASM_X86_SYNC_BITOPS_H
2 #define _ASM_X86_SYNC_BITOPS_H
3 
4 /*
5  * Copyright 1992, Linus Torvalds.
6  */
7 
8 /*
9  * These have to be done with inline assembly: that way the bit-setting
10  * is guaranteed to be atomic. All bit operations return 0 if the bit
11  * was cleared before the operation and != 0 if it was not.
12  *
13  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
14  */
15 
16 #define ADDR (*(volatile long *)addr)
17 
18 /**
19  * sync_set_bit - Atomically set a bit in memory
20  * @nr: the bit to set
21  * @addr: the address to start counting from
22  *
23  * This function is atomic and may not be reordered.  See __set_bit()
24  * if you do not require the atomic guarantees.
25  *
26  * Note that @nr may be almost arbitrarily large; this function is not
27  * restricted to acting on a single-word quantity.
28  */
29 static inline void sync_set_bit(long nr, volatile unsigned long *addr)
30 {
31 	asm volatile("lock; bts %1,%0"
32 		     : "+m" (ADDR)
33 		     : "Ir" (nr)
34 		     : "memory");
35 }
36 
37 /**
38  * sync_clear_bit - Clears a bit in memory
39  * @nr: Bit to clear
40  * @addr: Address to start counting from
41  *
42  * sync_clear_bit() is atomic and may not be reordered.  However, it does
43  * not contain a memory barrier, so if it is used for locking purposes,
44  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
45  * in order to ensure changes are visible on other processors.
46  */
47 static inline void sync_clear_bit(long nr, volatile unsigned long *addr)
48 {
49 	asm volatile("lock; btr %1,%0"
50 		     : "+m" (ADDR)
51 		     : "Ir" (nr)
52 		     : "memory");
53 }
54 
55 /**
56  * sync_change_bit - Toggle a bit in memory
57  * @nr: Bit to change
58  * @addr: Address to start counting from
59  *
60  * sync_change_bit() is atomic and may not be reordered.
61  * Note that @nr may be almost arbitrarily large; this function is not
62  * restricted to acting on a single-word quantity.
63  */
64 static inline void sync_change_bit(long nr, volatile unsigned long *addr)
65 {
66 	asm volatile("lock; btc %1,%0"
67 		     : "+m" (ADDR)
68 		     : "Ir" (nr)
69 		     : "memory");
70 }
71 
72 /**
73  * sync_test_and_set_bit - Set a bit and return its old value
74  * @nr: Bit to set
75  * @addr: Address to count from
76  *
77  * This operation is atomic and cannot be reordered.
78  * It also implies a memory barrier.
79  */
80 static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr)
81 {
82 	int oldbit;
83 
84 	asm volatile("lock; bts %2,%1\n\tsbbl %0,%0"
85 		     : "=r" (oldbit), "+m" (ADDR)
86 		     : "Ir" (nr) : "memory");
87 	return oldbit;
88 }
89 
90 /**
91  * sync_test_and_clear_bit - Clear a bit and return its old value
92  * @nr: Bit to clear
93  * @addr: Address to count from
94  *
95  * This operation is atomic and cannot be reordered.
96  * It also implies a memory barrier.
97  */
98 static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr)
99 {
100 	int oldbit;
101 
102 	asm volatile("lock; btr %2,%1\n\tsbbl %0,%0"
103 		     : "=r" (oldbit), "+m" (ADDR)
104 		     : "Ir" (nr) : "memory");
105 	return oldbit;
106 }
107 
108 /**
109  * sync_test_and_change_bit - Change a bit and return its old value
110  * @nr: Bit to change
111  * @addr: Address to count from
112  *
113  * This operation is atomic and cannot be reordered.
114  * It also implies a memory barrier.
115  */
116 static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr)
117 {
118 	int oldbit;
119 
120 	asm volatile("lock; btc %2,%1\n\tsbbl %0,%0"
121 		     : "=r" (oldbit), "+m" (ADDR)
122 		     : "Ir" (nr) : "memory");
123 	return oldbit;
124 }
125 
126 #define sync_test_bit(nr, addr) test_bit(nr, addr)
127 
128 #undef ADDR
129 
130 #endif /* _ASM_X86_SYNC_BITOPS_H */
131