1 #ifndef _PARISC_BITOPS_H
2 #define _PARISC_BITOPS_H
3 
4 #include <linux/spinlock.h>
5 #include <asm/system.h>
6 #include <asm/byteorder.h>
7 #include <asm/atomic.h>
8 
9 /*
10  * HP-PARISC specific bit operations
11  * for a detailed description of the functions please refer
12  * to include/asm-i386/bitops.h or kerneldoc
13  */
14 
15 #ifdef __LP64__
16 #   define SHIFT_PER_LONG 6
17 #ifndef BITS_PER_LONG
18 #   define BITS_PER_LONG 64
19 #endif
20 #else
21 #   define SHIFT_PER_LONG 5
22 #ifndef BITS_PER_LONG
23 #   define BITS_PER_LONG 32
24 #endif
25 #endif
26 
27 #define CHOP_SHIFTCOUNT(x) ((x) & (BITS_PER_LONG - 1))
28 
29 
30 #define smp_mb__before_clear_bit()      smp_mb()
31 #define smp_mb__after_clear_bit()       smp_mb()
32 
set_bit(int nr,void * address)33 static __inline__ void set_bit(int nr, void * address)
34 {
35 	unsigned long mask;
36 	unsigned long *addr = (unsigned long *) address;
37 	unsigned long flags;
38 
39 	addr += (nr >> SHIFT_PER_LONG);
40 	mask = 1L << CHOP_SHIFTCOUNT(nr);
41 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
42 	*addr |= mask;
43 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
44 }
45 
__set_bit(int nr,void * address)46 static __inline__ void __set_bit(int nr, void * address)
47 {
48 	unsigned long mask;
49 	unsigned long *addr = (unsigned long *) address;
50 
51 	addr += (nr >> SHIFT_PER_LONG);
52 	mask = 1L << CHOP_SHIFTCOUNT(nr);
53 	*addr |= mask;
54 }
55 
clear_bit(int nr,void * address)56 static __inline__ void clear_bit(int nr, void * address)
57 {
58 	unsigned long mask;
59 	unsigned long *addr = (unsigned long *) address;
60 	unsigned long flags;
61 
62 	addr += (nr >> SHIFT_PER_LONG);
63 	mask = 1L << CHOP_SHIFTCOUNT(nr);
64 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
65 	*addr &= ~mask;
66 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
67 }
68 
change_bit(int nr,void * address)69 static __inline__ void change_bit(int nr, void * address)
70 {
71 	unsigned long mask;
72 	unsigned long *addr = (unsigned long *) address;
73 	unsigned long flags;
74 
75 	addr += (nr >> SHIFT_PER_LONG);
76 	mask = 1L << CHOP_SHIFTCOUNT(nr);
77 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
78 	*addr ^= mask;
79 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
80 }
81 
__change_bit(int nr,void * address)82 static __inline__ void __change_bit(int nr, void * address)
83 {
84 	unsigned long mask;
85 	unsigned long *addr = (unsigned long *) address;
86 
87 	addr += (nr >> SHIFT_PER_LONG);
88 	mask = 1L << CHOP_SHIFTCOUNT(nr);
89 	*addr ^= mask;
90 }
91 
test_and_set_bit(int nr,void * address)92 static __inline__ int test_and_set_bit(int nr, void * address)
93 {
94 	unsigned long mask;
95 	unsigned long *addr = (unsigned long *) address;
96 	int oldbit;
97 	unsigned long flags;
98 
99 	addr += (nr >> SHIFT_PER_LONG);
100 	mask = 1L << CHOP_SHIFTCOUNT(nr);
101 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
102 	oldbit = (*addr & mask) ? 1 : 0;
103 	*addr |= mask;
104 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
105 
106 	return oldbit;
107 }
108 
__test_and_set_bit(int nr,void * address)109 static __inline__ int __test_and_set_bit(int nr, void * address)
110 {
111 	unsigned long mask;
112 	unsigned long *addr = (unsigned long *) address;
113 	int oldbit;
114 
115 	addr += (nr >> SHIFT_PER_LONG);
116 	mask = 1L << CHOP_SHIFTCOUNT(nr);
117 	oldbit = (*addr & mask) ? 1 : 0;
118 	*addr |= mask;
119 
120 	return oldbit;
121 }
122 
test_and_clear_bit(int nr,void * address)123 static __inline__ int test_and_clear_bit(int nr, void * address)
124 {
125 	unsigned long mask;
126 	unsigned long *addr = (unsigned long *) address;
127 	int oldbit;
128 	unsigned long flags;
129 
130 	addr += (nr >> SHIFT_PER_LONG);
131 	mask = 1L << CHOP_SHIFTCOUNT(nr);
132 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
133 	oldbit = (*addr & mask) ? 1 : 0;
134 	*addr &= ~mask;
135 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
136 
137 	return oldbit;
138 }
139 
__test_and_clear_bit(int nr,void * address)140 static __inline__ int __test_and_clear_bit(int nr, void * address)
141 {
142 	unsigned long mask;
143 	unsigned long *addr = (unsigned long *) address;
144 	int oldbit;
145 
146 	addr += (nr >> SHIFT_PER_LONG);
147 	mask = 1L << CHOP_SHIFTCOUNT(nr);
148 	oldbit = (*addr & mask) ? 1 : 0;
149 	*addr &= ~mask;
150 
151 	return oldbit;
152 }
153 
test_and_change_bit(int nr,void * address)154 static __inline__ int test_and_change_bit(int nr, void * address)
155 {
156 	unsigned long mask;
157 	unsigned long *addr = (unsigned long *) address;
158 	int oldbit;
159 	unsigned long flags;
160 
161 	addr += (nr >> SHIFT_PER_LONG);
162 	mask = 1L << CHOP_SHIFTCOUNT(nr);
163 	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
164 	oldbit = (*addr & mask) ? 1 : 0;
165 	*addr ^= mask;
166 	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
167 
168 	return oldbit;
169 }
170 
__test_and_change_bit(int nr,void * address)171 static __inline__ int __test_and_change_bit(int nr, void * address)
172 {
173 	unsigned long mask;
174 	unsigned long *addr = (unsigned long *) address;
175 	int oldbit;
176 
177 	addr += (nr >> SHIFT_PER_LONG);
178 	mask = 1L << CHOP_SHIFTCOUNT(nr);
179 	oldbit = (*addr & mask) ? 1 : 0;
180 	*addr ^= mask;
181 
182 	return oldbit;
183 }
184 
test_bit(int nr,const void * address)185 static __inline__ int test_bit(int nr, const void *address)
186 {
187 	unsigned long mask;
188 	unsigned long *addr = (unsigned long *) address;
189 
190 	addr += (nr >> SHIFT_PER_LONG);
191 	mask = 1L << CHOP_SHIFTCOUNT(nr);
192 
193 	return !!(*addr & mask);
194 }
195 
ffz(unsigned long word)196 extern __inline__ unsigned long ffz(unsigned long word)
197 {
198 	unsigned long result;
199 
200 	result = 0;
201 	while (word & 1) {
202 		result++;
203 		word >>= 1;
204 	}
205 
206 	return result;
207 }
208 
209 #ifdef __KERNEL__
210 
211 /*
212  * ffs: find first bit set. This is defined the same way as
213  * the libc and compiler builtin ffs routines, therefore
214  * differs in spirit from the above ffz (man ffs).
215  */
216 
217 #define ffs(x) generic_ffs(x)
218 
219 /*
220  * hweightN: returns the hamming weight (i.e. the number
221  * of bits set) of a N-bit word
222  */
223 
224 #define hweight32(x) generic_hweight32(x)
225 #define hweight16(x) generic_hweight16(x)
226 #define hweight8(x) generic_hweight8(x)
227 
228 #endif /* __KERNEL__ */
229 
230 /*
231  * This implementation of find_{first,next}_zero_bit was stolen from
232  * Linus' asm-alpha/bitops.h.
233  */
234 #define find_first_zero_bit(addr, size) \
235 	find_next_zero_bit((addr), (size), 0)
236 
find_next_zero_bit(void * addr,unsigned long size,unsigned long offset)237 static __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
238 {
239 	unsigned long * p = ((unsigned long *) addr) + (offset >> SHIFT_PER_LONG);
240 	unsigned long result = offset & ~(BITS_PER_LONG-1);
241 	unsigned long tmp;
242 
243 	if (offset >= size)
244 		return size;
245 	size -= result;
246 	offset &= (BITS_PER_LONG-1);
247 	if (offset) {
248 		tmp = *(p++);
249 		tmp |= ~0UL >> (BITS_PER_LONG-offset);
250 		if (size < BITS_PER_LONG)
251 			goto found_first;
252 		if (~tmp)
253 			goto found_middle;
254 		size -= BITS_PER_LONG;
255 		result += BITS_PER_LONG;
256 	}
257 	while (size & ~(BITS_PER_LONG -1)) {
258 		if (~(tmp = *(p++)))
259 			goto found_middle;
260 		result += BITS_PER_LONG;
261 		size -= BITS_PER_LONG;
262 	}
263 	if (!size)
264 		return result;
265 	tmp = *p;
266 found_first:
267 	tmp |= ~0UL << size;
268 found_middle:
269 	return result + ffz(tmp);
270 }
271 
272 #define _EXT2_HAVE_ASM_BITOPS_
273 
274 #ifdef __KERNEL__
275 /*
276  * test_and_{set,clear}_bit guarantee atomicity without
277  * disabling interrupts.
278  */
279 #ifdef __LP64__
280 #define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x38, addr)
281 #define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x38, addr)
282 #else
283 #define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x18, addr)
284 #define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x18, addr)
285 #endif
286 
287 #endif	/* __KERNEL__ */
288 
ext2_test_bit(int nr,__const__ void * addr)289 static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
290 {
291 	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
292 
293 	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
294 }
295 
296 /*
297  * This implementation of ext2_find_{first,next}_zero_bit was stolen from
298  * Linus' asm-alpha/bitops.h and modified for a big-endian machine.
299  */
300 
301 #define ext2_find_first_zero_bit(addr, size) \
302         ext2_find_next_zero_bit((addr), (size), 0)
303 
ext2_find_next_zero_bit(void * addr,unsigned long size,unsigned long offset)304 extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
305 	unsigned long size, unsigned long offset)
306 {
307 	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
308 	unsigned int result = offset & ~31UL;
309 	unsigned int tmp;
310 
311 	if (offset >= size)
312 		return size;
313 	size -= result;
314 	offset &= 31UL;
315 	if (offset) {
316 		tmp = cpu_to_le32p(p++);
317 		tmp |= ~0UL >> (32-offset);
318 		if (size < 32)
319 			goto found_first;
320 		if (tmp != ~0U)
321 			goto found_middle;
322 		size -= 32;
323 		result += 32;
324 	}
325 	while (size >= 32) {
326 		if ((tmp = cpu_to_le32p(p++)) != ~0U)
327 			goto found_middle;
328 		result += 32;
329 		size -= 32;
330 	}
331 	if (!size)
332 		return result;
333 	tmp = cpu_to_le32p(p);
334 found_first:
335 	tmp |= ~0U << size;
336 found_middle:
337 	return result + ffz(tmp);
338 }
339 
340 /* Bitmap functions for the minix filesystem.  */
341 #define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr)
342 #define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr))
343 #define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
344 #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
345 #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
346 
347 #endif /* _PARISC_BITOPS_H */
348