blob: 178c94f0aad0ee5bf98483e0b7f06fa5389dac7a [file] [log] [blame]
wdenk507bbe32004-04-18 21:13:41 +00001#ifndef _MICROBLAZE_BITOPS_H
2#define _MICROBLAZE_BITOPS_H
3
4/*
5 * Copyright 1992, Linus Torvalds.
6 */
7
wdenk507bbe32004-04-18 21:13:41 +00008#include <asm/byteorder.h> /* swab32 */
9#include <asm/system.h> /* save_flags */
Fabio Estevame6e7b7c2015-11-05 12:43:29 -020010#include <asm-generic/bitops/fls.h>
11#include <asm-generic/bitops/__fls.h>
12#include <asm-generic/bitops/fls64.h>
13#include <asm-generic/bitops/__ffs.h>
wdenk507bbe32004-04-18 21:13:41 +000014
15#ifdef __KERNEL__
16/*
17 * Function prototypes to keep gcc -Wall happy
18 */
19
20/*
21 * The __ functions are not atomic
22 */
23
Nathan Rossi7cb73732015-11-06 19:25:05 +100024extern void set_bit(int nr, volatile void *addr);
25extern void __set_bit(int nr, volatile void *addr);
wdenk507bbe32004-04-18 21:13:41 +000026
Nathan Rossi7cb73732015-11-06 19:25:05 +100027extern void clear_bit(int nr, volatile void *addr);
wdenk507bbe32004-04-18 21:13:41 +000028#define __clear_bit(nr, addr) clear_bit(nr, addr)
Simon Kagstrom0413cfe2009-09-17 15:15:52 +020029#define PLATFORM__CLEAR_BIT
wdenk507bbe32004-04-18 21:13:41 +000030
Nathan Rossi7cb73732015-11-06 19:25:05 +100031extern void change_bit(int nr, volatile void *addr);
32extern void __change_bit(int nr, volatile void *addr);
33extern int test_and_set_bit(int nr, volatile void *addr);
34extern int __test_and_set_bit(int nr, volatile void *addr);
35extern int test_and_clear_bit(int nr, volatile void *addr);
36extern int __test_and_clear_bit(int nr, volatile void *addr);
37extern int test_and_change_bit(int nr, volatile void *addr);
38extern int __test_and_change_bit(int nr, volatile void *addr);
39extern int __constant_test_bit(int nr, const volatile void *addr);
40extern int __test_bit(int nr, volatile void *addr);
41extern int find_first_zero_bit(void *addr, unsigned size);
42extern int find_next_zero_bit(void *addr, int size, int offset);
wdenk507bbe32004-04-18 21:13:41 +000043
44/*
45 * ffz = Find First Zero in word. Undefined if no zero exists,
46 * so code should check against ~0UL first..
47 */
Nathan Rossi7cb73732015-11-06 19:25:05 +100048extern inline unsigned long ffz(unsigned long word)
wdenk507bbe32004-04-18 21:13:41 +000049{
50 unsigned long result = 0;
51
52 while(word & 1) {
53 result++;
54 word >>= 1;
55 }
56 return result;
57}
58
59
Nathan Rossi7cb73732015-11-06 19:25:05 +100060extern inline void set_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +000061{
62 int * a = (int *) addr;
63 int mask;
64 unsigned long flags;
65
66 a += nr >> 5;
67 mask = 1 << (nr & 0x1f);
68 save_flags_cli(flags);
69 *a |= mask;
70 restore_flags(flags);
71}
72
Nathan Rossi7cb73732015-11-06 19:25:05 +100073extern inline void __set_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +000074{
75 int * a = (int *) addr;
76 int mask;
77
78 a += nr >> 5;
79 mask = 1 << (nr & 0x1f);
80 *a |= mask;
81}
Simon Kagstrom0413cfe2009-09-17 15:15:52 +020082#define PLATFORM__SET_BIT
wdenk507bbe32004-04-18 21:13:41 +000083
84/*
85 * clear_bit() doesn't provide any barrier for the compiler.
86 */
87#define smp_mb__before_clear_bit() barrier()
88#define smp_mb__after_clear_bit() barrier()
89
Nathan Rossi7cb73732015-11-06 19:25:05 +100090extern inline void clear_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +000091{
92 int * a = (int *) addr;
93 int mask;
94 unsigned long flags;
95
96 a += nr >> 5;
97 mask = 1 << (nr & 0x1f);
98 save_flags_cli(flags);
99 *a &= ~mask;
100 restore_flags(flags);
101}
102
Nathan Rossi7cb73732015-11-06 19:25:05 +1000103extern inline void change_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000104{
105 int mask;
106 unsigned long flags;
107 unsigned long *ADDR = (unsigned long *) addr;
108
109 ADDR += nr >> 5;
110 mask = 1 << (nr & 31);
111 save_flags_cli(flags);
112 *ADDR ^= mask;
113 restore_flags(flags);
114}
115
Nathan Rossi7cb73732015-11-06 19:25:05 +1000116extern inline void __change_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000117{
118 int mask;
119 unsigned long *ADDR = (unsigned long *) addr;
120
121 ADDR += nr >> 5;
122 mask = 1 << (nr & 31);
123 *ADDR ^= mask;
124}
125
Nathan Rossi7cb73732015-11-06 19:25:05 +1000126extern inline int test_and_set_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000127{
128 int mask, retval;
129 volatile unsigned int *a = (volatile unsigned int *) addr;
130 unsigned long flags;
131
132 a += nr >> 5;
133 mask = 1 << (nr & 0x1f);
134 save_flags_cli(flags);
135 retval = (mask & *a) != 0;
136 *a |= mask;
137 restore_flags(flags);
138
139 return retval;
140}
141
Nathan Rossi7cb73732015-11-06 19:25:05 +1000142extern inline int __test_and_set_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000143{
144 int mask, retval;
145 volatile unsigned int *a = (volatile unsigned int *) addr;
146
147 a += nr >> 5;
148 mask = 1 << (nr & 0x1f);
149 retval = (mask & *a) != 0;
150 *a |= mask;
151 return retval;
152}
153
Nathan Rossi7cb73732015-11-06 19:25:05 +1000154extern inline int test_and_clear_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000155{
156 int mask, retval;
157 volatile unsigned int *a = (volatile unsigned int *) addr;
158 unsigned long flags;
159
160 a += nr >> 5;
161 mask = 1 << (nr & 0x1f);
162 save_flags_cli(flags);
163 retval = (mask & *a) != 0;
164 *a &= ~mask;
165 restore_flags(flags);
166
167 return retval;
168}
169
Nathan Rossi7cb73732015-11-06 19:25:05 +1000170extern inline int __test_and_clear_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000171{
172 int mask, retval;
173 volatile unsigned int *a = (volatile unsigned int *) addr;
174
175 a += nr >> 5;
176 mask = 1 << (nr & 0x1f);
177 retval = (mask & *a) != 0;
178 *a &= ~mask;
179 return retval;
180}
181
Nathan Rossi7cb73732015-11-06 19:25:05 +1000182extern inline int test_and_change_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000183{
184 int mask, retval;
185 volatile unsigned int *a = (volatile unsigned int *) addr;
186 unsigned long flags;
187
188 a += nr >> 5;
189 mask = 1 << (nr & 0x1f);
190 save_flags_cli(flags);
191 retval = (mask & *a) != 0;
192 *a ^= mask;
193 restore_flags(flags);
194
195 return retval;
196}
197
Nathan Rossi7cb73732015-11-06 19:25:05 +1000198extern inline int __test_and_change_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000199{
200 int mask, retval;
201 volatile unsigned int *a = (volatile unsigned int *) addr;
202
203 a += nr >> 5;
204 mask = 1 << (nr & 0x1f);
205 retval = (mask & *a) != 0;
206 *a ^= mask;
207 return retval;
208}
209
210/*
211 * This routine doesn't need to be atomic.
212 */
Nathan Rossi7cb73732015-11-06 19:25:05 +1000213extern inline int __constant_test_bit(int nr, const volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000214{
215 return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
216}
217
Nathan Rossi7cb73732015-11-06 19:25:05 +1000218extern inline int __test_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000219{
220 int * a = (int *) addr;
221 int mask;
222
223 a += nr >> 5;
224 mask = 1 << (nr & 0x1f);
225 return ((mask & *a) != 0);
226}
227
228#define test_bit(nr,addr) \
229(__builtin_constant_p(nr) ? \
230 __constant_test_bit((nr),(addr)) : \
231 __test_bit((nr),(addr)))
232
233#define find_first_zero_bit(addr, size) \
234 find_next_zero_bit((addr), (size), 0)
235
Nathan Rossi7cb73732015-11-06 19:25:05 +1000236extern inline int find_next_zero_bit(void *addr, int size, int offset)
wdenk507bbe32004-04-18 21:13:41 +0000237{
238 unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
239 unsigned long result = offset & ~31UL;
240 unsigned long tmp;
241
242 if (offset >= size)
243 return size;
244 size -= result;
245 offset &= 31UL;
246 if (offset) {
247 tmp = *(p++);
248 tmp |= ~0UL >> (32-offset);
249 if (size < 32)
250 goto found_first;
251 if (~tmp)
252 goto found_middle;
253 size -= 32;
254 result += 32;
255 }
256 while (size & ~31UL) {
257 if (~(tmp = *(p++)))
258 goto found_middle;
259 result += 32;
260 size -= 32;
261 }
262 if (!size)
263 return result;
264 tmp = *p;
265
266found_first:
267 tmp |= ~0UL >> size;
268found_middle:
269 return result + ffz(tmp);
270}
271
wdenk507bbe32004-04-18 21:13:41 +0000272/*
273 * hweightN: returns the hamming weight (i.e. the number
274 * of bits set) of a N-bit word
275 */
276
277#define hweight32(x) generic_hweight32(x)
278#define hweight16(x) generic_hweight16(x)
279#define hweight8(x) generic_hweight8(x)
280
281
Nathan Rossi7cb73732015-11-06 19:25:05 +1000282extern inline int ext2_set_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000283{
284 int mask, retval;
285 unsigned long flags;
286 volatile unsigned char *ADDR = (unsigned char *) addr;
287
288 ADDR += nr >> 3;
289 mask = 1 << (nr & 0x07);
290 save_flags_cli(flags);
291 retval = (mask & *ADDR) != 0;
292 *ADDR |= mask;
293 restore_flags(flags);
294 return retval;
295}
296
Nathan Rossi7cb73732015-11-06 19:25:05 +1000297extern inline int ext2_clear_bit(int nr, volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000298{
299 int mask, retval;
300 unsigned long flags;
301 volatile unsigned char *ADDR = (unsigned char *) addr;
302
303 ADDR += nr >> 3;
304 mask = 1 << (nr & 0x07);
305 save_flags_cli(flags);
306 retval = (mask & *ADDR) != 0;
307 *ADDR &= ~mask;
308 restore_flags(flags);
309 return retval;
310}
311
Nathan Rossi7cb73732015-11-06 19:25:05 +1000312extern inline int ext2_test_bit(int nr, const volatile void *addr)
wdenk507bbe32004-04-18 21:13:41 +0000313{
314 int mask;
315 const volatile unsigned char *ADDR = (const unsigned char *) addr;
316
317 ADDR += nr >> 3;
318 mask = 1 << (nr & 0x07);
319 return ((mask & *ADDR) != 0);
320}
321
322#define ext2_find_first_zero_bit(addr, size) \
323 ext2_find_next_zero_bit((addr), (size), 0)
324
Michal Simek548ce4b2012-09-26 14:42:38 +0200325static inline unsigned long ext2_find_next_zero_bit(void *addr,
326 unsigned long size, unsigned long offset)
wdenk507bbe32004-04-18 21:13:41 +0000327{
328 unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
329 unsigned long result = offset & ~31UL;
330 unsigned long tmp;
331
332 if (offset >= size)
333 return size;
334 size -= result;
335 offset &= 31UL;
336 if(offset) {
337 /* We hold the little endian value in tmp, but then the
338 * shift is illegal. So we could keep a big endian value
339 * in tmp, like this:
340 *
341 * tmp = __swab32(*(p++));
342 * tmp |= ~0UL >> (32-offset);
343 *
344 * but this would decrease preformance, so we change the
345 * shift:
346 */
347 tmp = *(p++);
348 tmp |= __swab32(~0UL >> (32-offset));
349 if(size < 32)
350 goto found_first;
351 if(~tmp)
352 goto found_middle;
353 size -= 32;
354 result += 32;
355 }
356 while(size & ~31UL) {
357 if(~(tmp = *(p++)))
358 goto found_middle;
359 result += 32;
360 size -= 32;
361 }
362 if(!size)
363 return result;
364 tmp = *p;
365
366found_first:
367 /* tmp is little endian, so we would have to swab the shift,
368 * see above. But then we have to swab tmp below for ffz, so
369 * we might as well do this here.
370 */
371 return result + ffz(__swab32(tmp) | (~0UL << size));
372found_middle:
373 return result + ffz(__swab32(tmp));
374}
375
376/* Bitmap functions for the minix filesystem. */
377#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
378#define minix_set_bit(nr,addr) set_bit(nr,addr)
379#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
380#define minix_test_bit(nr,addr) test_bit(nr,addr)
381#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
382
383/**
384 * hweightN - returns the hamming weight of a N-bit word
385 * @x: the word to weigh
386 *
387 * The Hamming Weight of a number is the total number of bits set in it.
388 */
389
390#define hweight32(x) generic_hweight32(x)
391#define hweight16(x) generic_hweight16(x)
392#define hweight8(x) generic_hweight8(x)
393
394#endif /* __KERNEL__ */
395
396#endif /* _MICROBLAZE_BITOPS_H */