diff options
Diffstat (limited to 'include/sbi/sbi_bitops.h')
-rw-r--r-- | include/sbi/sbi_bitops.h | 141 |
1 files changed, 139 insertions, 2 deletions
diff --git a/include/sbi/sbi_bitops.h b/include/sbi/sbi_bitops.h index 10c29f1..c55ced0 100644 --- a/include/sbi/sbi_bitops.h +++ b/include/sbi/sbi_bitops.h @@ -4,7 +4,7 @@ * Copyright (c) 2019 Western Digital Corporation or its affiliates. * * Authors: - * Atish Patra<atish.patra@wdc.com> + * Atish Patra <atish.patra@wdc.com> */ #ifndef __SBI_BITOPS_H__ @@ -25,8 +25,16 @@ #define INSERT_FIELD(val, which, fieldval) \ (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1)))) +#define BITS_TO_LONGS(nbits) (((nbits) + BITS_PER_LONG - 1) / \ + BITS_PER_LONG) + +#define BIT(nr) (1UL << (nr)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BIT_WORD(bit) ((bit) / BITS_PER_LONG) +#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1)) + +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) /** * ffs - Find first bit set @@ -184,4 +192,133 @@ static inline unsigned long __fls(unsigned long word) return num; } +#define for_each_set_bit(bit, addr, size) \ + for ((bit) = find_first_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +/* same as for_each_set_bit() but use bit as value to start with */ +#define for_each_set_bit_from(bit, addr, size) \ + for ((bit) = find_next_bit((addr), (size), (bit)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +#define for_each_clear_bit(bit, addr, size) \ + for ((bit) = find_first_zero_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) + +/* same as for_each_clear_bit() but use bit as value to start with */ +#define for_each_clear_bit_from(bit, addr, size) \ + for ((bit) = find_next_zero_bit((addr), (size), (bit)); \ + (bit) < (size); \ + (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) + +unsigned long find_first_bit(const unsigned long *addr, + unsigned long size); + +unsigned long find_first_zero_bit(const unsigned long *addr, + unsigned long size); + +unsigned long find_last_bit(const unsigned long *addr, + unsigned long size); + +unsigned long find_next_bit(const unsigned long *addr, + unsigned long size, unsigned long offset); + +unsigned long find_next_zero_bit(const unsigned long *addr, + unsigned long size, + unsigned long offset); + +/** + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is non-atomic and may be reordered. + */ +static inline void __set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p |= mask; +} + +/** + * __clear_bit - Clear a bit in memory + * @nr: the bit to clear + * @addr: the address to start counting from + * + * This function is non-atomic and may be reordered. + */ +static inline void __clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p &= ~mask; +} + +/** + * __change_bit - Toggle a bit in memory + * @nr: the bit to change + * @addr: the address to start counting from + * + * This function is non-atomic and may be reordered. + */ +static inline void __change_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p ^= mask; +} + +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + */ +static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old | mask; + return (old & mask) != 0; +} + +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + */ +static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old & ~mask; + return (old & mask) != 0; +} + +/** + * __test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + * + * This operation is non-atomic and can be reordered. + */ +static inline int __test_bit(int nr, const volatile unsigned long *addr) +{ + return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); +} + #endif |