xref: /openbmc/linux/arch/s390/lib/find.c (revision f16fe2d3)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MSB0 numbered special bitops handling.
4  *
5  * The bits are numbered:
6  *   |0..............63|64............127|128...........191|192...........255|
7  *
8  * The reason for this bit numbering is the fact that the hardware sets bits
9  * in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap
10  * from the 'wrong end'.
11  */
12 
13 #include <linux/compiler.h>
14 #include <linux/bitops.h>
15 #include <linux/export.h>
16 
17 unsigned long find_first_bit_inv(const unsigned long *addr, unsigned long size)
18 {
19 	const unsigned long *p = addr;
20 	unsigned long result = 0;
21 	unsigned long tmp;
22 
23 	while (size & ~(BITS_PER_LONG - 1)) {
24 		if ((tmp = *(p++)))
25 			goto found;
26 		result += BITS_PER_LONG;
27 		size -= BITS_PER_LONG;
28 	}
29 	if (!size)
30 		return result;
31 	tmp = (*p) & (~0UL << (BITS_PER_LONG - size));
32 	if (!tmp)		/* Are any bits set? */
33 		return result + size;	/* Nope. */
34 found:
35 	return result + (__fls(tmp) ^ (BITS_PER_LONG - 1));
36 }
37 EXPORT_SYMBOL(find_first_bit_inv);
38 
39 unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
40 				unsigned long offset)
41 {
42 	const unsigned long *p = addr + (offset / BITS_PER_LONG);
43 	unsigned long result = offset & ~(BITS_PER_LONG - 1);
44 	unsigned long tmp;
45 
46 	if (offset >= size)
47 		return size;
48 	size -= result;
49 	offset %= BITS_PER_LONG;
50 	if (offset) {
51 		tmp = *(p++);
52 		tmp &= (~0UL >> offset);
53 		if (size < BITS_PER_LONG)
54 			goto found_first;
55 		if (tmp)
56 			goto found_middle;
57 		size -= BITS_PER_LONG;
58 		result += BITS_PER_LONG;
59 	}
60 	while (size & ~(BITS_PER_LONG-1)) {
61 		if ((tmp = *(p++)))
62 			goto found_middle;
63 		result += BITS_PER_LONG;
64 		size -= BITS_PER_LONG;
65 	}
66 	if (!size)
67 		return result;
68 	tmp = *p;
69 found_first:
70 	tmp &= (~0UL << (BITS_PER_LONG - size));
71 	if (!tmp)		/* Are any bits set? */
72 		return result + size;	/* Nope. */
73 found_middle:
74 	return result + (__fls(tmp) ^ (BITS_PER_LONG - 1));
75 }
76 EXPORT_SYMBOL(find_next_bit_inv);
77