~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/include/asm-sparc/bitops.h

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* $Id: bitops.h,v 1.61 2000/09/23 02:11:22 davem Exp $
  2  * bitops.h: Bit string operations on the Sparc.
  3  *
  4  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
  5  * Copyright 1996 Eddie C. Dost   (ecd@skynet.be)
  6  */
  7 
  8 #ifndef _SPARC_BITOPS_H
  9 #define _SPARC_BITOPS_H
 10 
 11 #include <linux/kernel.h>
 12 #include <asm/byteorder.h>
 13 
 14 #ifndef __KERNEL__
 15 
 16 /* User mode bitops, defined here for convenience. Note: these are not
 17  * atomic, so packages like nthreads should do some locking around these
 18  * themself.
 19  */
 20 
 21 extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
 22 {
 23         int mask;
 24         unsigned long *ADDR = (unsigned long *) addr;
 25 
 26         ADDR += nr >> 5;
 27         mask = 1 << (nr & 31);
 28         __asm__ __volatile__("
 29         ld      [%0], %%g3
 30         or      %%g3, %2, %%g2
 31         st      %%g2, [%0]
 32         and     %%g3, %2, %0
 33         "
 34         : "=&r" (ADDR)
 35         : "" (ADDR), "r" (mask)
 36         : "g2", "g3");
 37 
 38         return (unsigned long) ADDR;
 39 }
 40 
 41 extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
 42 {
 43         int mask;
 44         unsigned long *ADDR = (unsigned long *) addr;
 45 
 46         ADDR += nr >> 5;
 47         mask = 1 << (nr & 31);
 48         __asm__ __volatile__("
 49         ld      [%0], %%g3
 50         andn    %%g3, %2, %%g2
 51         st      %%g2, [%0]
 52         and     %%g3, %2, %0
 53         "
 54         : "=&r" (ADDR)
 55         : "" (ADDR), "r" (mask)
 56         : "g2", "g3");
 57 
 58         return (unsigned long) ADDR;
 59 }
 60 
 61 extern __inline__ void change_bit(unsigned long nr, void *addr)
 62 {
 63         int mask;
 64         unsigned long *ADDR = (unsigned long *) addr;
 65 
 66         ADDR += nr >> 5;
 67         mask = 1 << (nr & 31);
 68         __asm__ __volatile__("
 69         ld      [%0], %%g3
 70         xor     %%g3, %2, %%g2
 71         st      %%g2, [%0]
 72         and     %%g3, %2, %0
 73         "
 74         : "=&r" (ADDR)
 75         : "" (ADDR), "r" (mask)
 76         : "g2", "g3");
 77 }
 78 
 79 #else /* __KERNEL__ */
 80 
 81 #include <asm/system.h>
 82 
 83 /* Set bit 'nr' in 32-bit quantity at address 'addr' where bit ''
 84  * is in the highest of the four bytes and bit '31' is the high bit
 85  * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
 86  * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
 87  */
 88 
 89 extern __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr)
 90 {
 91         register unsigned long mask asm("g2");
 92         register unsigned long *ADDR asm("g1");
 93         ADDR = ((unsigned long *) addr) + (nr >> 5);
 94         mask = 1 << (nr & 31);
 95         __asm__ __volatile__("
 96         mov     %%o7, %%g4
 97         call    ___set_bit
 98          add    %%o7, 8, %%o7
 99 "       : "=&r" (mask)
100         : "" (mask), "r" (ADDR)
101         : "g3", "g4", "g5", "g7", "cc");
102 
103         return mask != 0;
104 }
105 
106 extern __inline__ void set_bit(unsigned long nr, volatile void *addr)
107 {
108         (void) test_and_set_bit(nr, addr);
109 }
110 
111 extern __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr)
112 {
113         register unsigned long mask asm("g2");
114         register unsigned long *ADDR asm("g1");
115 
116         ADDR = ((unsigned long *) addr) + (nr >> 5);
117         mask = 1 << (nr & 31);
118         __asm__ __volatile__("
119         mov     %%o7, %%g4
120         call    ___clear_bit
121          add    %%o7, 8, %%o7
122 "       : "=&r" (mask)
123         : "" (mask), "r" (ADDR)
124         : "g3", "g4", "g5", "g7", "cc");
125 
126         return mask != 0;
127 }
128 
129 extern __inline__ void clear_bit(unsigned long nr, volatile void *addr)
130 {
131         (void) test_and_clear_bit(nr, addr);
132 }
133 
134 extern __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
135 {
136         register unsigned long mask asm("g2");
137         register unsigned long *ADDR asm("g1");
138 
139         ADDR = ((unsigned long *) addr) + (nr >> 5);
140         mask = 1 << (nr & 31);
141         __asm__ __volatile__("
142         mov     %%o7, %%g4
143         call    ___change_bit
144          add    %%o7, 8, %%o7
145 "       : "=&r" (mask)
146         : "" (mask), "r" (ADDR)
147         : "g3", "g4", "g5", "g7", "cc");
148 
149         return mask != 0;
150 }
151 
152 extern __inline__ void change_bit(unsigned long nr, volatile void *addr)
153 {
154         (void) test_and_change_bit(nr, addr);
155 }
156 
157 #endif /* __KERNEL__ */
158 
159 #define smp_mb__before_clear_bit()      do { } while(0)
160 #define smp_mb__after_clear_bit()       do { } while(0)
161 
162 /* The following routine need not be atomic. */
163 extern __inline__ int test_bit(int nr, __const__ void *addr)
164 {
165         return (1 & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31))) != 0;
166 }
167 
168 /* The easy/cheese version for now. */
169 extern __inline__ unsigned long ffz(unsigned long word)
170 {
171         unsigned long result = 0;
172 
173         while(word & 1) {
174                 result++;
175                 word >>= 1;
176         }
177         return result;
178 }
179 
180 #ifdef __KERNEL__
181 
182 /*
183  * ffs: find first bit set. This is defined the same way as
184  * the libc and compiler builtin ffs routines, therefore
185  * differs in spirit from the above ffz (man ffs).
186  */
187 
188 #define ffs(x) generic_ffs(x)
189 
190 /*
191  * hweightN: returns the hamming weight (i.e. the number
192  * of bits set) of a N-bit word
193  */
194 
195 #define hweight32(x) generic_hweight32(x)
196 #define hweight16(x) generic_hweight16(x)
197 #define hweight8(x) generic_hweight8(x)
198 
199 #endif /* __KERNEL__ */
200 
201 /* find_next_zero_bit() finds the first zero bit in a bit string of length
202  * 'size' bits, starting the search at bit 'offset'. This is largely based
203  * on Linus's ALPHA routines, which are pretty portable BTW.
204  */
205 
206 extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
207 {
208         unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
209         unsigned long result = offset & ~31UL;
210         unsigned long tmp;
211 
212         if (offset >= size)
213                 return size;
214         size -= result;
215         offset &= 31UL;
216         if (offset) {
217                 tmp = *(p++);
218                 tmp |= ~0UL >> (32-offset);
219                 if (size < 32)
220                         goto found_first;
221                 if (~tmp)
222                         goto found_middle;
223                 size -= 32;
224                 result += 32;
225         }
226         while (size & ~31UL) {
227                 if (~(tmp = *(p++)))
228                         goto found_middle;
229                 result += 32;
230                 size -= 32;
231         }
232         if (!size)
233                 return result;
234         tmp = *p;
235 
236 found_first:
237         tmp |= ~0UL << size;
238         if (tmp == ~0UL)        /* Are any bits zero? */
239                 return result + size; /* Nope. */
240 found_middle:
241         return result + ffz(tmp);
242 }
243 
244 /* Linus sez that gcc can optimize the following correctly, we'll see if this
245  * holds on the Sparc as it does for the ALPHA.
246  */
247 
248 #define find_first_zero_bit(addr, size) \
249         find_next_zero_bit((addr), (size), 0)
250 
251 #ifndef __KERNEL__
252 
253 extern __inline__ int set_le_bit(int nr, void *addr)
254 {
255         int             mask;
256         unsigned char   *ADDR = (unsigned char *) addr;
257 
258         ADDR += nr >> 3;
259         mask = 1 << (nr & 0x07);
260         __asm__ __volatile__("
261         ldub    [%0], %%g3
262         or      %%g3, %2, %%g2
263         stb     %%g2, [%0]
264         and     %%g3, %2, %0
265         "
266         : "=&r" (ADDR)
267         : "" (ADDR), "r" (mask)
268         : "g2", "g3");
269 
270         return (int) ADDR;
271 }
272 
273 extern __inline__ int clear_le_bit(int nr, void *addr)
274 {
275         int             mask;
276         unsigned char   *ADDR = (unsigned char *) addr;
277 
278         ADDR += nr >> 3;
279         mask = 1 << (nr & 0x07);
280         __asm__ __volatile__("
281         ldub    [%0], %%g3
282         andn    %%g3, %2, %%g2
283         stb     %%g2, [%0]
284         and     %%g3, %2, %0
285         "
286         : "=&r" (ADDR)
287         : "" (ADDR), "r" (mask)
288         : "g2", "g3");
289 
290         return (int) ADDR;
291 }
292 
293 #else /* __KERNEL__ */
294 
295 /* Now for the ext2 filesystem bit operations and helper routines. */
296 
297 extern __inline__ int set_le_bit(int nr, volatile void * addr)
298 {
299         register int mask asm("g2");
300         register unsigned char *ADDR asm("g1");
301 
302         ADDR = ((unsigned char *) addr) + (nr >> 3);
303         mask = 1 << (nr & 0x07);
304         __asm__ __volatile__("
305         mov     %%o7, %%g4
306         call    ___set_le_bit
307          add    %%o7, 8, %%o7
308 "       : "=&r" (mask)
309         : "" (mask), "r" (ADDR)
310         : "g3", "g4", "g5", "g7", "cc");
311 
312         return mask;
313 }
314 
315 extern __inline__ int clear_le_bit(int nr, volatile void * addr)
316 {
317         register int mask asm("g2");
318         register unsigned char *ADDR asm("g1");
319 
320         ADDR = ((unsigned char *) addr) + (nr >> 3);
321         mask = 1 << (nr & 0x07);
322         __asm__ __volatile__("
323         mov     %%o7, %%g4
324         call    ___clear_le_bit
325          add    %%o7, 8, %%o7
326 "       : "=&r" (mask)
327         : "" (mask), "r" (ADDR)
328         : "g3", "g4", "g5", "g7", "cc");
329 
330         return mask;
331 }
332 
333 #endif /* __KERNEL__ */
334 
335 extern __inline__ int test_le_bit(int nr, __const__ void * addr)
336 {
337         int                     mask;
338         __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
339 
340         ADDR += nr >> 3;
341         mask = 1 << (nr & 0x07);
342         return ((mask & *ADDR) != 0);
343 }
344 
345 #ifdef __KERNEL__
346 
347 #define ext2_set_bit   set_le_bit
348 #define ext2_clear_bit clear_le_bit
349 #define ext2_test_bit  test_le_bit
350 
351 #endif /* __KERNEL__ */
352 
353 #define find_first_zero_le_bit(addr, size) \
354         find_next_zero_le_bit((addr), (size), 0)
355 
356 extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
357 {
358         unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
359         unsigned long result = offset & ~31UL;
360         unsigned long tmp;
361 
362         if (offset >= size)
363                 return size;
364         size -= result;
365         offset &= 31UL;
366         if(offset) {
367                 tmp = *(p++);
368                 tmp |= __swab32(~0UL >> (32-offset));
369                 if(size < 32)
370                         goto found_first;
371                 if(~tmp)
372                         goto found_middle;
373                 size -= 32;
374                 result += 32;
375         }
376         while(size & ~31UL) {
377                 if(~(tmp = *(p++)))
378                         goto found_middle;
379                 result += 32;
380                 size -= 32;
381         }
382         if(!size)
383                 return result;
384         tmp = *p;
385 
386 found_first:
387         tmp = __swab32(tmp) | (~0UL << size);
388         if (tmp == ~0UL)        /* Are any bits zero? */
389                 return result + size; /* Nope. */
390         return result + ffz(tmp);
391 
392 found_middle:
393         return result + ffz(__swab32(tmp));
394 }
395 
396 #ifdef __KERNEL__
397 
398 #define ext2_find_first_zero_bit     find_first_zero_le_bit
399 #define ext2_find_next_zero_bit      find_next_zero_le_bit
400 
401 /* Bitmap functions for the minix filesystem.  */
402 #define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
403 #define minix_set_bit(nr,addr) set_bit(nr,addr)
404 #define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
405 #define minix_test_bit(nr,addr) test_bit(nr,addr)
406 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
407 
408 #endif /* __KERNEL__ */
409 
410 #endif /* defined(_SPARC_BITOPS_H) */
411 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.