diff options
-rw-r--r-- | include/asm-generic/bitops/find.h | 13 | ||||
-rw-r--r-- | lib/find_next_bit.c | 112 |
2 files changed, 94 insertions, 31 deletions
diff --git a/include/asm-generic/bitops/find.h b/include/asm-generic/bitops/find.h new file mode 100644 index 000000000000..72a51e5a12ef --- /dev/null +++ b/include/asm-generic/bitops/find.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef _ASM_GENERIC_BITOPS_FIND_H_ | ||
2 | #define _ASM_GENERIC_BITOPS_FIND_H_ | ||
3 | |||
4 | extern unsigned long find_next_bit(const unsigned long *addr, unsigned long | ||
5 | size, unsigned long offset); | ||
6 | |||
7 | extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned | ||
8 | long size, unsigned long offset); | ||
9 | |||
10 | #define find_first_bit(addr, size) find_next_bit((addr), (size), 0) | ||
11 | #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) | ||
12 | |||
13 | #endif /*_ASM_GENERIC_BITOPS_FIND_H_ */ | ||
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c index c05b4b19cf6c..9c90853b4472 100644 --- a/lib/find_next_bit.c +++ b/lib/find_next_bit.c | |||
@@ -11,48 +11,98 @@ | |||
11 | 11 | ||
12 | #include <linux/bitops.h> | 12 | #include <linux/bitops.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <asm/types.h> | ||
14 | 15 | ||
15 | int find_next_bit(const unsigned long *addr, int size, int offset) | 16 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) |
17 | |||
18 | /** | ||
19 | * find_next_bit - find the next set bit in a memory region | ||
20 | * @addr: The address to base the search on | ||
21 | * @offset: The bitnumber to start searching at | ||
22 | * @size: The maximum size to search | ||
23 | */ | ||
24 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | ||
25 | unsigned long offset) | ||
16 | { | 26 | { |
17 | const unsigned long *base; | 27 | const unsigned long *p = addr + BITOP_WORD(offset); |
18 | const int NBITS = sizeof(*addr) * 8; | 28 | unsigned long result = offset & ~(BITS_PER_LONG-1); |
19 | unsigned long tmp; | 29 | unsigned long tmp; |
20 | 30 | ||
21 | base = addr; | 31 | if (offset >= size) |
32 | return size; | ||
33 | size -= result; | ||
34 | offset %= BITS_PER_LONG; | ||
22 | if (offset) { | 35 | if (offset) { |
23 | int suboffset; | 36 | tmp = *(p++); |
24 | 37 | tmp &= (~0UL << offset); | |
25 | addr += offset / NBITS; | 38 | if (size < BITS_PER_LONG) |
26 | 39 | goto found_first; | |
27 | suboffset = offset % NBITS; | 40 | if (tmp) |
28 | if (suboffset) { | 41 | goto found_middle; |
29 | tmp = *addr; | 42 | size -= BITS_PER_LONG; |
30 | tmp >>= suboffset; | 43 | result += BITS_PER_LONG; |
31 | if (tmp) | 44 | } |
32 | goto finish; | 45 | while (size & ~(BITS_PER_LONG-1)) { |
33 | } | 46 | if ((tmp = *(p++))) |
34 | 47 | goto found_middle; | |
35 | addr++; | 48 | result += BITS_PER_LONG; |
49 | size -= BITS_PER_LONG; | ||
36 | } | 50 | } |
51 | if (!size) | ||
52 | return result; | ||
53 | tmp = *p; | ||
37 | 54 | ||
38 | while ((tmp = *addr) == 0) | 55 | found_first: |
39 | addr++; | 56 | tmp &= (~0UL >> (BITS_PER_LONG - size)); |
57 | if (tmp == 0UL) /* Are any bits set? */ | ||
58 | return result + size; /* Nope. */ | ||
59 | found_middle: | ||
60 | return result + __ffs(tmp); | ||
61 | } | ||
40 | 62 | ||
41 | offset = (addr - base) * NBITS; | 63 | EXPORT_SYMBOL(find_next_bit); |
42 | 64 | ||
43 | finish: | 65 | /* |
44 | /* count the remaining bits without using __ffs() since that takes a 32-bit arg */ | 66 | * This implementation of find_{first,next}_zero_bit was stolen from |
45 | while (!(tmp & 0xff)) { | 67 | * Linus' asm-alpha/bitops.h. |
46 | offset += 8; | 68 | */ |
47 | tmp >>= 8; | 69 | unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, |
48 | } | 70 | unsigned long offset) |
71 | { | ||
72 | const unsigned long *p = addr + BITOP_WORD(offset); | ||
73 | unsigned long result = offset & ~(BITS_PER_LONG-1); | ||
74 | unsigned long tmp; | ||
49 | 75 | ||
50 | while (!(tmp & 1)) { | 76 | if (offset >= size) |
51 | offset++; | 77 | return size; |
52 | tmp >>= 1; | 78 | size -= result; |
79 | offset %= BITS_PER_LONG; | ||
80 | if (offset) { | ||
81 | tmp = *(p++); | ||
82 | tmp |= ~0UL >> (BITS_PER_LONG - offset); | ||
83 | if (size < BITS_PER_LONG) | ||
84 | goto found_first; | ||
85 | if (~tmp) | ||
86 | goto found_middle; | ||
87 | size -= BITS_PER_LONG; | ||
88 | result += BITS_PER_LONG; | ||
89 | } | ||
90 | while (size & ~(BITS_PER_LONG-1)) { | ||
91 | if (~(tmp = *(p++))) | ||
92 | goto found_middle; | ||
93 | result += BITS_PER_LONG; | ||
94 | size -= BITS_PER_LONG; | ||
53 | } | 95 | } |
96 | if (!size) | ||
97 | return result; | ||
98 | tmp = *p; | ||
54 | 99 | ||
55 | return offset; | 100 | found_first: |
101 | tmp |= ~0UL << size; | ||
102 | if (tmp == ~0UL) /* Are any bits zero? */ | ||
103 | return result + size; /* Nope. */ | ||
104 | found_middle: | ||
105 | return result + ffz(tmp); | ||
56 | } | 106 | } |
57 | 107 | ||
58 | EXPORT_SYMBOL(find_next_bit); | 108 | EXPORT_SYMBOL(find_next_zero_bit); |