Merge branch 'avr32-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemo...
[sfrench/cifs-2.6.git] / include / asm-x86 / sync_bitops.h
1 #ifndef _I386_SYNC_BITOPS_H
2 #define _I386_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(int nr, volatile unsigned long * addr)
30 {
31         __asm__ __volatile__("lock; btsl %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(int nr, volatile unsigned long * addr)
48 {
49         __asm__ __volatile__("lock; btrl %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(int nr, volatile unsigned long * addr)
65 {
66         __asm__ __volatile__("lock; btcl %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(int nr, volatile unsigned long * addr)
81 {
82         int oldbit;
83
84         __asm__ __volatile__("lock; btsl %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(int nr, volatile unsigned long * addr)
99 {
100         int oldbit;
101
102         __asm__ __volatile__("lock; btrl %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(int nr, volatile unsigned long* addr)
117 {
118         int oldbit;
119
120         __asm__ __volatile__("lock; btcl %2,%1\n\tsbbl %0,%0"
121                              :"=r" (oldbit),"+m" (ADDR)
122                              :"Ir" (nr) : "memory");
123         return oldbit;
124 }
125
126 static __always_inline int sync_constant_test_bit(int nr, const volatile unsigned long *addr)
127 {
128         return ((1UL << (nr & 31)) &
129                 (((const volatile unsigned int *)addr)[nr >> 5])) != 0;
130 }
131
132 static inline int sync_var_test_bit(int nr, const volatile unsigned long * addr)
133 {
134         int oldbit;
135
136         __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
137                              :"=r" (oldbit)
138                              :"m" (ADDR),"Ir" (nr));
139         return oldbit;
140 }
141
142 #define sync_test_bit(nr,addr)                  \
143         (__builtin_constant_p(nr) ?             \
144          sync_constant_test_bit((nr),(addr)) :  \
145          sync_var_test_bit((nr),(addr)))
146
147 #undef ADDR
148
149 #endif /* _I386_SYNC_BITOPS_H */