aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2013-07-16 18:20:14 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-07-16 18:24:04 -0400
commit9b710506a03b01a9fdd83962912bc9d8237b82e8 (patch)
treeffea830cd50ad9c51fff6128e1d2e09eef76e4ec /arch/x86/include
parent00e55a790706223c903ce6a450c18596a7bc9be0 (diff)
x86, bitops: Change bitops to be native operand size
Change the bitops operation to be naturally "long", i.e. 63 bits on the 64-bit kernel. Additional bugs are likely to crop up in the future. We already have bugs which machines with > 16 TiB of memory in a single node, as can happen if memory is interleaved. The x86 bitop operations take a signed index, so using an unsigned type is not an option. Jim Kukunas measured the effect of this patch on kernel size: it adds 2779 bytes to the allyesconfig kernel. Some of that probably could be elided by replacing the inline functions with macros which select the 32-bit type if the index is a 32-bit value, something like: In that case we could also use "Jr" constraints for the 64-bit version. However, this would more than double the amount of code for a relatively small gain. Note that we can't use ilog2() for _BITOPS_LONG_SHIFT, as that causes a recursive header inclusion problem. The change to constant_test_bit() should both generate better code and give correct result for negative bit indicies. As previously written the compiler had to generate extra code to create the proper wrong result for negative values. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Cc: Jim Kukunas <james.t.kukunas@intel.com> Link: http://lkml.kernel.org/n/tip-z61ofiwe90xeyb461o72h8ya@git.kernel.org
Diffstat (limited to 'arch/x86/include')
-rw-r--r--arch/x86/include/asm/bitops.h46
-rw-r--r--arch/x86/include/asm/sync_bitops.h24
2 files changed, 39 insertions, 31 deletions
diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h
index 6dfd0195bb55..41639ce8fd63 100644
--- a/arch/x86/include/asm/bitops.h
+++ b/arch/x86/include/asm/bitops.h
@@ -15,6 +15,14 @@
15#include <linux/compiler.h> 15#include <linux/compiler.h>
16#include <asm/alternative.h> 16#include <asm/alternative.h>
17 17
18#if BITS_PER_LONG == 32
19# define _BITOPS_LONG_SHIFT 5
20#elif BITS_PER_LONG == 64
21# define _BITOPS_LONG_SHIFT 6
22#else
23# error "Unexpected BITS_PER_LONG"
24#endif
25
18#define BIT_64(n) (U64_C(1) << (n)) 26#define BIT_64(n) (U64_C(1) << (n))
19 27
20/* 28/*
@@ -59,7 +67,7 @@
59 * restricted to acting on a single-word quantity. 67 * restricted to acting on a single-word quantity.
60 */ 68 */
61static __always_inline void 69static __always_inline void
62set_bit(unsigned int nr, volatile unsigned long *addr) 70set_bit(long nr, volatile unsigned long *addr)
63{ 71{
64 if (IS_IMMEDIATE(nr)) { 72 if (IS_IMMEDIATE(nr)) {
65 asm volatile(LOCK_PREFIX "orb %1,%0" 73 asm volatile(LOCK_PREFIX "orb %1,%0"
@@ -81,7 +89,7 @@ set_bit(unsigned int nr, volatile unsigned long *addr)
81 * If it's called on the same region of memory simultaneously, the effect 89 * If it's called on the same region of memory simultaneously, the effect
82 * may be that only one operation succeeds. 90 * may be that only one operation succeeds.
83 */ 91 */
84static inline void __set_bit(int nr, volatile unsigned long *addr) 92static inline void __set_bit(long nr, volatile unsigned long *addr)
85{ 93{
86 asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory"); 94 asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
87} 95}
@@ -97,7 +105,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr)
97 * in order to ensure changes are visible on other processors. 105 * in order to ensure changes are visible on other processors.
98 */ 106 */
99static __always_inline void 107static __always_inline void
100clear_bit(int nr, volatile unsigned long *addr) 108clear_bit(long nr, volatile unsigned long *addr)
101{ 109{
102 if (IS_IMMEDIATE(nr)) { 110 if (IS_IMMEDIATE(nr)) {
103 asm volatile(LOCK_PREFIX "andb %1,%0" 111 asm volatile(LOCK_PREFIX "andb %1,%0"
@@ -118,13 +126,13 @@ clear_bit(int nr, volatile unsigned long *addr)
118 * clear_bit() is atomic and implies release semantics before the memory 126 * clear_bit() is atomic and implies release semantics before the memory
119 * operation. It can be used for an unlock. 127 * operation. It can be used for an unlock.
120 */ 128 */
121static inline void clear_bit_unlock(unsigned nr, volatile unsigned long *addr) 129static inline void clear_bit_unlock(long nr, volatile unsigned long *addr)
122{ 130{
123 barrier(); 131 barrier();
124 clear_bit(nr, addr); 132 clear_bit(nr, addr);
125} 133}
126 134
127static inline void __clear_bit(int nr, volatile unsigned long *addr) 135static inline void __clear_bit(long nr, volatile unsigned long *addr)
128{ 136{
129 asm volatile("btr %1,%0" : ADDR : "Ir" (nr)); 137 asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
130} 138}
@@ -141,7 +149,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr)
141 * No memory barrier is required here, because x86 cannot reorder stores past 149 * No memory barrier is required here, because x86 cannot reorder stores past
142 * older loads. Same principle as spin_unlock. 150 * older loads. Same principle as spin_unlock.
143 */ 151 */
144static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr) 152static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
145{ 153{
146 barrier(); 154 barrier();
147 __clear_bit(nr, addr); 155 __clear_bit(nr, addr);
@@ -159,7 +167,7 @@ static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
159 * If it's called on the same region of memory simultaneously, the effect 167 * If it's called on the same region of memory simultaneously, the effect
160 * may be that only one operation succeeds. 168 * may be that only one operation succeeds.
161 */ 169 */
162static inline void __change_bit(int nr, volatile unsigned long *addr) 170static inline void __change_bit(long nr, volatile unsigned long *addr)
163{ 171{
164 asm volatile("btc %1,%0" : ADDR : "Ir" (nr)); 172 asm volatile("btc %1,%0" : ADDR : "Ir" (nr));
165} 173}
@@ -173,7 +181,7 @@ static inline void __change_bit(int nr, volatile unsigned long *addr)
173 * Note that @nr may be almost arbitrarily large; this function is not 181 * Note that @nr may be almost arbitrarily large; this function is not
174 * restricted to acting on a single-word quantity. 182 * restricted to acting on a single-word quantity.
175 */ 183 */
176static inline void change_bit(int nr, volatile unsigned long *addr) 184static inline void change_bit(long nr, volatile unsigned long *addr)
177{ 185{
178 if (IS_IMMEDIATE(nr)) { 186 if (IS_IMMEDIATE(nr)) {
179 asm volatile(LOCK_PREFIX "xorb %1,%0" 187 asm volatile(LOCK_PREFIX "xorb %1,%0"
@@ -194,7 +202,7 @@ static inline void change_bit(int nr, volatile unsigned long *addr)
194 * This operation is atomic and cannot be reordered. 202 * This operation is atomic and cannot be reordered.
195 * It also implies a memory barrier. 203 * It also implies a memory barrier.
196 */ 204 */
197static inline int test_and_set_bit(int nr, volatile unsigned long *addr) 205static inline int test_and_set_bit(long nr, volatile unsigned long *addr)
198{ 206{
199 int oldbit; 207 int oldbit;
200 208
@@ -212,7 +220,7 @@ static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
212 * This is the same as test_and_set_bit on x86. 220 * This is the same as test_and_set_bit on x86.
213 */ 221 */
214static __always_inline int 222static __always_inline int
215test_and_set_bit_lock(int nr, volatile unsigned long *addr) 223test_and_set_bit_lock(long nr, volatile unsigned long *addr)
216{ 224{
217 return test_and_set_bit(nr, addr); 225 return test_and_set_bit(nr, addr);
218} 226}
@@ -226,7 +234,7 @@ test_and_set_bit_lock(int nr, volatile unsigned long *addr)
226 * If two examples of this operation race, one can appear to succeed 234 * If two examples of this operation race, one can appear to succeed
227 * but actually fail. You must protect multiple accesses with a lock. 235 * but actually fail. You must protect multiple accesses with a lock.
228 */ 236 */
229static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) 237static inline int __test_and_set_bit(long nr, volatile unsigned long *addr)
230{ 238{
231 int oldbit; 239 int oldbit;
232 240
@@ -245,7 +253,7 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
245 * This operation is atomic and cannot be reordered. 253 * This operation is atomic and cannot be reordered.
246 * It also implies a memory barrier. 254 * It also implies a memory barrier.
247 */ 255 */
248static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) 256static inline int test_and_clear_bit(long nr, volatile unsigned long *addr)
249{ 257{
250 int oldbit; 258 int oldbit;
251 259
@@ -272,7 +280,7 @@ static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
272 * accessed from a hypervisor on the same CPU if running in a VM: don't change 280 * accessed from a hypervisor on the same CPU if running in a VM: don't change
273 * this without also updating arch/x86/kernel/kvm.c 281 * this without also updating arch/x86/kernel/kvm.c
274 */ 282 */
275static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) 283static inline int __test_and_clear_bit(long nr, volatile unsigned long *addr)
276{ 284{
277 int oldbit; 285 int oldbit;
278 286
@@ -284,7 +292,7 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
284} 292}
285 293
286/* WARNING: non atomic and it can be reordered! */ 294/* WARNING: non atomic and it can be reordered! */
287static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) 295static inline int __test_and_change_bit(long nr, volatile unsigned long *addr)
288{ 296{
289 int oldbit; 297 int oldbit;
290 298
@@ -304,7 +312,7 @@ static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
304 * This operation is atomic and cannot be reordered. 312 * This operation is atomic and cannot be reordered.
305 * It also implies a memory barrier. 313 * It also implies a memory barrier.
306 */ 314 */
307static inline int test_and_change_bit(int nr, volatile unsigned long *addr) 315static inline int test_and_change_bit(long nr, volatile unsigned long *addr)
308{ 316{
309 int oldbit; 317 int oldbit;
310 318
@@ -315,13 +323,13 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
315 return oldbit; 323 return oldbit;
316} 324}
317 325
318static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr) 326static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr)
319{ 327{
320 return ((1UL << (nr % BITS_PER_LONG)) & 328 return ((1UL << (nr & (BITS_PER_LONG-1))) &
321 (addr[nr / BITS_PER_LONG])) != 0; 329 (addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
322} 330}
323 331
324static inline int variable_test_bit(int nr, volatile const unsigned long *addr) 332static inline int variable_test_bit(long nr, volatile const unsigned long *addr)
325{ 333{
326 int oldbit; 334 int oldbit;
327 335
diff --git a/arch/x86/include/asm/sync_bitops.h b/arch/x86/include/asm/sync_bitops.h
index 9d09b4073b60..05af3b31d522 100644
--- a/arch/x86/include/asm/sync_bitops.h
+++ b/arch/x86/include/asm/sync_bitops.h
@@ -26,9 +26,9 @@
26 * Note that @nr may be almost arbitrarily large; this function is not 26 * Note that @nr may be almost arbitrarily large; this function is not
27 * restricted to acting on a single-word quantity. 27 * restricted to acting on a single-word quantity.
28 */ 28 */
29static inline void sync_set_bit(int nr, volatile unsigned long *addr) 29static inline void sync_set_bit(long nr, volatile unsigned long *addr)
30{ 30{
31 asm volatile("lock; btsl %1,%0" 31 asm volatile("lock; bts %1,%0"
32 : "+m" (ADDR) 32 : "+m" (ADDR)
33 : "Ir" (nr) 33 : "Ir" (nr)
34 : "memory"); 34 : "memory");
@@ -44,9 +44,9 @@ static inline void sync_set_bit(int nr, volatile unsigned long *addr)
44 * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() 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. 45 * in order to ensure changes are visible on other processors.
46 */ 46 */
47static inline void sync_clear_bit(int nr, volatile unsigned long *addr) 47static inline void sync_clear_bit(long nr, volatile unsigned long *addr)
48{ 48{
49 asm volatile("lock; btrl %1,%0" 49 asm volatile("lock; btr %1,%0"
50 : "+m" (ADDR) 50 : "+m" (ADDR)
51 : "Ir" (nr) 51 : "Ir" (nr)
52 : "memory"); 52 : "memory");
@@ -61,9 +61,9 @@ static inline void sync_clear_bit(int nr, volatile unsigned long *addr)
61 * Note that @nr may be almost arbitrarily large; this function is not 61 * Note that @nr may be almost arbitrarily large; this function is not
62 * restricted to acting on a single-word quantity. 62 * restricted to acting on a single-word quantity.
63 */ 63 */
64static inline void sync_change_bit(int nr, volatile unsigned long *addr) 64static inline void sync_change_bit(long nr, volatile unsigned long *addr)
65{ 65{
66 asm volatile("lock; btcl %1,%0" 66 asm volatile("lock; btc %1,%0"
67 : "+m" (ADDR) 67 : "+m" (ADDR)
68 : "Ir" (nr) 68 : "Ir" (nr)
69 : "memory"); 69 : "memory");
@@ -77,11 +77,11 @@ static inline void sync_change_bit(int nr, volatile unsigned long *addr)
77 * This operation is atomic and cannot be reordered. 77 * This operation is atomic and cannot be reordered.
78 * It also implies a memory barrier. 78 * It also implies a memory barrier.
79 */ 79 */
80static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr) 80static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr)
81{ 81{
82 int oldbit; 82 int oldbit;
83 83
84 asm volatile("lock; btsl %2,%1\n\tsbbl %0,%0" 84 asm volatile("lock; bts %2,%1\n\tsbbl %0,%0"
85 : "=r" (oldbit), "+m" (ADDR) 85 : "=r" (oldbit), "+m" (ADDR)
86 : "Ir" (nr) : "memory"); 86 : "Ir" (nr) : "memory");
87 return oldbit; 87 return oldbit;
@@ -95,11 +95,11 @@ static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr)
95 * This operation is atomic and cannot be reordered. 95 * This operation is atomic and cannot be reordered.
96 * It also implies a memory barrier. 96 * It also implies a memory barrier.
97 */ 97 */
98static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr) 98static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr)
99{ 99{
100 int oldbit; 100 int oldbit;
101 101
102 asm volatile("lock; btrl %2,%1\n\tsbbl %0,%0" 102 asm volatile("lock; btr %2,%1\n\tsbbl %0,%0"
103 : "=r" (oldbit), "+m" (ADDR) 103 : "=r" (oldbit), "+m" (ADDR)
104 : "Ir" (nr) : "memory"); 104 : "Ir" (nr) : "memory");
105 return oldbit; 105 return oldbit;
@@ -113,11 +113,11 @@ static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr)
113 * This operation is atomic and cannot be reordered. 113 * This operation is atomic and cannot be reordered.
114 * It also implies a memory barrier. 114 * It also implies a memory barrier.
115 */ 115 */
116static inline int sync_test_and_change_bit(int nr, volatile unsigned long *addr) 116static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr)
117{ 117{
118 int oldbit; 118 int oldbit;
119 119
120 asm volatile("lock; btcl %2,%1\n\tsbbl %0,%0" 120 asm volatile("lock; btc %2,%1\n\tsbbl %0,%0"
121 : "=r" (oldbit), "+m" (ADDR) 121 : "=r" (oldbit), "+m" (ADDR)
122 : "Ir" (nr) : "memory"); 122 : "Ir" (nr) : "memory");
123 return oldbit; 123 return oldbit;