bitops.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * PowerPC64 atomic bit operations.
  3.  * Dave Engebretsen, Todd Inglett, Don Reed, Pat McCarthy, Peter Bergner,
  4.  * Anton Blanchard
  5.  *
  6.  * Originally taken from the 32b PPC code.  Modified to use 64b values for
  7.  * the various counters & memory references.
  8.  *
  9.  * Bitops are odd when viewed on big-endian systems.  They were designed
  10.  * on little endian so the size of the bitset doesn't matter (low order bytes
  11.  * come first) as long as the bit in question is valid.
  12.  *
  13.  * Bits are "tested" often using the C expression (val & (1<<nr)) so we do
  14.  * our best to stay compatible with that.  The assumption is that val will
  15.  * be unsigned long for such tests.  As such, we assume the bits are stored
  16.  * as an array of unsigned long (the usual case is a single unsigned long,
  17.  * of course).  Here's an example bitset with bit numbering:
  18.  *
  19.  *   |63..........0|127........64|195.......128|255.......196|
  20.  *
  21.  * This leads to a problem. If an int, short or char is passed as a bitset
  22.  * it will be a bad memory reference since we want to store in chunks
  23.  * of unsigned long (64 bits here) size.
  24.  *
  25.  * This program is free software; you can redistribute it and/or
  26.  * modify it under the terms of the GNU General Public License
  27.  * as published by the Free Software Foundation; either version
  28.  * 2 of the License, or (at your option) any later version.
  29.  */
  30. #ifndef _PPC64_BITOPS_H
  31. #define _PPC64_BITOPS_H
  32. #ifdef __KERNEL__
  33. #include <asm/byteorder.h>
  34. #include <asm/memory.h>
  35. /*
  36.  * clear_bit doesn't imply a memory barrier
  37.  */
  38. #define smp_mb__before_clear_bit() smp_mb()
  39. #define smp_mb__after_clear_bit() smp_mb()
  40. static __inline__ int test_bit(unsigned long nr, __const__ volatile void *addr)
  41. {
  42. return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63)));
  43. }
  44. static __inline__ void set_bit(unsigned long nr, volatile void *addr)
  45. {
  46. unsigned long old;
  47. unsigned long mask = 1UL << (nr & 0x3f);
  48. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  49. __asm__ __volatile__(
  50. "1: ldarx %0,0,%3 # set_bitn
  51. or %0,%0,%2n
  52. stdcx. %0,0,%3n
  53. bne- 1b"
  54. : "=&r" (old), "=m" (*p)
  55. : "r" (mask), "r" (p), "m" (*p)
  56. : "cc");
  57. }
  58. static __inline__ void clear_bit(unsigned long nr, volatile void *addr)
  59. {
  60. unsigned long old;
  61. unsigned long mask = 1UL << (nr & 0x3f);
  62. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  63. __asm__ __volatile__(
  64. "1: ldarx %0,0,%3 # clear_bitn
  65. andc %0,%0,%2n
  66. stdcx. %0,0,%3n
  67. bne- 1b"
  68. : "=&r" (old), "=m" (*p)
  69. : "r" (mask), "r" (p), "m" (*p)
  70. : "cc");
  71. }
  72. static __inline__ void change_bit(unsigned long nr, volatile void *addr)
  73. {
  74. unsigned long old;
  75. unsigned long mask = 1UL << (nr & 0x3f);
  76. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  77. __asm__ __volatile__(
  78. "1: ldarx %0,0,%3 # change_bitn
  79. xor %0,%0,%2n
  80. stdcx. %0,0,%3n
  81. bne- 1b"
  82. : "=&r" (old), "=m" (*p)
  83. : "r" (mask), "r" (p), "m" (*p)
  84. : "cc");
  85. }
  86. static __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr)
  87. {
  88. unsigned long old, t;
  89. unsigned long mask = 1UL << (nr & 0x3f);
  90. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  91. __asm__ __volatile__(
  92. EIEIO_ON_SMP
  93. "1: ldarx %0,0,%3 # test_and_set_bitn
  94. or %1,%0,%2 n
  95. stdcx. %1,0,%3 n
  96. bne- 1b"
  97. ISYNC_ON_SMP
  98. : "=&r" (old), "=&r" (t)
  99. : "r" (mask), "r" (p)
  100. : "cc", "memory");
  101. return (old & mask) != 0;
  102. }
  103. static __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr)
  104. {
  105. unsigned long old, t;
  106. unsigned long mask = 1UL << (nr & 0x3f);
  107. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  108. __asm__ __volatile__(
  109. EIEIO_ON_SMP
  110. "1: ldarx %0,0,%3 # test_and_clear_bitn
  111. andc %1,%0,%2n
  112. stdcx. %1,0,%3n
  113. bne- 1b"
  114. ISYNC_ON_SMP
  115. : "=&r" (old), "=&r" (t)
  116. : "r" (mask), "r" (p)
  117. : "cc", "memory");
  118. return (old & mask) != 0;
  119. }
  120. static __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
  121. {
  122. unsigned long old, t;
  123. unsigned long mask = 1UL << (nr & 0x3f);
  124. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  125. __asm__ __volatile__(
  126. EIEIO_ON_SMP
  127. "1: ldarx %0,0,%3 # test_and_change_bitn
  128. xor %1,%0,%2n
  129. stdcx. %1,0,%3n
  130. bne- 1b"
  131. ISYNC_ON_SMP
  132. : "=&r" (old), "=&r" (t)
  133. : "r" (mask), "r" (p)
  134. : "cc", "memory");
  135. return (old & mask) != 0;
  136. }
  137. /*
  138.  * non-atomic versions
  139.  */
  140. static __inline__ void __set_bit(unsigned long nr, volatile void *addr)
  141. {
  142. unsigned long mask = 1UL << (nr & 0x3f);
  143. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  144. *p |= mask;
  145. }
  146. static __inline__ void __clear_bit(unsigned long nr, volatile void *addr)
  147. {
  148. unsigned long mask = 1UL << (nr & 0x3f);
  149. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  150. *p &= ~mask;
  151. }
  152. static __inline__ void __change_bit(unsigned long nr, volatile void *addr)
  153. {
  154. unsigned long mask = 1UL << (nr & 0x3f);
  155. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  156. *p ^= mask;
  157. }
  158. static __inline__ int __test_and_set_bit(unsigned long nr, volatile void *addr)
  159. {
  160. unsigned long mask = 1UL << (nr & 0x3f);
  161. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  162. unsigned long old = *p;
  163. *p = old | mask;
  164. return (old & mask) != 0;
  165. }
  166. static __inline__ int __test_and_clear_bit(unsigned long nr, volatile void *addr)
  167. {
  168. unsigned long mask = 1UL << (nr & 0x3f);
  169. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  170. unsigned long old = *p;
  171. *p = old & ~mask;
  172. return (old & mask) != 0;
  173. }
  174. static __inline__ int __test_and_change_bit(unsigned long nr, volatile void *addr)
  175. {
  176. unsigned long mask = 1UL << (nr & 0x3f);
  177. unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  178. unsigned long old = *p;
  179. *p = old ^ mask;
  180. return (old & mask) != 0;
  181. }
  182. /*
  183.  * Return the zero-based bit position (from RIGHT TO LEFT, 63 -> 0) of the
  184.  * most significant (left-most) 1-bit in a double word.
  185.  */
  186. static __inline__ int __ilog2(unsigned long x)
  187. {
  188. int lz;
  189. asm ("cntlzd %0,%1" : "=r" (lz) : "r" (x));
  190. return 63 - lz;
  191. }
  192. /* Return the zero-based bit position
  193.  *  from RIGHT TO LEFT  63 --> 0
  194.  *   of the most significant (left-most) 1-bit in an 8-byte area.
  195.  */
  196. static __inline__ long cnt_trailing_zeros(unsigned long mask)
  197. {
  198.         long cnt;
  199. asm(
  200. " addi %0,%1,-1 n
  201. andc %0,%0,%1 n
  202. cntlzd %0,%0 n
  203. subfic %0,%0,64"
  204. : "=r" (cnt)
  205. : "r" (mask));
  206. return cnt;
  207. }
  208. /*
  209.  * ffz = Find First Zero in word. Undefined if no zero exists,
  210.  *    Determines the bit position of the LEAST significant
  211.  *    (rightmost) 0 bit in the specified DOUBLE-WORD.
  212.  *    The returned bit position will be zero-based, starting
  213.  *    from the right side (63 - 0).
  214.  *    the code should check against ~0UL first..
  215.  */
  216. static __inline__ unsigned long ffz(unsigned long x)
  217. {
  218. u32  tempRC;
  219. /* Change all of x's 1s to 0s and 0s to 1s in x.
  220.  * And insure at least 1 zero exists in the 8 byte area.
  221.  */
  222. if ((x = ~x) == 0)
  223. /* no zero exists anywhere in the 8 byte area. */
  224. return 64;
  225. /* Calculate the bit position of the least significant '1' bit in x
  226.  * (since x has been changed this will actually be the least
  227.  * significant '0' bit in the original x).
  228.  * Note: (x & -x) gives us a mask that is the LEAST significant
  229.  * (RIGHT-most) 1-bit of the value in x.
  230.  */
  231. tempRC = __ilog2(x & -x);
  232. return tempRC;
  233. }
  234. /*
  235.  * ffs: find first bit set. This is defined the same way as
  236.  * the libc and compiler builtin ffs routines, therefore
  237.  * differs in spirit from the above ffz (man ffs).
  238.  */
  239. static __inline__ int ffs(int x)
  240. {
  241. int result = ffz(~x);
  242. return x ? result+1 : 0;
  243. }
  244. /*
  245.  * hweightN: returns the hamming weight (i.e. the number
  246.  * of bits set) of a N-bit word
  247.  */
  248. #define hweight32(x) generic_hweight32(x)
  249. #define hweight16(x) generic_hweight16(x)
  250. #define hweight8(x) generic_hweight8(x)
  251. extern unsigned long find_next_zero_bit(void * addr, unsigned long size,
  252. unsigned long offset);
  253. /*
  254.  * The optimizer actually does good code for this case..
  255.  */
  256. #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
  257. /* Bitmap functions for the ext2 filesystem. */
  258. #define _EXT2_HAVE_ASM_BITOPS_
  259. static __inline__ int ext2_set_bit(int nr, void* addr)
  260. {
  261. /* This method needs to take into account the fact that the ext2 file system represents
  262.  *  it's bitmaps as "little endian" unsigned integers.
  263.  * Note: this method is not atomic, but ext2 does not need it to be.
  264.  */
  265. int mask;
  266. int oldbit;
  267. unsigned char* ADDR = (unsigned char*) addr;
  268. /* Determine the BYTE containing the specified bit
  269.  * (nr) - important as if we go to a byte there are no
  270.  * little endian concerns.
  271.  */
  272. ADDR += nr >> 3;
  273. mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
  274. oldbit = *ADDR & mask;  /* Save the bit's previous value. */
  275. *ADDR |= mask;  /* Turn the bit on. */
  276. return oldbit;  /* Return the bit's previous value. */
  277. }
  278. static __inline__ int ext2_clear_bit(int nr, void* addr)
  279. {
  280. /* This method needs to take into account the fact that the ext2 file system represents
  281.  * | it's bitmaps as "little endian" unsigned integers.
  282.  * Note: this method is not atomic, but ext2 does not need it to be.
  283.  */
  284.         int     mask;
  285.         int oldbit;
  286.         unsigned char* ADDR = (unsigned char*) addr;
  287. /* Determine the BYTE containing the specified bit (nr)
  288.  *  - important as if we go to a byte there are no little endian concerns.
  289.  */
  290.         ADDR += nr >> 3;
  291.         mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
  292.         oldbit = *ADDR & mask;  /* Save the bit's previous value. */
  293.         *ADDR = *ADDR & ~mask;  /* Turn the bit off. */
  294.         return oldbit;  /* Return the bit's previous value. */
  295. }
  296. static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
  297. {
  298. /* This method needs to take into account the fact that the ext2 file system represents
  299.  * | it's bitmaps as "little endian" unsigned integers.
  300.  * Determine the BYTE containing the specified bit (nr),
  301.  *   then shift to the right the correct number of bits and return that bit's value.
  302.  */
  303. __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
  304. return (ADDR[nr >> 3] >> (nr & 7)) & 1;
  305. }
  306. /* Returns the bit position of the most significant 1 bit in a WORD. */
  307. static __inline__ int ext2_ilog2(unsigned int x)
  308. {
  309.         int lz;
  310.         asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
  311.         return 31 - lz;
  312. }
  313. /* ext2_ffz = ext2's Find First Zero.
  314.  *    Determines the bit position of the LEAST significant (rightmost) 0 bit in the specified WORD.
  315.  *    The returned bit position will be zero-based, starting from the right side (31 - 0).
  316.  */
  317. static __inline__ int ext2_ffz(unsigned int x)
  318. {
  319. u32  tempRC;
  320. /* Change all of x's 1s to 0s and 0s to 1s in x.  And insure at least 1 zero exists in the word. */
  321. if ((x = ~x) == 0)
  322. /* no zero exists anywhere in the 4 byte area. */
  323. return 32;
  324. /* Calculate the bit position of the least significant '1' bit in x
  325.  * (since x has been changed this will actually be the least
  326.  * significant '0' bit in the original x).
  327.  * Note: (x & -x) gives us a mask that is the LEAST significant
  328.  * (RIGHT-most) 1-bit of the value in x.
  329.  */
  330. tempRC = ext2_ilog2(x & -x);
  331. return tempRC;
  332. }
  333. static __inline__ u32 ext2_find_next_zero_bit(void* addr, u32 size, u32 offset)
  334. {
  335. /* This method needs to take into account the fact that the ext2 file system represents
  336.  * | it's bitmaps as "little endian" unsigned integers.
  337.  */
  338.         unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
  339.         unsigned int result = offset & ~31;
  340.         unsigned int tmp;
  341.         if (offset >= size)
  342.                 return size;
  343.         size -= result;
  344.         offset &= 31;
  345.         if (offset) {
  346.                 tmp = cpu_to_le32p(p++);
  347.                 tmp |= ~0U >> (32-offset); /* bug or feature ? */
  348.                 if (size < 32)
  349.                         goto found_first;
  350.                 if (tmp != ~0)
  351.                         goto found_middle;
  352.                 size -= 32;
  353.                 result += 32;
  354.         }
  355.         while (size >= 32) {
  356.                 if ((tmp = cpu_to_le32p(p++)) != ~0)
  357.                         goto found_middle;
  358.                 result += 32;
  359.                 size -= 32;
  360.         }
  361.         if (!size)
  362.                 return result;
  363.         tmp = cpu_to_le32p(p);
  364. found_first:
  365.         tmp |= ~0 << size;
  366.         if (tmp == ~0)          /* Are any bits zero? */
  367.                 return result + size; /* Nope. */
  368. found_middle:
  369.         return result + ext2_ffz(tmp);
  370. }
  371. #define ext2_find_first_zero_bit(addr, size) ext2_find_next_zero_bit((addr), (size), 0)
  372. #endif /* __KERNEL__ */
  373. #endif /* _PPC64_BITOPS_H */