]>
Commit | Line | Data |
---|---|---|
8f6f19dd | 1 | /* bit search implementation |
1da177e4 LT |
2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells ([email protected]) | |
5 | * | |
8f6f19dd YN |
6 | * Copyright (C) 2008 IBM Corporation |
7 | * 'find_last_bit' is written by Rusty Russell <[email protected]> | |
8 | * (Inspired by David Howell's find_next_bit implementation) | |
9 | * | |
2c57a0e2 YN |
10 | * Rewritten by Yury Norov <[email protected]> to decrease |
11 | * size and improve performance, 2015. | |
12 | * | |
1da177e4 LT |
13 | * This program is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU General Public License | |
15 | * as published by the Free Software Foundation; either version | |
16 | * 2 of the License, or (at your option) any later version. | |
17 | */ | |
18 | ||
19 | #include <linux/bitops.h> | |
8f6f19dd | 20 | #include <linux/bitmap.h> |
8bc3bcc9 | 21 | #include <linux/export.h> |
2c57a0e2 | 22 | #include <linux/kernel.h> |
1da177e4 | 23 | |
0ade34c3 CC |
24 | #if !defined(find_next_bit) || !defined(find_next_zero_bit) || \ |
25 | !defined(find_next_and_bit) | |
c7f612cd | 26 | |
64970b68 | 27 | /* |
0ade34c3 CC |
28 | * This is a common helper function for find_next_bit, find_next_zero_bit, and |
29 | * find_next_and_bit. The differences are: | |
30 | * - The "invert" argument, which is XORed with each fetched word before | |
31 | * searching it for one bits. | |
32 | * - The optional "addr2", which is anded with "addr1" if present. | |
c7f612cd | 33 | */ |
0ade34c3 CC |
34 | static inline unsigned long _find_next_bit(const unsigned long *addr1, |
35 | const unsigned long *addr2, unsigned long nbits, | |
36 | unsigned long start, unsigned long invert) | |
1da177e4 | 37 | { |
1da177e4 LT |
38 | unsigned long tmp; |
39 | ||
e4afd2e5 | 40 | if (unlikely(start >= nbits)) |
2c57a0e2 YN |
41 | return nbits; |
42 | ||
0ade34c3 CC |
43 | tmp = addr1[start / BITS_PER_LONG]; |
44 | if (addr2) | |
45 | tmp &= addr2[start / BITS_PER_LONG]; | |
46 | tmp ^= invert; | |
2c57a0e2 YN |
47 | |
48 | /* Handle 1st word. */ | |
49 | tmp &= BITMAP_FIRST_WORD_MASK(start); | |
50 | start = round_down(start, BITS_PER_LONG); | |
51 | ||
52 | while (!tmp) { | |
53 | start += BITS_PER_LONG; | |
54 | if (start >= nbits) | |
55 | return nbits; | |
56 | ||
0ade34c3 CC |
57 | tmp = addr1[start / BITS_PER_LONG]; |
58 | if (addr2) | |
59 | tmp &= addr2[start / BITS_PER_LONG]; | |
60 | tmp ^= invert; | |
1da177e4 LT |
61 | } |
62 | ||
2c57a0e2 | 63 | return min(start + __ffs(tmp), nbits); |
c7f612cd | 64 | } |
19de85ef | 65 | #endif |
1da177e4 | 66 | |
2c57a0e2 | 67 | #ifndef find_next_bit |
c7f612cd | 68 | /* |
2c57a0e2 | 69 | * Find the next set bit in a memory region. |
c7f612cd | 70 | */ |
2c57a0e2 YN |
71 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, |
72 | unsigned long offset) | |
73 | { | |
0ade34c3 | 74 | return _find_next_bit(addr, NULL, size, offset, 0UL); |
2c57a0e2 YN |
75 | } |
76 | EXPORT_SYMBOL(find_next_bit); | |
77 | #endif | |
78 | ||
79 | #ifndef find_next_zero_bit | |
fee4b19f TG |
80 | unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, |
81 | unsigned long offset) | |
c7f612cd | 82 | { |
0ade34c3 | 83 | return _find_next_bit(addr, NULL, size, offset, ~0UL); |
1da177e4 | 84 | } |
fee4b19f | 85 | EXPORT_SYMBOL(find_next_zero_bit); |
19de85ef | 86 | #endif |
77b9bd9c | 87 | |
0ade34c3 CC |
88 | #if !defined(find_next_and_bit) |
89 | unsigned long find_next_and_bit(const unsigned long *addr1, | |
90 | const unsigned long *addr2, unsigned long size, | |
91 | unsigned long offset) | |
92 | { | |
93 | return _find_next_bit(addr1, addr2, size, offset, 0UL); | |
94 | } | |
95 | EXPORT_SYMBOL(find_next_and_bit); | |
96 | #endif | |
97 | ||
19de85ef | 98 | #ifndef find_first_bit |
77b9bd9c AH |
99 | /* |
100 | * Find the first set bit in a memory region. | |
101 | */ | |
fee4b19f | 102 | unsigned long find_first_bit(const unsigned long *addr, unsigned long size) |
77b9bd9c | 103 | { |
2c57a0e2 | 104 | unsigned long idx; |
77b9bd9c | 105 | |
2c57a0e2 YN |
106 | for (idx = 0; idx * BITS_PER_LONG < size; idx++) { |
107 | if (addr[idx]) | |
108 | return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); | |
77b9bd9c | 109 | } |
77b9bd9c | 110 | |
2c57a0e2 | 111 | return size; |
77b9bd9c | 112 | } |
fee4b19f | 113 | EXPORT_SYMBOL(find_first_bit); |
19de85ef | 114 | #endif |
77b9bd9c | 115 | |
19de85ef | 116 | #ifndef find_first_zero_bit |
77b9bd9c AH |
117 | /* |
118 | * Find the first cleared bit in a memory region. | |
119 | */ | |
fee4b19f | 120 | unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) |
77b9bd9c | 121 | { |
2c57a0e2 | 122 | unsigned long idx; |
77b9bd9c | 123 | |
2c57a0e2 YN |
124 | for (idx = 0; idx * BITS_PER_LONG < size; idx++) { |
125 | if (addr[idx] != ~0UL) | |
126 | return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); | |
77b9bd9c | 127 | } |
77b9bd9c | 128 | |
2c57a0e2 | 129 | return size; |
77b9bd9c | 130 | } |
fee4b19f | 131 | EXPORT_SYMBOL(find_first_zero_bit); |
19de85ef | 132 | #endif |
930ae745 | 133 | |
8f6f19dd YN |
134 | #ifndef find_last_bit |
135 | unsigned long find_last_bit(const unsigned long *addr, unsigned long size) | |
136 | { | |
137 | if (size) { | |
138 | unsigned long val = BITMAP_LAST_WORD_MASK(size); | |
139 | unsigned long idx = (size-1) / BITS_PER_LONG; | |
140 | ||
141 | do { | |
142 | val &= addr[idx]; | |
143 | if (val) | |
144 | return idx * BITS_PER_LONG + __fls(val); | |
145 | ||
146 | val = ~0ul; | |
147 | } while (idx--); | |
148 | } | |
149 | return size; | |
150 | } | |
151 | EXPORT_SYMBOL(find_last_bit); | |
152 | #endif | |
153 | ||
930ae745 AM |
154 | #ifdef __BIG_ENDIAN |
155 | ||
156 | /* include/linux/byteorder does not support "unsigned long" type */ | |
930ae745 AM |
157 | static inline unsigned long ext2_swab(const unsigned long y) |
158 | { | |
159 | #if BITS_PER_LONG == 64 | |
160 | return (unsigned long) __swab64((u64) y); | |
161 | #elif BITS_PER_LONG == 32 | |
162 | return (unsigned long) __swab32((u32) y); | |
163 | #else | |
164 | #error BITS_PER_LONG not defined | |
165 | #endif | |
166 | } | |
167 | ||
2c57a0e2 | 168 | #if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) |
0ade34c3 CC |
169 | static inline unsigned long _find_next_bit_le(const unsigned long *addr1, |
170 | const unsigned long *addr2, unsigned long nbits, | |
171 | unsigned long start, unsigned long invert) | |
930ae745 | 172 | { |
930ae745 AM |
173 | unsigned long tmp; |
174 | ||
e4afd2e5 | 175 | if (unlikely(start >= nbits)) |
2c57a0e2 YN |
176 | return nbits; |
177 | ||
0ade34c3 CC |
178 | tmp = addr1[start / BITS_PER_LONG]; |
179 | if (addr2) | |
180 | tmp &= addr2[start / BITS_PER_LONG]; | |
181 | tmp ^= invert; | |
2c57a0e2 YN |
182 | |
183 | /* Handle 1st word. */ | |
184 | tmp &= ext2_swab(BITMAP_FIRST_WORD_MASK(start)); | |
185 | start = round_down(start, BITS_PER_LONG); | |
930ae745 | 186 | |
2c57a0e2 YN |
187 | while (!tmp) { |
188 | start += BITS_PER_LONG; | |
189 | if (start >= nbits) | |
190 | return nbits; | |
191 | ||
0ade34c3 CC |
192 | tmp = addr1[start / BITS_PER_LONG]; |
193 | if (addr2) | |
194 | tmp &= addr2[start / BITS_PER_LONG]; | |
195 | tmp ^= invert; | |
930ae745 | 196 | } |
930ae745 | 197 | |
2c57a0e2 YN |
198 | return min(start + __ffs(ext2_swab(tmp)), nbits); |
199 | } | |
200 | #endif | |
201 | ||
202 | #ifndef find_next_zero_bit_le | |
203 | unsigned long find_next_zero_bit_le(const void *addr, unsigned | |
204 | long size, unsigned long offset) | |
205 | { | |
0ade34c3 | 206 | return _find_next_bit_le(addr, NULL, size, offset, ~0UL); |
930ae745 | 207 | } |
c4945b9e | 208 | EXPORT_SYMBOL(find_next_zero_bit_le); |
19de85ef | 209 | #endif |
930ae745 | 210 | |
19de85ef | 211 | #ifndef find_next_bit_le |
a56560b3 | 212 | unsigned long find_next_bit_le(const void *addr, unsigned |
aa02ad67 AK |
213 | long size, unsigned long offset) |
214 | { | |
0ade34c3 | 215 | return _find_next_bit_le(addr, NULL, size, offset, 0UL); |
aa02ad67 | 216 | } |
c4945b9e | 217 | EXPORT_SYMBOL(find_next_bit_le); |
19de85ef | 218 | #endif |
0664996b | 219 | |
930ae745 | 220 | #endif /* __BIG_ENDIAN */ |