diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/find_next_bit.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c index 9c90853b4472..bda0d71a2514 100644 --- a/lib/find_next_bit.c +++ b/lib/find_next_bit.c | |||
@@ -12,6 +12,7 @@ | |||
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 | #include <asm/types.h> |
15 | #include <asm/byteorder.h> | ||
15 | 16 | ||
16 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | 17 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) |
17 | 18 | ||
@@ -106,3 +107,75 @@ found_middle: | |||
106 | } | 107 | } |
107 | 108 | ||
108 | EXPORT_SYMBOL(find_next_zero_bit); | 109 | EXPORT_SYMBOL(find_next_zero_bit); |
110 | |||
111 | #ifdef __BIG_ENDIAN | ||
112 | |||
113 | /* include/linux/byteorder does not support "unsigned long" type */ | ||
114 | static inline unsigned long ext2_swabp(const unsigned long * x) | ||
115 | { | ||
116 | #if BITS_PER_LONG == 64 | ||
117 | return (unsigned long) __swab64p((u64 *) x); | ||
118 | #elif BITS_PER_LONG == 32 | ||
119 | return (unsigned long) __swab32p((u32 *) x); | ||
120 | #else | ||
121 | #error BITS_PER_LONG not defined | ||
122 | #endif | ||
123 | } | ||
124 | |||
125 | /* include/linux/byteorder doesn't support "unsigned long" type */ | ||
126 | static inline unsigned long ext2_swab(const unsigned long y) | ||
127 | { | ||
128 | #if BITS_PER_LONG == 64 | ||
129 | return (unsigned long) __swab64((u64) y); | ||
130 | #elif BITS_PER_LONG == 32 | ||
131 | return (unsigned long) __swab32((u32) y); | ||
132 | #else | ||
133 | #error BITS_PER_LONG not defined | ||
134 | #endif | ||
135 | } | ||
136 | |||
137 | unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned | ||
138 | long size, unsigned long offset) | ||
139 | { | ||
140 | const unsigned long *p = addr + BITOP_WORD(offset); | ||
141 | unsigned long result = offset & ~(BITS_PER_LONG - 1); | ||
142 | unsigned long tmp; | ||
143 | |||
144 | if (offset >= size) | ||
145 | return size; | ||
146 | size -= result; | ||
147 | offset &= (BITS_PER_LONG - 1UL); | ||
148 | if (offset) { | ||
149 | tmp = ext2_swabp(p++); | ||
150 | tmp |= (~0UL >> (BITS_PER_LONG - offset)); | ||
151 | if (size < BITS_PER_LONG) | ||
152 | goto found_first; | ||
153 | if (~tmp) | ||
154 | goto found_middle; | ||
155 | size -= BITS_PER_LONG; | ||
156 | result += BITS_PER_LONG; | ||
157 | } | ||
158 | |||
159 | while (size & ~(BITS_PER_LONG - 1)) { | ||
160 | if (~(tmp = *(p++))) | ||
161 | goto found_middle_swap; | ||
162 | result += BITS_PER_LONG; | ||
163 | size -= BITS_PER_LONG; | ||
164 | } | ||
165 | if (!size) | ||
166 | return result; | ||
167 | tmp = ext2_swabp(p); | ||
168 | found_first: | ||
169 | tmp |= ~0UL << size; | ||
170 | if (tmp == ~0UL) /* Are any bits zero? */ | ||
171 | return result + size; /* Nope. Skip ffz */ | ||
172 | found_middle: | ||
173 | return result + ffz(tmp); | ||
174 | |||
175 | found_middle_swap: | ||
176 | return result + ffz(ext2_swab(tmp)); | ||
177 | } | ||
178 | |||
179 | EXPORT_SYMBOL(generic_find_next_zero_le_bit); | ||
180 | |||
181 | #endif /* __BIG_ENDIAN */ | ||