File: /usr/src/linux/include/asm-parisc/bitops.h

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     #ifdef __LP64__
10     #   define SHIFT_PER_LONG 6
11     #ifndef BITS_PER_LONG
12     #   define BITS_PER_LONG 64
13     #endif
14     #else
15     #   define SHIFT_PER_LONG 5
16     #ifndef BITS_PER_LONG
17     #   define BITS_PER_LONG 32
18     #endif
19     #endif
20     
21     #define CHOP_SHIFTCOUNT(x) ((x) & (BITS_PER_LONG - 1))
22     
23     static __inline__ int test_and_set_bit(int nr, void * address)
24     {
25     	unsigned long mask;
26     	unsigned long *addr = (unsigned long *) address;
27     	int oldbit;
28     	unsigned long flags;
29     
30     	addr += (nr >> SHIFT_PER_LONG);
31     	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
32     
33     	mask = 1L << CHOP_SHIFTCOUNT(nr);
34     	oldbit = (*addr & mask) ? 1 : 0;
35     	*addr |= mask;
36     
37     	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
38     
39     	return oldbit;
40     }
41     
42     static __inline__ int test_and_clear_bit(int nr, void * address)
43     {
44     	unsigned long mask;
45     	unsigned long *addr = (unsigned long *) address;
46     	int oldbit;
47     	unsigned long flags;
48     
49     	addr += (nr >> SHIFT_PER_LONG);
50     	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
51     
52     	mask = 1L << CHOP_SHIFTCOUNT(nr);
53     	oldbit = (*addr & mask) ? 1 : 0;
54     	*addr &= ~mask;
55     
56     	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
57     
58     	return oldbit;
59     }
60     
61     static __inline__ int test_and_change_bit(int nr, void * address)
62     {
63     	unsigned long mask;
64     	unsigned long *addr = (unsigned long *) address;
65     	int oldbit;
66     	unsigned long flags;
67     
68     	addr += (nr >> SHIFT_PER_LONG);
69     	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
70     
71     	mask = 1L << CHOP_SHIFTCOUNT(nr);
72     	oldbit = (*addr & mask) ? 1 : 0;
73     	*addr ^= mask;
74     
75     	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
76     
77     	return oldbit;
78     }
79     
80     /* again, the read-only case doesn't have to do any locking */
81     
82     static __inline__ int test_bit(int nr, const volatile 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     	
90     	return !!(*addr & mask);
91     }
92     
93     /* sparc does this, other arch's don't -- what's the right answer? XXX */
94     #define smp_mb__before_clear_bit()	do { } while(0)
95     #define smp_mb__after_clear_bit()	do { } while(0)
96     #define set_bit(nr,addr)	((void)test_and_set_bit(nr,addr))
97     #define clear_bit(nr,addr)	((void)test_and_clear_bit(nr,addr))
98     #define change_bit(nr,addr)	((void)test_and_change_bit(nr,addr))
99     
100     /* XXX We'd need some binary search here */
101     
102     extern __inline__ unsigned long ffz(unsigned long word)
103     {
104     	unsigned long result;
105     
106     	result = 0;
107     	while(word & 1) {
108     		result++;
109     		word >>= 1;
110     	}
111     
112     	return result;
113     }
114     
115     #ifdef __KERNEL__
116     
117     /*
118      * ffs: find first bit set. This is defined the same way as
119      * the libc and compiler builtin ffs routines, therefore
120      * differs in spirit from the above ffz (man ffs).
121      */
122     
123     #define ffs(x) generic_ffs(x)
124     
125     /*
126      * hweightN: returns the hamming weight (i.e. the number
127      * of bits set) of a N-bit word
128      */
129     
130     #define hweight32(x) generic_hweight32(x)
131     #define hweight16(x) generic_hweight16(x)
132     #define hweight8(x) generic_hweight8(x)
133     
134     #endif /* __KERNEL__ */
135     
136     /*
137      * This implementation of find_{first,next}_zero_bit was stolen from
138      * Linus' asm-alpha/bitops.h.
139      */
140     #define find_first_zero_bit(addr, size) \
141     	find_next_zero_bit((addr), (size), 0)
142     
143     static __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
144     {
145     	unsigned long * p = ((unsigned long *) addr) + (offset >> SHIFT_PER_LONG);
146     	unsigned long result = offset & ~(BITS_PER_LONG-1);
147     	unsigned long tmp;
148     
149     	if (offset >= size)
150     		return size;
151     	size -= result;
152     	offset &= (BITS_PER_LONG-1);
153     	if (offset) {
154     		tmp = *(p++);
155     		tmp |= ~0UL >> (BITS_PER_LONG-offset);
156     		if (size < BITS_PER_LONG)
157     			goto found_first;
158     		if (~tmp)
159     			goto found_middle;
160     		size -= BITS_PER_LONG;
161     		result += BITS_PER_LONG;
162     	}
163     	while (size & ~(BITS_PER_LONG -1)) {
164     		if (~(tmp = *(p++)))
165     			goto found_middle;
166     		result += BITS_PER_LONG;
167     		size -= BITS_PER_LONG;
168     	}
169     	if (!size)
170     		return result;
171     	tmp = *p;
172     found_first:
173     	tmp |= ~0UL << size;
174     found_middle:
175     	return result + ffz(tmp);
176     }
177     
178     #define _EXT2_HAVE_ASM_BITOPS_
179     
180     #ifdef __KERNEL__
181     /*
182      * test_and_{set,clear}_bit guarantee atomicity without
183      * disabling interrupts.
184      */
185     #define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x18, addr)
186     #define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x18, addr)
187     
188     #endif	/* __KERNEL__ */
189     
190     static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
191     {
192     	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
193     
194     	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
195     }
196     
197     /*
198      * This implementation of ext2_find_{first,next}_zero_bit was stolen from
199      * Linus' asm-alpha/bitops.h and modified for a big-endian machine.
200      */
201     
202     #define ext2_find_first_zero_bit(addr, size) \
203             ext2_find_next_zero_bit((addr), (size), 0)
204     
205     extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
206     	unsigned long size, unsigned long offset)
207     {
208     	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
209     	unsigned int result = offset & ~31UL;
210     	unsigned int tmp;
211     
212     	if (offset >= size)
213     		return size;
214     	size -= result;
215     	offset &= 31UL;
216     	if (offset) {
217     		tmp = cpu_to_le32p(p++);
218     		tmp |= ~0UL >> (32-offset);
219     		if (size < 32)
220     			goto found_first;
221     		if (tmp != ~0U)
222     			goto found_middle;
223     		size -= 32;
224     		result += 32;
225     	}
226     	while (size >= 32) {
227     		if ((tmp = cpu_to_le32p(p++)) != ~0U)
228     			goto found_middle;
229     		result += 32;
230     		size -= 32;
231     	}
232     	if (!size)
233     		return result;
234     	tmp = cpu_to_le32p(p);
235     found_first:
236     	tmp |= ~0U << size;
237     found_middle:
238     	return result + ffz(tmp);
239     }
240     
241     /* Bitmap functions for the minix filesystem.  */
242     #define minix_set_bit(nr,addr) ext2_set_bit(nr,addr)
243     #define minix_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
244     #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
245     #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
246     
247     #endif /* _PARISC_BITOPS_H */
248