diff options
Diffstat (limited to 'lib/find_next_bit.c')
| -rw-r--r-- | lib/find_next_bit.c | 73 | 
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c index 9c90853b447..bda0d71a251 100644 --- a/lib/find_next_bit.c +++ b/lib/find_next_bit.c @@ -12,6 +12,7 @@  #include <linux/bitops.h>  #include <linux/module.h>  #include <asm/types.h> +#include <asm/byteorder.h>  #define BITOP_WORD(nr)		((nr) / BITS_PER_LONG) @@ -106,3 +107,75 @@ found_middle:  }  EXPORT_SYMBOL(find_next_zero_bit); + +#ifdef __BIG_ENDIAN + +/* include/linux/byteorder does not support "unsigned long" type */ +static inline unsigned long ext2_swabp(const unsigned long * x) +{ +#if BITS_PER_LONG == 64 +	return (unsigned long) __swab64p((u64 *) x); +#elif BITS_PER_LONG == 32 +	return (unsigned long) __swab32p((u32 *) x); +#else +#error BITS_PER_LONG not defined +#endif +} + +/* include/linux/byteorder doesn't support "unsigned long" type */ +static inline unsigned long ext2_swab(const unsigned long y) +{ +#if BITS_PER_LONG == 64 +	return (unsigned long) __swab64((u64) y); +#elif BITS_PER_LONG == 32 +	return (unsigned long) __swab32((u32) y); +#else +#error BITS_PER_LONG not defined +#endif +} + +unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned +		long size, unsigned long offset) +{ +	const unsigned long *p = addr + BITOP_WORD(offset); +	unsigned long result = offset & ~(BITS_PER_LONG - 1); +	unsigned long tmp; + +	if (offset >= size) +		return size; +	size -= result; +	offset &= (BITS_PER_LONG - 1UL); +	if (offset) { +		tmp = ext2_swabp(p++); +		tmp |= (~0UL >> (BITS_PER_LONG - 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)) { +		if (~(tmp = *(p++))) +			goto found_middle_swap; +		result += BITS_PER_LONG; +		size -= BITS_PER_LONG; +	} +	if (!size) +		return result; +	tmp = ext2_swabp(p); +found_first: +	tmp |= ~0UL << size; +	if (tmp == ~0UL)	/* Are any bits zero? */ +		return result + size; /* Nope. Skip ffz */ +found_middle: +	return result + ffz(tmp); + +found_middle_swap: +	return result + ffz(ext2_swab(tmp)); +} + +EXPORT_SYMBOL(generic_find_next_zero_le_bit); + +#endif /* __BIG_ENDIAN */  |