1 /* $Id: bitops.h,v 1.3 1999/08/20 21:59:08 ralf Exp $
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * Copyright (c) 1994 - 1999 Ralf Baechle (ralf@gnu.org)
8 * Copyright (c) 1999 Silicon Graphics, Inc.
13 #include <linux/types.h>
14 #include <linux/byteorder/swab.h> /* sigh ... */
17 #error "Don't do this, sucker ..."
20 #include <asm/system.h>
21 #include <asm/sgidefs.h>
22 #include <asm/mipsregs.h>
25 * These functions for MIPS ISA > 1 are interrupt and SMP proof and
29 extern __inline__
void
30 set_bit(unsigned long nr
, void *addr
)
32 unsigned long *m
= ((unsigned long *) addr
) + (nr
>> 6);
36 "1:\tlld\t%0, %1\t\t# set_bit\n\t"
40 :"=&r" (temp
), "=m" (*m
)
41 :"ir" (1UL << (nr
& 0x3f)), "m" (*m
));
44 extern __inline__
void
45 clear_bit(unsigned long nr
, void *addr
)
47 unsigned long *m
= ((unsigned long *) addr
) + (nr
>> 6);
51 "1:\tlld\t%0, %1\t\t# clear_bit\n\t"
55 :"=&r" (temp
), "=m" (*m
)
56 :"ir" (~(1UL << (nr
& 0x3f))), "m" (*m
));
59 extern __inline__
void
60 change_bit(unsigned long nr
, void *addr
)
62 unsigned long *m
= ((unsigned long *) addr
) + (nr
>> 6);
66 "1:\tlld\t%0, %1\t\t# change_bit\n\t"
70 :"=&r" (temp
), "=m" (*m
)
71 :"ir" (1UL << (nr
& 0x3f)), "m" (*m
));
74 extern __inline__
unsigned long
75 test_and_set_bit(unsigned long nr
, void *addr
)
77 unsigned long *m
= ((unsigned long *) addr
) + (nr
>> 6);
78 unsigned long temp
, res
;
81 ".set\tnoreorder\t\t# test_and_set_bit\n"
86 " and\t%2, %0, %3\n\t"
88 :"=&r" (temp
), "=m" (*m
), "=&r" (res
)
89 :"r" (1UL << (nr
& 0x3f)), "m" (*m
));
94 extern __inline__
unsigned long
95 test_and_clear_bit(unsigned long nr
, void *addr
)
97 unsigned long *m
= ((unsigned long *) addr
) + (nr
>> 6);
98 unsigned long temp
, res
;
100 __asm__
__volatile__(
101 ".set\tnoreorder\t\t# test_and_clear_bit\n"
102 "1:\tlld\t%0, %1\n\t"
107 " and\t%2, %0, %3\n\t"
109 :"=&r" (temp
), "=m" (*m
), "=&r" (res
)
110 :"r" (1UL << (nr
& 0x3f)), "m" (*m
));
115 extern __inline__
unsigned long
116 test_and_change_bit(unsigned long nr
, void *addr
)
118 unsigned long *m
= ((unsigned long *) addr
) + (nr
>> 6);
119 unsigned long temp
, res
;
121 __asm__
__volatile__(
122 ".set\tnoreorder\t\t# test_and_change_bit\n"
123 "1:\tlld\t%0, %1\n\t"
124 "xor\t%2, %0, %3\n\t"
127 " and\t%2, %0, %3\n\t"
129 :"=&r" (temp
), "=m" (*m
), "=&r" (res
)
130 :"r" (1UL << (nr
& 0x3f)), "m" (*m
));
135 extern __inline__
unsigned long
136 test_bit(int nr
, volatile void * addr
)
138 return 1UL & (((const long *) addr
)[nr
>> 6] >> (nr
& 0x3f));
143 /* Little endian versions. */
145 extern __inline__
int
146 find_first_zero_bit (void *addr
, unsigned size
)
154 __asm__ (".set\tnoreorder\n\t"
156 "1:\tsubu\t$1,%6,%0\n\t"
160 #if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) || \
161 (_MIPS_ISA == _MIPS_ISA_MIPS4) || (_MIPS_ISA == _MIPS_ISA_MIPS5)
171 #error "Fix this for big endian"
172 #endif /* __MIPSEB__ */
174 "1:\tand\t%2,$1,%1\n\t"
185 : "0" ((signed int) 0),
186 "1" ((unsigned int) 0xffffffff),
194 extern __inline__
int
195 find_next_zero_bit (void * addr
, int size
, int offset
)
197 unsigned int *p
= ((unsigned int *) addr
) + (offset
>> 5);
198 int set
= 0, bit
= offset
& 31, res
;
203 * Look for zero in first byte
206 #error "Fix this for big endian byte order"
208 __asm__(".set\tnoreorder\n\t"
210 "1:\tand\t$1,%4,%1\n\t"
224 if (set
< (32 - bit
))
230 * No zero yet, search remaining full bytes for a zero
232 res
= find_first_zero_bit(p
, size
- 32 * (p
- (unsigned int *) addr
));
233 return offset
+ set
+ res
;
236 #endif /* !(__MIPSEB__) */
239 * ffz = Find First Zero in word. Undefined if no zero exists,
240 * so code should check against ~0UL first..
242 extern __inline__
unsigned long ffz(unsigned long word
)
248 if (word
& 0x00000000ffffffffUL
) { k
-= 32; word
<<= 32; }
249 if (word
& 0x0000ffff00000000UL
) { k
-= 16; word
<<= 16; }
250 if (word
& 0x00ff000000000000UL
) { k
-= 8; word
<<= 8; }
251 if (word
& 0x0f00000000000000UL
) { k
-= 4; word
<<= 4; }
252 if (word
& 0x3000000000000000UL
) { k
-= 2; word
<<= 2; }
253 if (word
& 0x4000000000000000UL
) { k
-= 1; }
261 * ffs: find first bit set. This is defined the same way as
262 * the libc and compiler builtin ffs routines, therefore
263 * differs in spirit from the above ffz (man ffs).
266 #define ffs(x) generic_ffs(x)
269 * hweightN: returns the hamming weight (i.e. the number
270 * of bits set) of a N-bit word
273 #define hweight32(x) generic_hweight32(x)
274 #define hweight16(x) generic_hweight16(x)
275 #define hweight8(x) generic_hweight8(x)
277 #endif /* __KERNEL__ */
282 * find_next_zero_bit() finds the first zero bit in a bit string of length
283 * 'size' bits, starting the search at bit 'offset'. This is largely based
284 * on Linus's ALPHA routines, which are pretty portable BTW.
287 extern __inline__
unsigned long
288 find_next_zero_bit(void *addr
, unsigned long size
, unsigned long offset
)
290 unsigned long *p
= ((unsigned long *) addr
) + (offset
>> 6);
291 unsigned long result
= offset
& ~63UL;
300 tmp
|= ~0UL >> (64-offset
);
308 while (size
& ~63UL) {
321 return result
+ ffz(tmp
);
324 #define find_first_zero_bit(addr, size) \
325 find_next_zero_bit((addr), (size), 0)
327 #endif /* (__MIPSEB__) */
331 /* Now for the ext2 filesystem bit operations and helper routines. */
336 ext2_set_bit(int nr
,void * addr
)
338 int mask
, retval
, flags
;
339 unsigned char *ADDR
= (unsigned char *) addr
;
342 mask
= 1 << (nr
& 0x07);
344 retval
= (mask
& *ADDR
) != 0;
346 restore_flags(flags
);
351 ext2_clear_bit(int nr
, void * addr
)
353 int mask
, retval
, flags
;
354 unsigned char *ADDR
= (unsigned char *) addr
;
357 mask
= 1 << (nr
& 0x07);
359 retval
= (mask
& *ADDR
) != 0;
361 restore_flags(flags
);
366 ext2_test_bit(int nr
, const void * addr
)
369 const unsigned char *ADDR
= (const unsigned char *) addr
;
372 mask
= 1 << (nr
& 0x07);
373 return ((mask
& *ADDR
) != 0);
376 #define ext2_find_first_zero_bit(addr, size) \
377 ext2_find_next_zero_bit((addr), (size), 0)
379 extern inline unsigned int
380 ext2_find_next_zero_bit(void *addr
, unsigned long size
, unsigned long offset
)
382 unsigned int *p
= ((unsigned int *) addr
) + (offset
>> 5);
383 unsigned int result
= offset
& ~31UL;
391 /* We hold the little endian value in tmp, but then the
392 * shift is illegal. So we could keep a big endian value
395 * tmp = __swab32(*(p++));
396 * tmp |= ~0UL >> (32-offset);
398 * but this would decrease preformance, so we change the
402 tmp
|= __swab32(~0UL >> (32-offset
));
410 while(size
& ~31UL) {
421 /* tmp is little endian, so we would have to swab the shift,
422 * see above. But then we have to swab tmp below for ffz, so
423 * we might as well do this here.
425 return result
+ ffz(__swab32(tmp
) | (~0UL << size
));
427 return result
+ ffz(__swab32(tmp
));
429 #else /* !(__MIPSEB__) */
431 /* Native ext2 byte ordering, just collapse using defines. */
432 #define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
433 #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
434 #define ext2_test_bit(nr, addr) test_bit((nr), (addr))
435 #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
436 #define ext2_find_next_zero_bit(addr, size, offset) \
437 find_next_zero_bit((addr), (size), (offset))
439 #endif /* !(__MIPSEB__) */
442 * Bitmap functions for the minix filesystem.
443 * FIXME: These assume that Minix uses the native byte/bitorder.
444 * This limits the Minix filesystem's value for data exchange very much.
446 #define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
447 #define minix_set_bit(nr,addr) set_bit(nr,addr)
448 #define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
449 #define minix_test_bit(nr,addr) test_bit(nr,addr)
450 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
452 #endif /* __KERNEL__ */
454 #endif /* _ASM_BITOPS_H */