Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/lib/find_next_bit.c
10811 views
1
/* find_next_bit.c: fallback find next bit implementation
2
*
3
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version
9
* 2 of the License, or (at your option) any later version.
10
*/
11
12
#include <linux/bitops.h>
13
#include <linux/module.h>
14
#include <asm/types.h>
15
#include <asm/byteorder.h>
16
17
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
18
19
#ifndef find_next_bit
20
/*
21
* Find the next set bit in a memory region.
22
*/
23
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
24
unsigned long offset)
25
{
26
const unsigned long *p = addr + BITOP_WORD(offset);
27
unsigned long result = offset & ~(BITS_PER_LONG-1);
28
unsigned long tmp;
29
30
if (offset >= size)
31
return size;
32
size -= result;
33
offset %= BITS_PER_LONG;
34
if (offset) {
35
tmp = *(p++);
36
tmp &= (~0UL << offset);
37
if (size < BITS_PER_LONG)
38
goto found_first;
39
if (tmp)
40
goto found_middle;
41
size -= BITS_PER_LONG;
42
result += BITS_PER_LONG;
43
}
44
while (size & ~(BITS_PER_LONG-1)) {
45
if ((tmp = *(p++)))
46
goto found_middle;
47
result += BITS_PER_LONG;
48
size -= BITS_PER_LONG;
49
}
50
if (!size)
51
return result;
52
tmp = *p;
53
54
found_first:
55
tmp &= (~0UL >> (BITS_PER_LONG - size));
56
if (tmp == 0UL) /* Are any bits set? */
57
return result + size; /* Nope. */
58
found_middle:
59
return result + __ffs(tmp);
60
}
61
EXPORT_SYMBOL(find_next_bit);
62
#endif
63
64
#ifndef find_next_zero_bit
65
/*
66
* This implementation of find_{first,next}_zero_bit was stolen from
67
* Linus' asm-alpha/bitops.h.
68
*/
69
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
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;
75
76
if (offset >= size)
77
return size;
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;
95
}
96
if (!size)
97
return result;
98
tmp = *p;
99
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);
106
}
107
EXPORT_SYMBOL(find_next_zero_bit);
108
#endif
109
110
#ifndef find_first_bit
111
/*
112
* Find the first set bit in a memory region.
113
*/
114
unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
115
{
116
const unsigned long *p = addr;
117
unsigned long result = 0;
118
unsigned long tmp;
119
120
while (size & ~(BITS_PER_LONG-1)) {
121
if ((tmp = *(p++)))
122
goto found;
123
result += BITS_PER_LONG;
124
size -= BITS_PER_LONG;
125
}
126
if (!size)
127
return result;
128
129
tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
130
if (tmp == 0UL) /* Are any bits set? */
131
return result + size; /* Nope. */
132
found:
133
return result + __ffs(tmp);
134
}
135
EXPORT_SYMBOL(find_first_bit);
136
#endif
137
138
#ifndef find_first_zero_bit
139
/*
140
* Find the first cleared bit in a memory region.
141
*/
142
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
143
{
144
const unsigned long *p = addr;
145
unsigned long result = 0;
146
unsigned long tmp;
147
148
while (size & ~(BITS_PER_LONG-1)) {
149
if (~(tmp = *(p++)))
150
goto found;
151
result += BITS_PER_LONG;
152
size -= BITS_PER_LONG;
153
}
154
if (!size)
155
return result;
156
157
tmp = (*p) | (~0UL << size);
158
if (tmp == ~0UL) /* Are any bits zero? */
159
return result + size; /* Nope. */
160
found:
161
return result + ffz(tmp);
162
}
163
EXPORT_SYMBOL(find_first_zero_bit);
164
#endif
165
166
#ifdef __BIG_ENDIAN
167
168
/* include/linux/byteorder does not support "unsigned long" type */
169
static inline unsigned long ext2_swabp(const unsigned long * x)
170
{
171
#if BITS_PER_LONG == 64
172
return (unsigned long) __swab64p((u64 *) x);
173
#elif BITS_PER_LONG == 32
174
return (unsigned long) __swab32p((u32 *) x);
175
#else
176
#error BITS_PER_LONG not defined
177
#endif
178
}
179
180
/* include/linux/byteorder doesn't support "unsigned long" type */
181
static inline unsigned long ext2_swab(const unsigned long y)
182
{
183
#if BITS_PER_LONG == 64
184
return (unsigned long) __swab64((u64) y);
185
#elif BITS_PER_LONG == 32
186
return (unsigned long) __swab32((u32) y);
187
#else
188
#error BITS_PER_LONG not defined
189
#endif
190
}
191
192
#ifndef find_next_zero_bit_le
193
unsigned long find_next_zero_bit_le(const void *addr, unsigned
194
long size, unsigned long offset)
195
{
196
const unsigned long *p = addr;
197
unsigned long result = offset & ~(BITS_PER_LONG - 1);
198
unsigned long tmp;
199
200
if (offset >= size)
201
return size;
202
p += BITOP_WORD(offset);
203
size -= result;
204
offset &= (BITS_PER_LONG - 1UL);
205
if (offset) {
206
tmp = ext2_swabp(p++);
207
tmp |= (~0UL >> (BITS_PER_LONG - offset));
208
if (size < BITS_PER_LONG)
209
goto found_first;
210
if (~tmp)
211
goto found_middle;
212
size -= BITS_PER_LONG;
213
result += BITS_PER_LONG;
214
}
215
216
while (size & ~(BITS_PER_LONG - 1)) {
217
if (~(tmp = *(p++)))
218
goto found_middle_swap;
219
result += BITS_PER_LONG;
220
size -= BITS_PER_LONG;
221
}
222
if (!size)
223
return result;
224
tmp = ext2_swabp(p);
225
found_first:
226
tmp |= ~0UL << size;
227
if (tmp == ~0UL) /* Are any bits zero? */
228
return result + size; /* Nope. Skip ffz */
229
found_middle:
230
return result + ffz(tmp);
231
232
found_middle_swap:
233
return result + ffz(ext2_swab(tmp));
234
}
235
EXPORT_SYMBOL(find_next_zero_bit_le);
236
#endif
237
238
#ifndef find_next_bit_le
239
unsigned long find_next_bit_le(const void *addr, unsigned
240
long size, unsigned long offset)
241
{
242
const unsigned long *p = addr;
243
unsigned long result = offset & ~(BITS_PER_LONG - 1);
244
unsigned long tmp;
245
246
if (offset >= size)
247
return size;
248
p += BITOP_WORD(offset);
249
size -= result;
250
offset &= (BITS_PER_LONG - 1UL);
251
if (offset) {
252
tmp = ext2_swabp(p++);
253
tmp &= (~0UL << offset);
254
if (size < BITS_PER_LONG)
255
goto found_first;
256
if (tmp)
257
goto found_middle;
258
size -= BITS_PER_LONG;
259
result += BITS_PER_LONG;
260
}
261
262
while (size & ~(BITS_PER_LONG - 1)) {
263
tmp = *(p++);
264
if (tmp)
265
goto found_middle_swap;
266
result += BITS_PER_LONG;
267
size -= BITS_PER_LONG;
268
}
269
if (!size)
270
return result;
271
tmp = ext2_swabp(p);
272
found_first:
273
tmp &= (~0UL >> (BITS_PER_LONG - size));
274
if (tmp == 0UL) /* Are any bits set? */
275
return result + size; /* Nope. */
276
found_middle:
277
return result + __ffs(tmp);
278
279
found_middle_swap:
280
return result + __ffs(ext2_swab(tmp));
281
}
282
EXPORT_SYMBOL(find_next_bit_le);
283
#endif
284
285
#endif /* __BIG_ENDIAN */
286
287