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

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

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

  1 /*
  2  * This file is subject to the terms and conditions of the GNU General Public
  3  * License.  See the file "COPYING" in the main directory of this archive
  4  * for more details.
  5  *
  6  * Copyright (c) 1994, 95, 96, 97, 98, 99, 2000  Ralf Baechle
  7  * Copyright (c) 1999, 2000  Silicon Graphics, Inc.
  8  */
  9 #ifndef _ASM_BITOPS_H
 10 #define _ASM_BITOPS_H
 11 
 12 #include <linux/types.h>
 13 #include <linux/byteorder/swab.h>               /* sigh ... */
 14 
 15 #ifndef __KERNEL__
 16 #error "Don't do this, sucker ..."
 17 #endif
 18 
 19 #include <asm/system.h>
 20 #include <asm/sgidefs.h>
 21 #include <asm/mipsregs.h>
 22 
 23 /*
 24  * clear_bit() doesn't provide any barrier for the compiler.
 25  */
 26 #define smp_mb__before_clear_bit()      barrier()
 27 #define smp_mb__after_clear_bit()       barrier()
 28 
 29 /*
 30  * These functions for MIPS ISA > 1 are interrupt and SMP proof and
 31  * interrupt friendly
 32  */
 33 
 34 extern __inline__ void
 35 set_bit(unsigned long nr, volatile void *addr)
 36 {
 37         unsigned long *m = ((unsigned long *) addr) + (nr >> 6);
 38         unsigned long temp;
 39 
 40         __asm__ __volatile__(
 41                 "1:\tlld\t%0, %1\t\t# set_bit\n\t"
 42                 "or\t%0, %2\n\t"
 43                 "scd\t%0, %1\n\t"
 44                 "beqz\t%0, 1b"
 45                 : "=&r" (temp), "=m" (*m)
 46                 : "ir" (1UL << (nr & 0x3f)), "m" (*m)
 47                 : "memory");
 48 }
 49 
 50 /* WARNING: non atomic and it can be reordered! */
 51 extern __inline__ void __set_bit(int nr, volatile void * addr)
 52 {
 53         unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
 54 
 55         *m |= 1UL << (nr & 0x3f);
 56 }
 57 
 58 extern __inline__ void
 59 clear_bit(unsigned long nr, volatile void *addr)
 60 {
 61         unsigned long *m = ((unsigned long *) addr) + (nr >> 6);
 62         unsigned long temp;
 63 
 64         __asm__ __volatile__(
 65                 "1:\tlld\t%0, %1\t\t# clear_bit\n\t"
 66                 "and\t%0, %2\n\t"
 67                 "scd\t%0, %1\n\t"
 68                 "beqz\t%0, 1b\n\t"
 69                 : "=&r" (temp), "=m" (*m)
 70                 : "ir" (~(1UL << (nr & 0x3f))), "m" (*m));
 71 }
 72 
 73 
 74 extern __inline__ void
 75 change_bit(unsigned long nr, volatile void *addr)
 76 {
 77         unsigned long *m = ((unsigned long *) addr) + (nr >> 6);
 78         unsigned long temp;
 79 
 80         __asm__ __volatile__(
 81                 "1:\tlld\t%0, %1\t\t# change_bit\n\t"
 82                 "xor\t%0, %2\n\t"
 83                 "scd\t%0, %1\n\t"
 84                 "beqz\t%0, 1b"
 85                 :"=&r" (temp), "=m" (*m)
 86                 :"ir" (1UL << (nr & 0x3f)), "m" (*m));
 87 }
 88 
 89 extern __inline__ unsigned long
 90 test_and_set_bit(unsigned long nr, volatile void *addr)
 91 {
 92         unsigned long *m = ((unsigned long *) addr) + (nr >> 6);
 93         unsigned long temp, res;
 94 
 95         __asm__ __volatile__(
 96                 ".set\tnoreorder\t\t# test_and_set_bit\n"
 97                 "1:\tlld\t%0, %1\n\t"
 98                 "or\t%2, %0, %3\n\t"
 99                 "scd\t%2, %1\n\t"
100                 "beqz\t%2, 1b\n\t"
101                 " and\t%2, %0, %3\n\t"
102                 ".set\treorder"
103                 : "=&r" (temp), "=m" (*m), "=&r" (res)
104                 : "r" (1UL << (nr & 0x3f)), "m" (*m)
105                 : "memory");
106 
107         return res != 0;
108 }
109 
110 extern __inline__ int __test_and_set_bit(int nr, volatile void * addr)
111 {
112         int mask, retval;
113         volatile long *a = addr;
114 
115         a += nr >> 6;
116         mask = 1 << (nr & 0x3f);
117         retval = (mask & *a) != 0;
118         *a |= mask;
119 
120         return retval;
121 }
122 
123 extern __inline__ unsigned long
124 test_and_clear_bit(unsigned long nr, volatile void *addr)
125 {
126         unsigned long *m = ((unsigned long *) addr) + (nr >> 6);
127         unsigned long temp, res;
128 
129         __asm__ __volatile__(
130                 ".set\tnoreorder\t\t# test_and_clear_bit\n"
131                 "1:\tlld\t%0, %1\n\t"
132                 "or\t%2, %0, %3\n\t"
133                 "xor\t%2, %3\n\t"
134                 "scd\t%2, %1\n\t"
135                 "beqz\t%2, 1b\n\t"
136                 " and\t%2, %0, %3\n\t"
137                 ".set\treorder"
138                 : "=&r" (temp), "=m" (*m), "=&r" (res)
139                 : "r" (1UL << (nr & 0x3f)), "m" (*m)
140                 : "memory");
141 
142         return res != 0;
143 }
144 
145 extern __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
146 {
147         int     mask, retval;
148         volatile long    *a = addr;
149 
150         a += nr >> 6;
151         mask = 1 << (nr & 0x3f);
152         retval = (mask & *a) != 0;
153         *a &= ~mask;
154 
155         return retval;
156 }
157 
158 extern __inline__ unsigned long
159 test_and_change_bit(unsigned long nr, volatile void *addr)
160 {
161         unsigned long *m = ((unsigned long *) addr) + (nr >> 6);
162         unsigned long temp, res;
163 
164         __asm__ __volatile__(
165                 ".set\tnoreorder\t\t# test_and_change_bit\n"
166                 "1:\tlld\t%0, %1\n\t"
167                 "xor\t%2, %0, %3\n\t"
168                 "scd\t%2, %1\n\t"
169                 "beqz\t%2, 1b\n\t"
170                 " and\t%2, %0, %3\n\t"
171                 ".set\treorder"
172                 : "=&r" (temp), "=m" (*m), "=&r" (res)
173                 : "r" (1UL << (nr & 0x3f)), "m" (*m)
174                 : "memory");
175 
176         return res != 0;
177 }
178 
179 extern __inline__ unsigned long
180 test_bit(int nr, volatile void * addr)
181 {
182         return 1UL & (((const long *) addr)[nr >> 6] >> (nr & 0x3f));
183 }
184 
185 #ifndef __MIPSEB__
186 
187 /* Little endian versions. */
188 
189 extern __inline__ int
190 find_first_zero_bit (void *addr, unsigned size)
191 {
192         unsigned long dummy;
193         int res;
194 
195         if (!size)
196                 return 0;
197 
198         __asm__ (".set\tnoreorder\n\t"
199                 ".set\tnoat\n"
200                 "1:\tsubu\t$1,%6,%0\n\t"
201                 "blez\t$1,2f\n\t"
202                 "lw\t$1,(%5)\n\t"
203                 "addiu\t%5,4\n\t"
204 #if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) || \
205     (_MIPS_ISA == _MIPS_ISA_MIPS4) || (_MIPS_ISA == _MIPS_ISA_MIPS5)
206                 "beql\t%1,$1,1b\n\t"
207                 "addiu\t%0,32\n\t"
208 #else
209                 "addiu\t%0,32\n\t"
210                 "beq\t%1,$1,1b\n\t"
211                 "nop\n\t"
212                 "subu\t%0,32\n\t"
213 #endif
214                 "li\t%1,1\n"
215                 "1:\tand\t%2,$1,%1\n\t"
216                 "beqz\t%2,2f\n\t"
217                 "sll\t%1,%1,1\n\t"
218                 "bnez\t%1,1b\n\t"
219                 "add\t%0,%0,1\n\t"
220                 ".set\tat\n\t"
221                 ".set\treorder\n"
222                 "2:"
223                 : "=r" (res), "=r" (dummy), "=r" (addr)
224                 : "" ((signed int) 0), "1" ((unsigned int) 0xffffffff),
225                   "2" (addr), "r" (size)
226                 : "$1");
227 
228         return res;
229 }
230 
231 extern __inline__ int
232 find_next_zero_bit (void * addr, int size, int offset)
233 {
234         unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
235         int set = 0, bit = offset & 31, res;
236         unsigned long dummy;
237 
238         if (bit) {
239                 /*
240                  * Look for zero in first byte
241                  */
242                 __asm__(".set\tnoreorder\n\t"
243                         ".set\tnoat\n"
244                         "1:\tand\t$1,%4,%1\n\t"
245                         "beqz\t$1,1f\n\t"
246                         "sll\t%1,%1,1\n\t"
247                         "bnez\t%1,1b\n\t"
248                         "addiu\t%0,1\n\t"
249                         ".set\tat\n\t"
250                         ".set\treorder\n"
251                         "1:"
252                         : "=r" (set), "=r" (dummy)
253                         : "" (0), "1" (1 << bit), "r" (*p)
254                         : "$1");
255                 if (set < (32 - bit))
256                         return set + offset;
257                 set = 32 - bit;
258                 p++;
259         }
260         /*
261          * No zero yet, search remaining full bytes for a zero
262          */
263         res = find_first_zero_bit(p, size - 32 * (p - (unsigned int *) addr));
264         return offset + set + res;
265 }
266 
267 #endif /* !(__MIPSEB__) */
268 
269 /*
270  * ffz = Find First Zero in word. Undefined if no zero exists,
271  * so code should check against ~0UL first..
272  */
273 extern __inline__ unsigned long ffz(unsigned long word)
274 {
275         unsigned long k;
276 
277         word = ~word;
278         k = 63;
279         if (word & 0x00000000ffffffffUL) { k -= 32; word <<= 32; }
280         if (word & 0x0000ffff00000000UL) { k -= 16; word <<= 16; }
281         if (word & 0x00ff000000000000UL) { k -= 8;  word <<= 8;  }
282         if (word & 0x0f00000000000000UL) { k -= 4;  word <<= 4;  }
283         if (word & 0x3000000000000000UL) { k -= 2;  word <<= 2;  }
284         if (word & 0x4000000000000000UL) { k -= 1; }
285 
286         return k;
287 }
288 
289 #ifdef __KERNEL__
290 
291 /*
292  * ffs: find first bit set. This is defined the same way as
293  * the libc and compiler builtin ffs routines, therefore
294  * differs in spirit from the above ffz (man ffs).
295  */
296 
297 #define ffs(x) generic_ffs(x)
298 
299 /*
300  * hweightN: returns the hamming weight (i.e. the number
301  * of bits set) of a N-bit word
302  */
303 
304 #define hweight32(x) generic_hweight32(x)
305 #define hweight16(x) generic_hweight16(x)
306 #define hweight8(x)  generic_hweight8(x)
307 
308 #endif /* __KERNEL__ */
309 
310 #ifdef __MIPSEB__
311 
312 /*
313  * find_next_zero_bit() finds the first zero bit in a bit string of length
314  * 'size' bits, starting the search at bit 'offset'. This is largely based
315  * on Linus's ALPHA routines, which are pretty portable BTW.
316  */
317 
318 extern __inline__ unsigned long
319 find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
320 {
321         unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
322         unsigned long result = offset & ~63UL;
323         unsigned long tmp;
324 
325         if (offset >= size)
326                 return size;
327         size -= result;
328         offset &= 63UL;
329         if (offset) {
330                 tmp = *(p++);
331                 tmp |= ~0UL >> (64-offset);
332                 if (size < 64)
333                         goto found_first;
334                 if (~tmp)
335                         goto found_middle;
336                 size -= 64;
337                 result += 64;
338         }
339         while (size & ~63UL) {
340                 if (~(tmp = *(p++)))
341                         goto found_middle;
342                 result += 64;
343                 size -= 64;
344         }
345         if (!size)
346                 return result;
347         tmp = *p;
348 
349 found_first:
350         tmp |= ~0UL << size;
351 found_middle:
352         return result + ffz(tmp);
353 }
354 
355 #define find_first_zero_bit(addr, size) \
356         find_next_zero_bit((addr), (size), 0)
357 
358 #endif /* (__MIPSEB__) */
359 
360 #ifdef __KERNEL__
361 
362 /* Now for the ext2 filesystem bit operations and helper routines. */
363 
364 #ifdef __MIPSEB__
365 
366 extern inline int
367 ext2_set_bit(int nr,void * addr)
368 {
369         int             mask, retval, flags;
370         unsigned char   *ADDR = (unsigned char *) addr;
371 
372         ADDR += nr >> 3;
373         mask = 1 << (nr & 0x07);
374         save_and_cli(flags);
375         retval = (mask & *ADDR) != 0;
376         *ADDR |= mask;
377         restore_flags(flags);
378         return retval;
379 }
380 
381 extern inline int
382 ext2_clear_bit(int nr, void * addr)
383 {
384         int             mask, retval, flags;
385         unsigned char   *ADDR = (unsigned char *) addr;
386 
387         ADDR += nr >> 3;
388         mask = 1 << (nr & 0x07);
389         save_and_cli(flags);
390         retval = (mask & *ADDR) != 0;
391         *ADDR &= ~mask;
392         restore_flags(flags);
393         return retval;
394 }
395 
396 extern inline int
397 ext2_test_bit(int nr, const void * addr)
398 {
399         int                     mask;
400         const unsigned char     *ADDR = (const unsigned char *) addr;
401 
402         ADDR += nr >> 3;
403         mask = 1 << (nr & 0x07);
404         return ((mask & *ADDR) != 0);
405 }
406 
407 #define ext2_find_first_zero_bit(addr, size) \
408         ext2_find_next_zero_bit((addr), (size), 0)
409 
410 extern inline unsigned int
411 ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
412 {
413         unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
414         unsigned int result = offset & ~31UL;
415         unsigned int tmp;
416 
417         if (offset >= size)
418                 return size;
419         size -= result;
420         offset &= 31UL;
421         if(offset) {
422                 /* We hold the little endian value in tmp, but then the
423                  * shift is illegal. So we could keep a big endian value
424                  * in tmp, like this:
425                  *
426                  * tmp = __swab32(*(p++));
427                  * tmp |= ~0UL >> (32-offset);
428                  *
429                  * but this would decrease preformance, so we change the
430                  * shift:
431                  */
432                 tmp = *(p++);
433                 tmp |= __swab32(~0UL >> (32-offset));
434                 if(size < 32)
435                         goto found_first;
436                 if(~tmp)
437                         goto found_middle;
438                 size -= 32;
439                 result += 32;
440         }
441         while(size & ~31UL) {
442                 if(~(tmp = *(p++)))
443                         goto found_middle;
444                 result += 32;
445                 size -= 32;
446         }
447         if(!size)
448                 return result;
449         tmp = *p;
450 
451 found_first:
452         /* tmp is little endian, so we would have to swab the shift,
453          * see above. But then we have to swab tmp below for ffz, so
454          * we might as well do this here.
455          */
456         return result + ffz(__swab32(tmp) | (~0UL << size));
457 found_middle:
458         return result + ffz(__swab32(tmp));
459 }
460 #else /* !(__MIPSEB__) */
461 
462 /* Native ext2 byte ordering, just collapse using defines. */
463 #define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
464 #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
465 #define ext2_test_bit(nr, addr) test_bit((nr), (addr))
466 #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size))
467 #define ext2_find_next_zero_bit(addr, size, offset) \
468                 find_next_zero_bit((addr), (size), (offset))
469  
470 #endif /* !(__MIPSEB__) */
471 
472 /*
473  * Bitmap functions for the minix filesystem.
474  * FIXME: These assume that Minix uses the native byte/bitorder.
475  * This limits the Minix filesystem's value for data exchange very much.
476  */
477 #define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
478 #define minix_set_bit(nr,addr) set_bit(nr,addr)
479 #define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
480 #define minix_test_bit(nr,addr) test_bit(nr,addr)
481 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
482 
483 #endif /* __KERNEL__ */
484 
485 #endif /* _ASM_BITOPS_H */
486 

~ [ 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.