7f2b3356e5dc987136893f79729deed4366e8740
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * Copyright 1992, Linus Torvalds.
22 * These have to be done with inline assembly: that way the bit-setting
23 * is guaranteed to be atomic. All bit operations return 0 if the bit
24 * was cleared before the operation and != 0 if it was not.
26 * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
30 #define LOCK_PREFIX "lock ; "
32 #define LOCK_PREFIX ""
36 * Function prototypes to keep gcc -Wall happy
38 extern void set_bit(int nr
, volatile void * addr
);
39 extern void clear_bit(int nr
, volatile void * addr
);
40 extern void change_bit(int nr
, volatile void * addr
);
41 extern int test_and_set_bit(int nr
, volatile void * addr
);
42 extern int test_and_clear_bit(int nr
, volatile void * addr
);
43 extern int test_and_change_bit(int nr
, volatile void * addr
);
44 extern int __constant_test_bit(int nr
, const volatile void * addr
);
45 extern int __test_bit(int nr
, volatile void * addr
);
46 extern int find_first_zero_bit(void * addr
, unsigned size
);
47 extern int find_next_zero_bit (void * addr
, int size
, int offset
);
48 extern unsigned long ffz(unsigned long word
);
51 * Some hacks to defeat gcc over-optimizations..
53 struct __dummy
{ unsigned long a
[100]; };
54 #define ADDR (*(volatile struct __dummy *) addr)
55 #define CONST_ADDR (*(volatile const struct __dummy *) addr)
57 void set_bit(int nr
, volatile void * addr
)
59 __asm__
__volatile__( LOCK_PREFIX
65 void clear_bit(int nr
, volatile void * addr
)
67 __asm__
__volatile__( LOCK_PREFIX
73 void change_bit(int nr
, volatile void * addr
)
75 __asm__
__volatile__( LOCK_PREFIX
81 int test_and_set_bit(int nr
, volatile void * addr
)
85 __asm__
__volatile__( LOCK_PREFIX
86 "btsl %2,%1\n\tsbbl %0,%0"
87 :"=r" (oldbit
),"=m" (ADDR
)
92 int test_and_clear_bit(int nr
, volatile void * addr
)
96 __asm__
__volatile__( LOCK_PREFIX
97 "btrl %2,%1\n\tsbbl %0,%0"
98 :"=r" (oldbit
),"=m" (ADDR
)
103 int test_and_change_bit(int nr
, volatile void * addr
)
107 __asm__
__volatile__( LOCK_PREFIX
108 "btcl %2,%1\n\tsbbl %0,%0"
109 :"=r" (oldbit
),"=m" (ADDR
)
115 * This routine doesn't need to be atomic.
117 int __constant_test_bit(int nr
, const volatile void * addr
)
119 return ((1UL << (nr
& 31)) & (((const volatile unsigned int *) addr
)[nr
>> 5])) != 0;
122 int test_bit(int nr
, volatile void * addr
)
126 __asm__
__volatile__(
127 "btl %2,%1\n\tsbbl %0,%0"
129 :"m" (ADDR
),"Ir" (nr
));
134 #define test_bit(nr,addr) \
135 (__builtin_constant_p(nr) ? \
136 __constant_test_bit((nr),(addr)) : \
137 __test_bit((nr),(addr)))
141 * Find-bit routines..
143 int find_first_zero_bit(void * addr
, unsigned size
)
152 "xorl %%edx,%%edx\n\t"
155 "xorl -4(%%edi),%%eax\n\t"
158 "1:\tsubl %%ebx,%%edi\n\t"
161 :"=d" (res
), "=&c" (d0
), "=&D" (d1
), "=&a" (d2
)
162 :"1" ((size
+ 31) >> 5), "2" (addr
), "b" (addr
));
166 int find_next_zero_bit (void * addr
, int size
, int offset
)
168 unsigned long * p
= ((unsigned long *) addr
) + (offset
>> 5);
169 int set
= 0, bit
= offset
& 31, res
;
173 * Look for zero in first byte
175 __asm__("bsfl %1,%0\n\t"
180 : "r" (~(*p
>> bit
)));
181 if (set
< (32 - bit
))
187 * No zero yet, search remaining full bytes for a zero
189 res
= find_first_zero_bit (p
, size
- 32 * (p
- (unsigned long *) addr
));
190 return (offset
+ set
+ res
);
194 * ffz = Find First Zero in word. Undefined if no zero exists,
195 * so code should check against ~0UL first..
197 unsigned long ffz(unsigned long word
)