Provide atomic and non-atomic APIs for clearing and setting bits, along with "test" versions to return the original value. Don't bother with "change" APIs, as they are highly unlikely to be needed. Opportunistically move the existing definitions to bitops.h so that common code can access the helpers. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- lib/x86/asm/bitops.h | 86 +++++++++++++++++++++++++++++++++++++++++--- lib/x86/processor.h | 12 ------- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/lib/x86/asm/bitops.h b/lib/x86/asm/bitops.h index 54ec9c42..3ece1b67 100644 --- a/lib/x86/asm/bitops.h +++ b/lib/x86/asm/bitops.h @@ -13,12 +13,88 @@ #define HAVE_BUILTIN_FLS 1 -static inline void test_and_set_bit(long nr, unsigned long *addr) +/* + * Macros to generate condition code outputs from inline assembly, + * The output operand must be type "bool". + */ +#ifdef __GCC_ASM_FLAG_OUTPUTS__ +# define CC_SET(c) "\n\t/* output condition code " #c "*/\n" +# define CC_OUT(c) "=@cc" #c +#else +# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n" +# define CC_OUT(c) [_cc_ ## c] "=qm" +#endif + +static inline void __clear_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + + __asm__ __volatile__("btr %1, %0" + : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); +} + +static inline void __set_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + + __asm__ __volatile__("bts %1, %0" + : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); +} + +static inline bool __test_and_clear_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + bool v; + + __asm__ __volatile__("btr %2, %1" CC_SET(c) + : CC_OUT(c) (v), "+m" (*addr) : "Ir" (bit)); + return v; +} + +static inline bool __test_and_set_bit(int bit, void *__addr) { - asm volatile("lock; bts %1,%0" - : "+m" (*addr) - : "Ir" (nr) - : "memory"); + unsigned long *addr = __addr; + bool v; + + __asm__ __volatile__("bts %2, %1" CC_SET(c) + : CC_OUT(c) (v), "+m" (*addr) : "Ir" (bit)); + return v; +} + +static inline void clear_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + + __asm__ __volatile__("lock; btr %1, %0" + : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); +} + +static inline void set_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + + __asm__ __volatile__("lock; bts %1, %0" + : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); +} + +static inline bool test_and_clear_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + bool v; + + __asm__ __volatile__("lock; btr %2, %1" CC_SET(c) + : CC_OUT(c) (v), "+m" (*addr) : "Ir" (bit)); + return v; +} + +static inline bool test_and_set_bit(int bit, void *__addr) +{ + unsigned long *addr = __addr; + bool v; + + __asm__ __volatile__("lock; bts %2, %1" CC_SET(c) + : CC_OUT(c) (v), "+m" (*addr) : "Ir" (bit)); + return v; } #endif diff --git a/lib/x86/processor.h b/lib/x86/processor.h index a0be04c5..5bc9ef89 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -914,18 +914,6 @@ static inline bool is_canonical(u64 addr) return (s64)(addr << shift_amt) >> shift_amt == addr; } -static inline void clear_bit(int bit, u8 *addr) -{ - __asm__ __volatile__("lock; btr %1, %0" - : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); -} - -static inline void set_bit(int bit, u8 *addr) -{ - __asm__ __volatile__("lock; bts %1, %0" - : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); -} - static inline void flush_tlb(void) { ulong cr4; -- 2.50.0.rc0.604.gd4ff7b7c86-goog