home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / src / linux-headers-2.6.17-6 / include / asm-parisc / bitops.h < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-11  |  6.0 KB  |  228 lines

  1. #ifndef _PARISC_BITOPS_H
  2. #define _PARISC_BITOPS_H
  3.  
  4. #include <linux/compiler.h>
  5. #include <asm/types.h>        /* for BITS_PER_LONG/SHIFT_PER_LONG */
  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. #define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1))
  16.  
  17.  
  18. #define smp_mb__before_clear_bit()      smp_mb()
  19. #define smp_mb__after_clear_bit()       smp_mb()
  20.  
  21. /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion
  22.  * on use of volatile and __*_bit() (set/clear/change):
  23.  *    *_bit() want use of volatile.
  24.  *    __*_bit() are "relaxed" and don't use spinlock or volatile.
  25.  */
  26.  
  27. static __inline__ void set_bit(int nr, volatile unsigned long * addr)
  28. {
  29.     unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
  30.     unsigned long flags;
  31.  
  32.     addr += (nr >> SHIFT_PER_LONG);
  33.     _atomic_spin_lock_irqsave(addr, flags);
  34.     *addr |= mask;
  35.     _atomic_spin_unlock_irqrestore(addr, flags);
  36. }
  37.  
  38. static __inline__ void clear_bit(int nr, volatile unsigned long * addr)
  39. {
  40.     unsigned long mask = ~(1UL << CHOP_SHIFTCOUNT(nr));
  41.     unsigned long flags;
  42.  
  43.     addr += (nr >> SHIFT_PER_LONG);
  44.     _atomic_spin_lock_irqsave(addr, flags);
  45.     *addr &= mask;
  46.     _atomic_spin_unlock_irqrestore(addr, flags);
  47. }
  48.  
  49. static __inline__ void change_bit(int nr, volatile unsigned long * addr)
  50. {
  51.     unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
  52.     unsigned long flags;
  53.  
  54.     addr += (nr >> SHIFT_PER_LONG);
  55.     _atomic_spin_lock_irqsave(addr, flags);
  56.     *addr ^= mask;
  57.     _atomic_spin_unlock_irqrestore(addr, flags);
  58. }
  59.  
  60. static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr)
  61. {
  62.     unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
  63.     unsigned long oldbit;
  64.     unsigned long flags;
  65.  
  66.     addr += (nr >> SHIFT_PER_LONG);
  67.     _atomic_spin_lock_irqsave(addr, flags);
  68.     oldbit = *addr;
  69.     *addr = oldbit | mask;
  70.     _atomic_spin_unlock_irqrestore(addr, flags);
  71.  
  72.     return (oldbit & mask) ? 1 : 0;
  73. }
  74.  
  75. static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr)
  76. {
  77.     unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
  78.     unsigned long oldbit;
  79.     unsigned long flags;
  80.  
  81.     addr += (nr >> SHIFT_PER_LONG);
  82.     _atomic_spin_lock_irqsave(addr, flags);
  83.     oldbit = *addr;
  84.     *addr = oldbit & ~mask;
  85.     _atomic_spin_unlock_irqrestore(addr, flags);
  86.  
  87.     return (oldbit & mask) ? 1 : 0;
  88. }
  89.  
  90. static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr)
  91. {
  92.     unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
  93.     unsigned long oldbit;
  94.     unsigned long flags;
  95.  
  96.     addr += (nr >> SHIFT_PER_LONG);
  97.     _atomic_spin_lock_irqsave(addr, flags);
  98.     oldbit = *addr;
  99.     *addr = oldbit ^ mask;
  100.     _atomic_spin_unlock_irqrestore(addr, flags);
  101.  
  102.     return (oldbit & mask) ? 1 : 0;
  103. }
  104.  
  105. #include <asm-generic/bitops/non-atomic.h>
  106.  
  107. #ifdef __KERNEL__
  108.  
  109. /**
  110.  * __ffs - find first bit in word. returns 0 to "BITS_PER_LONG-1".
  111.  * @word: The word to search
  112.  *
  113.  * __ffs() return is undefined if no bit is set.
  114.  *
  115.  * 32-bit fast __ffs by LaMont Jones "lamont At hp com".
  116.  * 64-bit enhancement by Grant Grundler "grundler At parisc-linux org".
  117.  * (with help from willy/jejb to get the semantics right)
  118.  *
  119.  * This algorithm avoids branches by making use of nullification.
  120.  * One side effect of "extr" instructions is it sets PSW[N] bit.
  121.  * How PSW[N] (nullify next insn) gets set is determined by the 
  122.  * "condition" field (eg "<>" or "TR" below) in the extr* insn.
  123.  * Only the 1st and one of either the 2cd or 3rd insn will get executed.
  124.  * Each set of 3 insn will get executed in 2 cycles on PA8x00 vs 16 or so
  125.  * cycles for each mispredicted branch.
  126.  */
  127.  
  128. static __inline__ unsigned long __ffs(unsigned long x)
  129. {
  130.     unsigned long ret;
  131.  
  132.     __asm__(
  133. #ifdef __LP64__
  134.         " ldi       63,%1\n"
  135.         " extrd,u,*<>  %0,63,32,%%r0\n"
  136.         " extrd,u,*TR  %0,31,32,%0\n"    /* move top 32-bits down */
  137.         " addi    -32,%1,%1\n"
  138. #else
  139.         " ldi       31,%1\n"
  140. #endif
  141.         " extru,<>  %0,31,16,%%r0\n"
  142.         " extru,TR  %0,15,16,%0\n"    /* xxxx0000 -> 0000xxxx */
  143.         " addi    -16,%1,%1\n"
  144.         " extru,<>  %0,31,8,%%r0\n"
  145.         " extru,TR  %0,23,8,%0\n"    /* 0000xx00 -> 000000xx */
  146.         " addi    -8,%1,%1\n"
  147.         " extru,<>  %0,31,4,%%r0\n"
  148.         " extru,TR  %0,27,4,%0\n"    /* 000000x0 -> 0000000x */
  149.         " addi    -4,%1,%1\n"
  150.         " extru,<>  %0,31,2,%%r0\n"
  151.         " extru,TR  %0,29,2,%0\n"    /* 0000000y, 1100b -> 0011b */
  152.         " addi    -2,%1,%1\n"
  153.         " extru,=  %0,31,1,%%r0\n"    /* check last bit */
  154.         " addi    -1,%1,%1\n"
  155.             : "+r" (x), "=r" (ret) );
  156.     return ret;
  157. }
  158.  
  159. #include <asm-generic/bitops/ffz.h>
  160.  
  161. /*
  162.  * ffs: find first bit set. returns 1 to BITS_PER_LONG or 0 (if none set)
  163.  * This is defined the same way as the libc and compiler builtin
  164.  * ffs routines, therefore differs in spirit from the above ffz (man ffs).
  165.  */
  166. static __inline__ int ffs(int x)
  167. {
  168.     return x ? (__ffs((unsigned long)x) + 1) : 0;
  169. }
  170.  
  171. /*
  172.  * fls: find last (most significant) bit set.
  173.  * fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
  174.  */
  175.  
  176. static __inline__ int fls(int x)
  177. {
  178.     int ret;
  179.     if (!x)
  180.         return 0;
  181.  
  182.     __asm__(
  183.     "    ldi        1,%1\n"
  184.     "    extru,<>    %0,15,16,%%r0\n"
  185.     "    zdep,TR        %0,15,16,%0\n"        /* xxxx0000 */
  186.     "    addi        16,%1,%1\n"
  187.     "    extru,<>    %0,7,8,%%r0\n"
  188.     "    zdep,TR        %0,23,24,%0\n"        /* xx000000 */
  189.     "    addi        8,%1,%1\n"
  190.     "    extru,<>    %0,3,4,%%r0\n"
  191.     "    zdep,TR        %0,27,28,%0\n"        /* x0000000 */
  192.     "    addi        4,%1,%1\n"
  193.     "    extru,<>    %0,1,2,%%r0\n"
  194.     "    zdep,TR        %0,29,30,%0\n"        /* y0000000 (y&3 = 0) */
  195.     "    addi        2,%1,%1\n"
  196.     "    extru,=        %0,0,1,%%r0\n"
  197.     "    addi        1,%1,%1\n"        /* if y & 8, add 1 */
  198.         : "+r" (x), "=r" (ret) );
  199.  
  200.     return ret;
  201. }
  202.  
  203. #include <asm-generic/bitops/fls64.h>
  204. #include <asm-generic/bitops/hweight.h>
  205. #include <asm-generic/bitops/sched.h>
  206.  
  207. #endif /* __KERNEL__ */
  208.  
  209. #include <asm-generic/bitops/find.h>
  210.  
  211. #ifdef __KERNEL__
  212.  
  213. #include <asm-generic/bitops/ext2-non-atomic.h>
  214.  
  215. /* '3' is bits per byte */
  216. #define LE_BYTE_ADDR ((sizeof(unsigned long) - 1) << 3)
  217.  
  218. #define ext2_set_bit_atomic(l,nr,addr) \
  219.         test_and_set_bit((nr)   ^ LE_BYTE_ADDR, (unsigned long *)addr)
  220. #define ext2_clear_bit_atomic(l,nr,addr) \
  221.         test_and_clear_bit( (nr) ^ LE_BYTE_ADDR, (unsigned long *)addr)
  222.  
  223. #endif    /* __KERNEL__ */
  224.  
  225. #include <asm-generic/bitops/minix-le.h>
  226.  
  227. #endif /* _PARISC_BITOPS_H */
  228.