diff options
Diffstat (limited to 'arch/arm/include/asm/bitops.h')
| -rw-r--r-- | arch/arm/include/asm/bitops.h | 181 |
1 files changed, 93 insertions, 88 deletions
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index 338ff19ae44..56380995f4c 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -24,10 +24,8 @@ #endif #include <linux/compiler.h> -#include <asm/system.h> - -#define smp_mb__before_clear_bit() mb() -#define smp_mb__after_clear_bit() mb() +#include <linux/irqflags.h> +#include <asm/barrier.h> /* * These functions are the basis of our bit ops. @@ -149,14 +147,18 @@ ____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p) */ /* + * Native endian assembly bitops. nr = 0 -> word 0 bit 0. + */ +extern void _set_bit(int nr, volatile unsigned long * p); +extern void _clear_bit(int nr, volatile unsigned long * p); +extern void _change_bit(int nr, volatile unsigned long * p); +extern int _test_and_set_bit(int nr, volatile unsigned long * p); +extern int _test_and_clear_bit(int nr, volatile unsigned long * p); +extern int _test_and_change_bit(int nr, volatile unsigned long * p); + +/* * Little endian assembly bitops. nr = 0 -> byte 0 bit 0. */ -extern void _set_bit_le(int nr, volatile unsigned long * p); -extern void _clear_bit_le(int nr, volatile unsigned long * p); -extern void _change_bit_le(int nr, volatile unsigned long * p); -extern int _test_and_set_bit_le(int nr, volatile unsigned long * p); -extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p); -extern int _test_and_change_bit_le(int nr, volatile unsigned long * p); extern int _find_first_zero_bit_le(const void * p, unsigned size); extern int _find_next_zero_bit_le(const void * p, int size, int offset); extern int _find_first_bit_le(const unsigned long *p, unsigned size); @@ -165,12 +167,6 @@ extern int _find_next_bit_le(const unsigned long *p, int size, int offset); /* * Big endian assembly bitops. nr = 0 -> byte 3 bit 0. */ -extern void _set_bit_be(int nr, volatile unsigned long * p); -extern void _clear_bit_be(int nr, volatile unsigned long * p); -extern void _change_bit_be(int nr, volatile unsigned long * p); -extern int _test_and_set_bit_be(int nr, volatile unsigned long * p); -extern int _test_and_clear_bit_be(int nr, volatile unsigned long * p); -extern int _test_and_change_bit_be(int nr, volatile unsigned long * p); extern int _find_first_zero_bit_be(const void * p, unsigned size); extern int _find_next_zero_bit_be(const void * p, int size, int offset); extern int _find_first_bit_be(const unsigned long *p, unsigned size); @@ -180,58 +176,40 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset); /* * The __* form of bitops are non-atomic and may be reordered. */ -#define ATOMIC_BITOP_LE(name,nr,p) \ - (__builtin_constant_p(nr) ? \ - ____atomic_##name(nr, p) : \ - _##name##_le(nr,p)) - -#define ATOMIC_BITOP_BE(name,nr,p) \ - (__builtin_constant_p(nr) ? \ - ____atomic_##name(nr, p) : \ - _##name##_be(nr,p)) +#define ATOMIC_BITOP(name,nr,p) \ + (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p)) #else -#define ATOMIC_BITOP_LE(name,nr,p) _##name##_le(nr,p) -#define ATOMIC_BITOP_BE(name,nr,p) _##name##_be(nr,p) +#define ATOMIC_BITOP(name,nr,p) _##name(nr,p) #endif -#define NONATOMIC_BITOP(name,nr,p) \ - (____nonatomic_##name(nr, p)) +/* + * Native endian atomic definitions. + */ +#define set_bit(nr,p) ATOMIC_BITOP(set_bit,nr,p) +#define clear_bit(nr,p) ATOMIC_BITOP(clear_bit,nr,p) +#define change_bit(nr,p) ATOMIC_BITOP(change_bit,nr,p) +#define test_and_set_bit(nr,p) ATOMIC_BITOP(test_and_set_bit,nr,p) +#define test_and_clear_bit(nr,p) ATOMIC_BITOP(test_and_clear_bit,nr,p) +#define test_and_change_bit(nr,p) ATOMIC_BITOP(test_and_change_bit,nr,p) #ifndef __ARMEB__ /* * These are the little endian, atomic definitions. */ -#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p) -#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p) -#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p) -#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p) -#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p) -#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p) #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off) -#define WORD_BITOFF_TO_LE(x) ((x)) - #else - /* * These are the big endian, atomic definitions. */ -#define set_bit(nr,p) ATOMIC_BITOP_BE(set_bit,nr,p) -#define clear_bit(nr,p) ATOMIC_BITOP_BE(clear_bit,nr,p) -#define change_bit(nr,p) ATOMIC_BITOP_BE(change_bit,nr,p) -#define test_and_set_bit(nr,p) ATOMIC_BITOP_BE(test_and_set_bit,nr,p) -#define test_and_clear_bit(nr,p) ATOMIC_BITOP_BE(test_and_clear_bit,nr,p) -#define test_and_change_bit(nr,p) ATOMIC_BITOP_BE(test_and_change_bit,nr,p) #define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_be(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_be(p,sz,off) -#define WORD_BITOFF_TO_LE(x) ((x) ^ 0x18) - #endif #if __LINUX_ARM_ARCH__ < 5 @@ -274,25 +252,59 @@ static inline int constant_fls(int x) } /* - * On ARMv5 and above those functions can be implemented around - * the clz instruction for much better code efficiency. + * On ARMv5 and above those functions can be implemented around the + * clz instruction for much better code efficiency. __clz returns + * the number of leading zeros, zero input will return 32, and + * 0x80000000 will return 0. */ +static inline unsigned int __clz(unsigned int x) +{ + unsigned int ret; + asm("clz\t%0, %1" : "=r" (ret) : "r" (x)); + + return ret; +} + +/* + * fls() returns zero if the input is zero, otherwise returns the bit + * position of the last set bit, where the LSB is 1 and MSB is 32. + */ static inline int fls(int x) { - int ret; - if (__builtin_constant_p(x)) return constant_fls(x); - asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc"); - ret = 32 - ret; - return ret; + return 32 - __clz(x); +} + +/* + * __fls() returns the bit position of the last bit set, where the + * LSB is 0 and MSB is 31. Zero input is undefined. + */ +static inline unsigned long __fls(unsigned long x) +{ + return fls(x) - 1; +} + +/* + * ffs() returns zero if the input was zero, otherwise returns the bit + * position of the first set bit, where the LSB is 1 and MSB is 32. + */ +static inline int ffs(int x) +{ + return fls(x & -x); +} + +/* + * __ffs() returns the bit position of the first bit set, where the + * LSB is 0 and MSB is 31. Zero input is undefined. + */ +static inline unsigned long __ffs(unsigned long x) +{ + return ffs(x) - 1; } -#define __fls(x) (fls(x) - 1) -#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) -#define __ffs(x) (ffs(x) - 1) #define ffz(x) __ffs( ~(x) ) #endif @@ -303,41 +315,34 @@ static inline int fls(int x) #include <asm-generic/bitops/hweight.h> #include <asm-generic/bitops/lock.h> -/* - * Ext2 is defined to use little-endian byte ordering. - * These do not need to be atomic. - */ -#define ext2_set_bit(nr,p) \ - __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define ext2_set_bit_atomic(lock,nr,p) \ - test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define ext2_clear_bit(nr,p) \ - __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define ext2_clear_bit_atomic(lock,nr,p) \ - test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define ext2_test_bit(nr,p) \ - test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define ext2_find_first_zero_bit(p,sz) \ - _find_first_zero_bit_le(p,sz) -#define ext2_find_next_zero_bit(p,sz,off) \ - _find_next_zero_bit_le(p,sz,off) -#define ext2_find_next_bit(p, sz, off) \ - _find_next_bit_le(p, sz, off) +#ifdef __ARMEB__ + +static inline int find_first_zero_bit_le(const void *p, unsigned size) +{ + return _find_first_zero_bit_le(p, size); +} +#define find_first_zero_bit_le find_first_zero_bit_le + +static inline int find_next_zero_bit_le(const void *p, int size, int offset) +{ + return _find_next_zero_bit_le(p, size, offset); +} +#define find_next_zero_bit_le find_next_zero_bit_le + +static inline int find_next_bit_le(const void *p, int size, int offset) +{ + return _find_next_bit_le(p, size, offset); +} +#define find_next_bit_le find_next_bit_le + +#endif + +#include <asm-generic/bitops/le.h> /* - * Minix is defined to use little-endian byte ordering. - * These do not need to be atomic. + * Ext2 is defined to use little-endian byte ordering. */ -#define minix_set_bit(nr,p) \ - __set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define minix_test_bit(nr,p) \ - test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define minix_test_and_set_bit(nr,p) \ - __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define minix_test_and_clear_bit(nr,p) \ - __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) -#define minix_find_first_zero_bit(p,sz) \ - _find_first_zero_bit_le(p,sz) +#include <asm-generic/bitops/ext2-atomic-setbit.h> #endif /* __KERNEL__ */ |
