diff options
Diffstat (limited to 'arch/s390/lib/find.c')
| -rw-r--r-- | arch/s390/lib/find.c | 77 | 
1 files changed, 77 insertions, 0 deletions
diff --git a/arch/s390/lib/find.c b/arch/s390/lib/find.c new file mode 100644 index 00000000000..922003c1b90 --- /dev/null +++ b/arch/s390/lib/find.c @@ -0,0 +1,77 @@ +/* + * MSB0 numbered special bitops handling. + * + * On s390x the bits are numbered: + *   |0..............63|64............127|128...........191|192...........255| + * and on s390: + *   |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255| + * + * The reason for this bit numbering is the fact that the hardware sets bits + * in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap + * from the 'wrong end'. + */ + +#include <linux/compiler.h> +#include <linux/bitops.h> +#include <linux/export.h> + +unsigned long find_first_bit_inv(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)		/* Are any bits set? */ +		return result + size;	/* Nope. */ +found: +	return result + (__fls(tmp) ^ (BITS_PER_LONG - 1)); +} +EXPORT_SYMBOL(find_first_bit_inv); + +unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size, +				unsigned long offset) +{ +	const unsigned long *p = addr + (offset / BITS_PER_LONG); +	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)) { +		if ((tmp = *(p++))) +			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)		/* Are any bits set? */ +		return result + size;	/* Nope. */ +found_middle: +	return result + (__fls(tmp) ^ (BITS_PER_LONG - 1)); +} +EXPORT_SYMBOL(find_next_bit_inv);  | 
