diff options
author | Tom Rini <trini@konsulko.com> | 2019-11-08 14:05:07 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-11-08 14:05:07 -0500 |
commit | a4b7485e2f311b1319b1b9cd59f5666536e24a28 (patch) | |
tree | 45e234a7fa285e3eb2c6a31d52b1e27cd86f4e92 /include/linux/bitmap.h | |
parent | fb6dc1fd58fc3209f833ddcd155fe1b276e7a335 (diff) | |
parent | e0891bb679200a8cc73c3b3d98ba40c02c31b850 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-usb
- Assorted fixes
Diffstat (limited to 'include/linux/bitmap.h')
-rw-r--r-- | include/linux/bitmap.h | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 4a54ae05091..fbbb67c8b24 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -20,4 +20,65 @@ static inline void bitmap_zero(unsigned long *dst, int nbits) } } +static inline unsigned long +find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + const unsigned long *p = addr + BIT_WORD(offset); + unsigned long result = offset & ~(BITS_PER_LONG - 1); + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset %= BITS_PER_LONG; + if (offset) { + tmp = *(p++); + tmp &= (~0UL << offset); + if (size < BITS_PER_LONG) + goto found_first; + if (tmp) + goto found_middle; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + } + while (size & ~(BITS_PER_LONG - 1)) { + tmp = *(p++); + if ((tmp)) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= (~0UL >> (BITS_PER_LONG - size)); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + +/* + * Find the first set bit in a memory region. + */ +static inline unsigned long find_first_bit(const unsigned long *addr, unsigned long size) +{ + unsigned long idx; + + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { + if (addr[idx]) + return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); + } + + return size; +} + +#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)) + #endif /* __LINUX_BITMAP_H */ |