blob: c02d09f37d586c93978a0b20fbe2ecb75fc3ffb2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 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 (dhowells@redhat.com)
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>
David Howells40234402006-01-08 01:01:19 -080013#include <linux/module.h>
Akinobu Mitac7f612c2006-03-26 01:39:11 -080014#include <asm/types.h>
Akinobu Mita930ae742006-03-26 01:39:15 -080015#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Akinobu Mitac7f612c2006-03-26 01:39:11 -080017#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
18
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +020019#ifdef CONFIG_GENERIC_FIND_NEXT_BIT
Akinobu Mita19de85e2011-05-26 16:26:09 -070020#ifndef find_next_bit
Alexander van Heukelum64970b62008-03-11 16:17:19 +010021/*
22 * Find the next set bit in a memory region.
Akinobu Mitac7f612c2006-03-26 01:39:11 -080023 */
Thomas Gleixnerfee4b192008-04-29 12:01:02 +020024unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
25 unsigned long offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026{
Akinobu Mitac7f612c2006-03-26 01:39:11 -080027 const unsigned long *p = addr + BITOP_WORD(offset);
28 unsigned long result = offset & ~(BITS_PER_LONG-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 unsigned long tmp;
30
Akinobu Mitac7f612c2006-03-26 01:39:11 -080031 if (offset >= size)
32 return size;
33 size -= result;
34 offset %= BITS_PER_LONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 if (offset) {
Akinobu Mitac7f612c2006-03-26 01:39:11 -080036 tmp = *(p++);
37 tmp &= (~0UL << offset);
38 if (size < BITS_PER_LONG)
39 goto found_first;
40 if (tmp)
41 goto found_middle;
42 size -= BITS_PER_LONG;
43 result += BITS_PER_LONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 }
Akinobu Mitac7f612c2006-03-26 01:39:11 -080045 while (size & ~(BITS_PER_LONG-1)) {
46 if ((tmp = *(p++)))
47 goto found_middle;
48 result += BITS_PER_LONG;
49 size -= BITS_PER_LONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 }
Akinobu Mitac7f612c2006-03-26 01:39:11 -080051 if (!size)
52 return result;
53 tmp = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Akinobu Mitac7f612c2006-03-26 01:39:11 -080055found_first:
56 tmp &= (~0UL >> (BITS_PER_LONG - size));
57 if (tmp == 0UL) /* Are any bits set? */
58 return result + size; /* Nope. */
59found_middle:
60 return result + __ffs(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061}
Thomas Gleixnerfee4b192008-04-29 12:01:02 +020062EXPORT_SYMBOL(find_next_bit);
Akinobu Mita19de85e2011-05-26 16:26:09 -070063#endif
Akinobu Mitac7f612c2006-03-26 01:39:11 -080064
Akinobu Mita19de85e2011-05-26 16:26:09 -070065#ifndef find_next_zero_bit
Akinobu Mitac7f612c2006-03-26 01:39:11 -080066/*
67 * This implementation of find_{first,next}_zero_bit was stolen from
68 * Linus' asm-alpha/bitops.h.
69 */
Thomas Gleixnerfee4b192008-04-29 12:01:02 +020070unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
71 unsigned long offset)
Akinobu Mitac7f612c2006-03-26 01:39:11 -080072{
73 const unsigned long *p = addr + BITOP_WORD(offset);
74 unsigned long result = offset & ~(BITS_PER_LONG-1);
75 unsigned long tmp;
76
77 if (offset >= size)
78 return size;
79 size -= result;
80 offset %= BITS_PER_LONG;
81 if (offset) {
82 tmp = *(p++);
83 tmp |= ~0UL >> (BITS_PER_LONG - offset);
84 if (size < BITS_PER_LONG)
85 goto found_first;
86 if (~tmp)
87 goto found_middle;
88 size -= BITS_PER_LONG;
89 result += BITS_PER_LONG;
90 }
91 while (size & ~(BITS_PER_LONG-1)) {
92 if (~(tmp = *(p++)))
93 goto found_middle;
94 result += BITS_PER_LONG;
95 size -= BITS_PER_LONG;
96 }
97 if (!size)
98 return result;
99 tmp = *p;
100
101found_first:
102 tmp |= ~0UL << size;
103 if (tmp == ~0UL) /* Are any bits zero? */
104 return result + size; /* Nope. */
105found_middle:
106 return result + ffz(tmp);
107}
Thomas Gleixnerfee4b192008-04-29 12:01:02 +0200108EXPORT_SYMBOL(find_next_zero_bit);
Akinobu Mita19de85e2011-05-26 16:26:09 -0700109#endif
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200110#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */
111
112#ifdef CONFIG_GENERIC_FIND_FIRST_BIT
Akinobu Mita19de85e2011-05-26 16:26:09 -0700113#ifndef find_first_bit
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200114/*
115 * Find the first set bit in a memory region.
116 */
Thomas Gleixnerfee4b192008-04-29 12:01:02 +0200117unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200118{
119 const unsigned long *p = addr;
120 unsigned long result = 0;
121 unsigned long tmp;
122
123 while (size & ~(BITS_PER_LONG-1)) {
124 if ((tmp = *(p++)))
125 goto found;
126 result += BITS_PER_LONG;
127 size -= BITS_PER_LONG;
128 }
129 if (!size)
130 return result;
131
132 tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
133 if (tmp == 0UL) /* Are any bits set? */
134 return result + size; /* Nope. */
135found:
136 return result + __ffs(tmp);
137}
Thomas Gleixnerfee4b192008-04-29 12:01:02 +0200138EXPORT_SYMBOL(find_first_bit);
Akinobu Mita19de85e2011-05-26 16:26:09 -0700139#endif
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200140
Akinobu Mita19de85e2011-05-26 16:26:09 -0700141#ifndef find_first_zero_bit
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200142/*
143 * Find the first cleared bit in a memory region.
144 */
Thomas Gleixnerfee4b192008-04-29 12:01:02 +0200145unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200146{
147 const unsigned long *p = addr;
148 unsigned long result = 0;
149 unsigned long tmp;
150
151 while (size & ~(BITS_PER_LONG-1)) {
152 if (~(tmp = *(p++)))
153 goto found;
154 result += BITS_PER_LONG;
155 size -= BITS_PER_LONG;
156 }
157 if (!size)
158 return result;
159
160 tmp = (*p) | (~0UL << size);
161 if (tmp == ~0UL) /* Are any bits zero? */
162 return result + size; /* Nope. */
163found:
164 return result + ffz(tmp);
165}
Thomas Gleixnerfee4b192008-04-29 12:01:02 +0200166EXPORT_SYMBOL(find_first_zero_bit);
Akinobu Mita19de85e2011-05-26 16:26:09 -0700167#endif
Alexander van Heukelum77b9bd92008-04-01 11:46:19 +0200168#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
Akinobu Mita930ae742006-03-26 01:39:15 -0800169
170#ifdef __BIG_ENDIAN
Akinobu Mita06649962011-03-23 16:41:59 -0700171#ifdef CONFIG_GENERIC_FIND_BIT_LE
Akinobu Mita930ae742006-03-26 01:39:15 -0800172
173/* include/linux/byteorder does not support "unsigned long" type */
174static inline unsigned long ext2_swabp(const unsigned long * x)
175{
176#if BITS_PER_LONG == 64
177 return (unsigned long) __swab64p((u64 *) x);
178#elif BITS_PER_LONG == 32
179 return (unsigned long) __swab32p((u32 *) x);
180#else
181#error BITS_PER_LONG not defined
182#endif
183}
184
185/* include/linux/byteorder doesn't support "unsigned long" type */
186static inline unsigned long ext2_swab(const unsigned long y)
187{
188#if BITS_PER_LONG == 64
189 return (unsigned long) __swab64((u64) y);
190#elif BITS_PER_LONG == 32
191 return (unsigned long) __swab32((u32) y);
192#else
193#error BITS_PER_LONG not defined
194#endif
195}
196
Akinobu Mita19de85e2011-05-26 16:26:09 -0700197#ifndef find_next_zero_bit_le
Akinobu Mitaa56560b2011-03-23 16:41:50 -0700198unsigned long find_next_zero_bit_le(const void *addr, unsigned
Akinobu Mita930ae742006-03-26 01:39:15 -0800199 long size, unsigned long offset)
200{
Akinobu Mitaa56560b2011-03-23 16:41:50 -0700201 const unsigned long *p = addr;
Akinobu Mita930ae742006-03-26 01:39:15 -0800202 unsigned long result = offset & ~(BITS_PER_LONG - 1);
203 unsigned long tmp;
204
205 if (offset >= size)
206 return size;
Akinobu Mitaa56560b2011-03-23 16:41:50 -0700207 p += BITOP_WORD(offset);
Akinobu Mita930ae742006-03-26 01:39:15 -0800208 size -= result;
209 offset &= (BITS_PER_LONG - 1UL);
210 if (offset) {
211 tmp = ext2_swabp(p++);
212 tmp |= (~0UL >> (BITS_PER_LONG - offset));
213 if (size < BITS_PER_LONG)
214 goto found_first;
215 if (~tmp)
216 goto found_middle;
217 size -= BITS_PER_LONG;
218 result += BITS_PER_LONG;
219 }
220
221 while (size & ~(BITS_PER_LONG - 1)) {
222 if (~(tmp = *(p++)))
223 goto found_middle_swap;
224 result += BITS_PER_LONG;
225 size -= BITS_PER_LONG;
226 }
227 if (!size)
228 return result;
229 tmp = ext2_swabp(p);
230found_first:
231 tmp |= ~0UL << size;
232 if (tmp == ~0UL) /* Are any bits zero? */
233 return result + size; /* Nope. Skip ffz */
234found_middle:
235 return result + ffz(tmp);
236
237found_middle_swap:
238 return result + ffz(ext2_swab(tmp));
239}
Akinobu Mitac4945b92011-03-23 16:41:47 -0700240EXPORT_SYMBOL(find_next_zero_bit_le);
Akinobu Mita19de85e2011-05-26 16:26:09 -0700241#endif
Akinobu Mita930ae742006-03-26 01:39:15 -0800242
Akinobu Mita19de85e2011-05-26 16:26:09 -0700243#ifndef find_next_bit_le
Akinobu Mitaa56560b2011-03-23 16:41:50 -0700244unsigned long find_next_bit_le(const void *addr, unsigned
Aneesh Kumar K.Vaa02ad62008-01-28 23:58:27 -0500245 long size, unsigned long offset)
246{
Akinobu Mitaa56560b2011-03-23 16:41:50 -0700247 const unsigned long *p = addr;
Aneesh Kumar K.Vaa02ad62008-01-28 23:58:27 -0500248 unsigned long result = offset & ~(BITS_PER_LONG - 1);
249 unsigned long tmp;
250
251 if (offset >= size)
252 return size;
Akinobu Mitaa56560b2011-03-23 16:41:50 -0700253 p += BITOP_WORD(offset);
Aneesh Kumar K.Vaa02ad62008-01-28 23:58:27 -0500254 size -= result;
255 offset &= (BITS_PER_LONG - 1UL);
256 if (offset) {
257 tmp = ext2_swabp(p++);
258 tmp &= (~0UL << offset);
259 if (size < BITS_PER_LONG)
260 goto found_first;
261 if (tmp)
262 goto found_middle;
263 size -= BITS_PER_LONG;
264 result += BITS_PER_LONG;
265 }
266
267 while (size & ~(BITS_PER_LONG - 1)) {
268 tmp = *(p++);
269 if (tmp)
270 goto found_middle_swap;
271 result += BITS_PER_LONG;
272 size -= BITS_PER_LONG;
273 }
274 if (!size)
275 return result;
276 tmp = ext2_swabp(p);
277found_first:
278 tmp &= (~0UL >> (BITS_PER_LONG - size));
279 if (tmp == 0UL) /* Are any bits set? */
280 return result + size; /* Nope. */
281found_middle:
282 return result + __ffs(tmp);
283
284found_middle_swap:
285 return result + __ffs(ext2_swab(tmp));
286}
Akinobu Mitac4945b92011-03-23 16:41:47 -0700287EXPORT_SYMBOL(find_next_bit_le);
Akinobu Mita19de85e2011-05-26 16:26:09 -0700288#endif
Akinobu Mita06649962011-03-23 16:41:59 -0700289
290#endif /* CONFIG_GENERIC_FIND_BIT_LE */
Akinobu Mita930ae742006-03-26 01:39:15 -0800291#endif /* __BIG_ENDIAN */