1 /*
2 * Copyright 1995, Russell King.
3 * Various bits and pieces copyrights include:
4 * Linus Torvalds (test_bit).
5 *
6 * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
7 *
8 * Please note that the code in this file should never be included
9 * from user space. Many of these are not implemented in assembler
10 * since they would be too costly. Also, they require priviledged
11 * instructions (which are not available from user mode) to ensure
12 * that they are atomic.
13 */
14
15 #ifndef __ASM_ARM_BITOPS_H
16 #define __ASM_ARM_BITOPS_H
17
18 #if __LINUX_ARM_ARCH__ < 5
19
20 #include <asm-generic/bitops/__ffs.h>
21 #include <asm-generic/bitops/__fls.h>
22 #include <asm-generic/bitops/fls.h>
23
24 #else
25
26 #define PLATFORM_FFS
27 #define PLATFORM_FLS
28
29 #if !IS_ENABLED(CONFIG_HAS_THUMB2) && CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
30
31 unsigned long __fls(unsigned long word);
32 unsigned long __ffs(unsigned long word);
33 int fls(unsigned int x);
34 int ffs(int x);
35
36 #else
37
38 #include <asm-generic/bitops/builtin-__fls.h>
39 #include <asm-generic/bitops/builtin-__ffs.h>
40 #include <asm-generic/bitops/builtin-fls.h>
41 #include <asm-generic/bitops/builtin-ffs.h>
42
43 #endif
44 #endif
45
46 #include <asm-generic/bitops/fls64.h>
47
48 #ifdef __KERNEL__
49
50 #ifndef __ASSEMBLY__
51 #include <linux/bitops.h>
52 #endif
53 #include <asm/proc-armv/system.h>
54
55 #define smp_mb__before_clear_bit() do { } while (0)
56 #define smp_mb__after_clear_bit() do { } while (0)
57
58 /*
59 * Function prototypes to keep gcc -Wall happy.
60 */
61 extern void set_bit(int nr, volatile void * addr);
62
63 extern void clear_bit(int nr, volatile void * addr);
64
65 extern void change_bit(int nr, volatile void * addr);
66
__change_bit(int nr,volatile void * addr)67 static inline void __change_bit(int nr, volatile void *addr)
68 {
69 unsigned long mask = BIT_MASK(nr);
70 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
71
72 *p ^= mask;
73 }
74
__test_and_set_bit(int nr,volatile void * addr)75 static inline int __test_and_set_bit(int nr, volatile void *addr)
76 {
77 unsigned long mask = BIT_MASK(nr);
78 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
79 unsigned long old = *p;
80
81 *p = old | mask;
82 return (old & mask) != 0;
83 }
84
test_and_set_bit(int nr,volatile void * addr)85 static inline int test_and_set_bit(int nr, volatile void * addr)
86 {
87 unsigned long flags = 0;
88 int out;
89
90 local_irq_save(flags);
91 out = __test_and_set_bit(nr, addr);
92 local_irq_restore(flags);
93
94 return out;
95 }
96
__test_and_clear_bit(int nr,volatile void * addr)97 static inline int __test_and_clear_bit(int nr, volatile void *addr)
98 {
99 unsigned long mask = BIT_MASK(nr);
100 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
101 unsigned long old = *p;
102
103 *p = old & ~mask;
104 return (old & mask) != 0;
105 }
106
test_and_clear_bit(int nr,volatile void * addr)107 static inline int test_and_clear_bit(int nr, volatile void * addr)
108 {
109 unsigned long flags = 0;
110 int out;
111
112 local_irq_save(flags);
113 out = __test_and_clear_bit(nr, addr);
114 local_irq_restore(flags);
115
116 return out;
117 }
118
119 extern int test_and_change_bit(int nr, volatile void * addr);
120
__test_and_change_bit(int nr,volatile void * addr)121 static inline int __test_and_change_bit(int nr, volatile void *addr)
122 {
123 unsigned long mask = BIT_MASK(nr);
124 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
125 unsigned long old = *p;
126
127 *p = old ^ mask;
128 return (old & mask) != 0;
129 }
130
131 /*
132 * This routine doesn't need to be atomic.
133 */
test_bit(int nr,const void * addr)134 static inline int test_bit(int nr, const void * addr)
135 {
136 return ((unsigned char *) addr)[nr >> 3] & (1U << (nr & 7));
137 }
138
__ilog2(unsigned int x)139 static inline int __ilog2(unsigned int x)
140 {
141 return fls(x) - 1;
142 }
143
144 #define ffz(x) __ffs(~(x))
145
find_next_zero_bit(void * addr,int size,int offset)146 static inline int find_next_zero_bit(void *addr, int size, int offset)
147 {
148 unsigned long *p = ((unsigned long *)addr) + (offset / BITS_PER_LONG);
149 unsigned long result = offset & ~(BITS_PER_LONG - 1);
150 unsigned long tmp;
151
152 if (offset >= size)
153 return size;
154 size -= result;
155 offset &= (BITS_PER_LONG - 1);
156 if (offset) {
157 tmp = *(p++);
158 tmp |= ~0UL >> (BITS_PER_LONG - offset);
159 if (size < BITS_PER_LONG)
160 goto found_first;
161 if (~tmp)
162 goto found_middle;
163 size -= BITS_PER_LONG;
164 result += BITS_PER_LONG;
165 }
166 while (size & ~(BITS_PER_LONG - 1)) {
167 tmp = *(p++);
168 if (~tmp)
169 goto found_middle;
170 result += BITS_PER_LONG;
171 size -= BITS_PER_LONG;
172 }
173 if (!size)
174 return result;
175 tmp = *p;
176
177 found_first:
178 tmp |= ~0UL << size;
179 found_middle:
180 return result + ffz(tmp);
181 }
182
183 /*
184 * hweightN: returns the hamming weight (i.e. the number
185 * of bits set) of a N-bit word
186 */
187
188 #define hweight32(x) generic_hweight32(x)
189 #define hweight16(x) generic_hweight16(x)
190 #define hweight8(x) generic_hweight8(x)
191
192 #define find_first_zero_bit(addr, size) \
193 find_next_zero_bit((addr), (size), 0)
194
195 #define ext2_set_bit test_and_set_bit
196 #define ext2_clear_bit test_and_clear_bit
197 #define ext2_test_bit test_bit
198 #define ext2_find_first_zero_bit find_first_zero_bit
199 #define ext2_find_next_zero_bit find_next_zero_bit
200
201 /* Bitmap functions for the minix filesystem. */
202 #define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
203 #define minix_set_bit(nr,addr) set_bit(nr,addr)
204 #define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
205 #define minix_test_bit(nr,addr) test_bit(nr,addr)
206 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
207
208 #endif /* __KERNEL__ */
209
210 #endif /* _ARM_BITOPS_H */
211