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
33static __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
46static __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
56static __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
69static __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
82static __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
92static __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
109static __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
123static __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
140static __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
154static __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
171static __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
185static __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
196extern __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
237static __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;
266found_first:
267	tmp |= ~0UL << size;
268found_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
289static __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
304extern __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);
334found_first:
335	tmp |= ~0U << size;
336found_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