diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5639de47ed454350cb24172269f530fbfa96a7e8..1a69b68ff6cc6b1bec389523bb47bf924a776245 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -77,6 +77,9 @@ config GENERIC_BUG def_bool y depends on BUG +config GENERIC_FIND_FIRST_BIT + def_bool X86_32 + config GENERIC_FIND_NEXT_BIT def_bool y diff --git a/include/asm-x86/bitops_32.h b/include/asm-x86/bitops_32.h index 3ed64b21b765d116a563e042b3bd6d1a71f70c81..ba2c0defafa8c7d3ec8f0adb53b508be660334e0 100644 --- a/include/asm-x86/bitops_32.h +++ b/include/asm-x86/bitops_32.h @@ -5,6 +5,7 @@ * Copyright 1992, Linus Torvalds. */ +#ifndef CONFIG_GENERIC_FIND_FIRST_BIT /** * find_first_zero_bit - find the first zero bit in a memory region * @addr: The address to start the search at @@ -59,6 +60,7 @@ static inline unsigned find_first_bit(const unsigned long *addr, unsigned size) } return x; } +#endif #ifdef __KERNEL__ diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 3865f2c93bd8282e02bee4880d382a7448703d16..355d67ba3bdc66de8c190e1eb87180bfedf419f3 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -113,6 +113,40 @@ static inline unsigned fls_long(unsigned long l) } #ifdef __KERNEL__ +#ifdef CONFIG_GENERIC_FIND_FIRST_BIT +extern unsigned long __find_first_bit(const unsigned long *addr, + unsigned long size); + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first set bit. + */ +static __always_inline unsigned long +find_first_bit(const unsigned long *addr, unsigned long size) +{ + return __find_first_bit(addr, size); +} + +extern unsigned long __find_first_zero_bit(const unsigned long *addr, + unsigned long size); + +/** + * find_first_zero_bit - find the first cleared bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first cleared bit. + */ +static __always_inline unsigned long +find_first_zero_bit(const unsigned long *addr, unsigned long size) +{ + return __find_first_zero_bit(addr, size); +} +#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */ + #ifdef CONFIG_GENERIC_FIND_NEXT_BIT extern unsigned long __find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset); diff --git a/lib/Makefile b/lib/Makefile index bf8000fc7d48e771eb560f10fde894c64bffbb63..2d7001b7f5a4d641be0c618a6405d4c9863b41fb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o +lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c index ce94c4c92d10c0ec3720528811a48ac7508bd8fd..d3f5784807b45a00fa2301727951f6fb3e325f35 100644 --- a/lib/find_next_bit.c +++ b/lib/find_next_bit.c @@ -16,6 +16,7 @@ #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) +#ifdef CONFIG_GENERIC_FIND_NEXT_BIT /* * Find the next set bit in a memory region. */ @@ -102,6 +103,63 @@ unsigned long __find_next_zero_bit(const unsigned long *addr, return result + ffz(tmp); } EXPORT_SYMBOL(__find_next_zero_bit); +#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */ + +#ifdef CONFIG_GENERIC_FIND_FIRST_BIT +/* + * Find the first set bit in a memory region. + */ +unsigned long __find_first_bit(const unsigned long *addr, + unsigned long size) +{ + const unsigned long *p = addr; + unsigned long result = 0; + unsigned long tmp; + + while (size & ~(BITS_PER_LONG-1)) { + if ((tmp = *(p++))) + goto found; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + + tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found: + return result + __ffs(tmp); +} +EXPORT_SYMBOL(__find_first_bit); + +/* + * Find the first cleared bit in a memory region. + */ +unsigned long __find_first_zero_bit(const unsigned long *addr, + unsigned long size) +{ + const unsigned long *p = addr; + unsigned long result = 0; + unsigned long tmp; + + while (size & ~(BITS_PER_LONG-1)) { + if (~(tmp = *(p++))) + goto found; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + + tmp = (*p) | (~0UL << size); + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ +found: + return result + ffz(tmp); +} +EXPORT_SYMBOL(__find_first_zero_bit); +#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */ #ifdef __BIG_ENDIAN