bitops.h
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.bitops.h 1.9 05/26/01 14:48:14 paulus
  3.  */
  4. /*
  5.  * bitops.h: Bit string operations on the ppc
  6.  */
  7. #ifdef __KERNEL__
  8. #ifndef _PPC_BITOPS_H
  9. #define _PPC_BITOPS_H
  10. #include <linux/config.h>
  11. #include <asm/byteorder.h>
  12. /*
  13.  * The test_and_*_bit operations are taken to imply a memory barrier
  14.  * on SMP systems.
  15.  */
  16. #ifdef CONFIG_SMP
  17. #define SMP_WMB "eieion"
  18. #define SMP_MB "nsync"
  19. #else
  20. #define SMP_WMB
  21. #define SMP_MB
  22. #endif /* CONFIG_SMP */
  23. /*
  24.  * These used to be if'd out here because using : "cc" as a constraint
  25.  * resulted in errors from egcs.  Things appear to be OK with gcc-2.95.
  26.  */
  27. static __inline__ void set_bit(int nr, volatile void * addr)
  28. {
  29. unsigned long old;
  30. unsigned long mask = 1 << (nr & 0x1f);
  31. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  32. __asm__ __volatile__("n
  33. 1: lwarx %0,0,%3 n
  34. or %0,%0,%2 n
  35. stwcx. %0,0,%3 n
  36. bne- 1b"
  37. : "=&r" (old), "=m" (*p)
  38. : "r" (mask), "r" (p), "m" (*p)
  39. : "cc" );
  40. }
  41. /*
  42.  * non-atomic version
  43.  */
  44. static __inline__ void __set_bit(int nr, volatile void *addr)
  45. {
  46. unsigned long mask = 1 << (nr & 0x1f);
  47. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  48. *p |= mask;
  49. }
  50. /*
  51.  * clear_bit doesn't imply a memory barrier
  52.  */
  53. #define smp_mb__before_clear_bit() smp_mb()
  54. #define smp_mb__after_clear_bit() smp_mb()
  55. static __inline__ void clear_bit(int nr, volatile void *addr)
  56. {
  57. unsigned long old;
  58. unsigned long mask = 1 << (nr & 0x1f);
  59. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  60. __asm__ __volatile__("n
  61. 1: lwarx %0,0,%3 n
  62. andc %0,%0,%2 n
  63. stwcx. %0,0,%3 n
  64. bne- 1b"
  65. : "=&r" (old), "=m" (*p)
  66. : "r" (mask), "r" (p), "m" (*p)
  67. : "cc");
  68. }
  69. /*
  70.  * non-atomic version
  71.  */
  72. static __inline__ void __clear_bit(int nr, volatile void *addr)
  73. {
  74. unsigned long mask = 1 << (nr & 0x1f);
  75. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  76. *p &= ~mask;
  77. }
  78. static __inline__ void change_bit(int nr, volatile void *addr)
  79. {
  80. unsigned long old;
  81. unsigned long mask = 1 << (nr & 0x1f);
  82. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  83. __asm__ __volatile__("n
  84. 1: lwarx %0,0,%3 n
  85. xor %0,%0,%2 n
  86. stwcx. %0,0,%3 n
  87. bne- 1b"
  88. : "=&r" (old), "=m" (*p)
  89. : "r" (mask), "r" (p), "m" (*p)
  90. : "cc");
  91. }
  92. /*
  93.  * non-atomic version
  94.  */
  95. static __inline__ void __change_bit(int nr, volatile void *addr)
  96. {
  97. unsigned long mask = 1 << (nr & 0x1f);
  98. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  99. *p ^= mask;
  100. }
  101. /*
  102.  * test_and_*_bit do imply a memory barrier (?)
  103.  */
  104. static __inline__ int test_and_set_bit(int nr, volatile void *addr)
  105. {
  106. unsigned int old, t;
  107. unsigned int mask = 1 << (nr & 0x1f);
  108. volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
  109. __asm__ __volatile__(SMP_WMB "n
  110. 1: lwarx %0,0,%4 n
  111. or %1,%0,%3 n
  112. stwcx. %1,0,%4 n
  113. bne 1b"
  114. SMP_MB
  115. : "=&r" (old), "=&r" (t), "=m" (*p)
  116. : "r" (mask), "r" (p), "m" (*p)
  117. : "cc", "memory");
  118. return (old & mask) != 0;
  119. }
  120. /*
  121.  * non-atomic version
  122.  */
  123. static __inline__ int __test_and_set_bit(int nr, volatile void *addr)
  124. {
  125. unsigned long mask = 1 << (nr & 0x1f);
  126. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  127. unsigned long old = *p;
  128. *p = old | mask;
  129. return (old & mask) != 0;
  130. }
  131. static __inline__ int test_and_clear_bit(int nr, volatile void *addr)
  132. {
  133. unsigned int old, t;
  134. unsigned int mask = 1 << (nr & 0x1f);
  135. volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
  136. __asm__ __volatile__(SMP_WMB "n
  137. 1: lwarx %0,0,%4 n
  138. andc %1,%0,%3 n
  139. stwcx. %1,0,%4 n
  140. bne 1b"
  141. SMP_MB
  142. : "=&r" (old), "=&r" (t), "=m" (*p)
  143. : "r" (mask), "r" (p), "m" (*p)
  144. : "cc", "memory");
  145. return (old & mask) != 0;
  146. }
  147. /*
  148.  * non-atomic version
  149.  */
  150. static __inline__ int __test_and_clear_bit(int nr, volatile void *addr)
  151. {
  152. unsigned long mask = 1 << (nr & 0x1f);
  153. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  154. unsigned long old = *p;
  155. *p = old & ~mask;
  156. return (old & mask) != 0;
  157. }
  158. static __inline__ int test_and_change_bit(int nr, volatile void *addr)
  159. {
  160. unsigned int old, t;
  161. unsigned int mask = 1 << (nr & 0x1f);
  162. volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
  163. __asm__ __volatile__(SMP_WMB "n
  164. 1: lwarx %0,0,%4 n
  165. xor %1,%0,%3 n
  166. stwcx. %1,0,%4 n
  167. bne 1b"
  168. SMP_MB
  169. : "=&r" (old), "=&r" (t), "=m" (*p)
  170. : "r" (mask), "r" (p), "m" (*p)
  171. : "cc", "memory");
  172. return (old & mask) != 0;
  173. }
  174. /*
  175.  * non-atomic version
  176.  */
  177. static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
  178. {
  179. unsigned long mask = 1 << (nr & 0x1f);
  180. unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
  181. unsigned long old = *p;
  182. *p = old ^ mask;
  183. return (old & mask) != 0;
  184. }
  185. static __inline__ int test_bit(int nr, __const__ volatile void *addr)
  186. {
  187. __const__ unsigned int *p = (__const__ unsigned int *) addr;
  188. return ((p[nr >> 5] >> (nr & 0x1f)) & 1) != 0;
  189. }
  190. /* Return the bit position of the most significant 1 bit in a word */
  191. static __inline__ int __ilog2(unsigned int x)
  192. {
  193. int lz;
  194. asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
  195. return 31 - lz;
  196. }
  197. static __inline__ int ffz(unsigned int x)
  198. {
  199. if ((x = ~x) == 0)
  200. return 32;
  201. return __ilog2(x & -x);
  202. }
  203. #ifdef __KERNEL__
  204. /*
  205.  * ffs: find first bit set. This is defined the same way as
  206.  * the libc and compiler builtin ffs routines, therefore
  207.  * differs in spirit from the above ffz (man ffs).
  208.  */
  209. static __inline__ int ffs(int x)
  210. {
  211. return __ilog2(x & -x) + 1;
  212. }
  213. /*
  214.  * hweightN: returns the hamming weight (i.e. the number
  215.  * of bits set) of a N-bit word
  216.  */
  217. #define hweight32(x) generic_hweight32(x)
  218. #define hweight16(x) generic_hweight16(x)
  219. #define hweight8(x) generic_hweight8(x)
  220. #endif /* __KERNEL__ */
  221. /*
  222.  * This implementation of find_{first,next}_zero_bit was stolen from
  223.  * Linus' asm-alpha/bitops.h.
  224.  */
  225. #define find_first_zero_bit(addr, size) 
  226. find_next_zero_bit((addr), (size), 0)
  227. static __inline__ unsigned long find_next_zero_bit(void * addr,
  228. unsigned long size, unsigned long offset)
  229. {
  230. unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
  231. unsigned int result = offset & ~31UL;
  232. unsigned int tmp;
  233. if (offset >= size)
  234. return size;
  235. size -= result;
  236. offset &= 31UL;
  237. if (offset) {
  238. tmp = *p++;
  239. tmp |= ~0UL >> (32-offset);
  240. if (size < 32)
  241. goto found_first;
  242. if (tmp != ~0U)
  243. goto found_middle;
  244. size -= 32;
  245. result += 32;
  246. }
  247. while (size >= 32) {
  248. if ((tmp = *p++) != ~0U)
  249. goto found_middle;
  250. result += 32;
  251. size -= 32;
  252. }
  253. if (!size)
  254. return result;
  255. tmp = *p;
  256. found_first:
  257. tmp |= ~0UL << size;
  258. if (tmp == ~0UL)        /* Are any bits zero? */
  259. return result + size; /* Nope. */
  260. found_middle:
  261. return result + ffz(tmp);
  262. }
  263. #ifdef __KERNEL__
  264. #define ext2_set_bit(nr, addr) __test_and_set_bit((nr) ^ 0x18, addr)
  265. #define ext2_clear_bit(nr, addr) __test_and_clear_bit((nr) ^ 0x18, addr)
  266. static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
  267. {
  268. __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
  269. return (ADDR[nr >> 3] >> (nr & 7)) & 1;
  270. }
  271. /*
  272.  * This implementation of ext2_find_{first,next}_zero_bit was stolen from
  273.  * Linus' asm-alpha/bitops.h and modified for a big-endian machine.
  274.  */
  275. #define ext2_find_first_zero_bit(addr, size) 
  276.         ext2_find_next_zero_bit((addr), (size), 0)
  277. static __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
  278. unsigned long size, unsigned long offset)
  279. {
  280. unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
  281. unsigned int result = offset & ~31UL;
  282. unsigned int tmp;
  283. if (offset >= size)
  284. return size;
  285. size -= result;
  286. offset &= 31UL;
  287. if (offset) {
  288. tmp = cpu_to_le32p(p++);
  289. tmp |= ~0UL >> (32-offset);
  290. if (size < 32)
  291. goto found_first;
  292. if (tmp != ~0U)
  293. goto found_middle;
  294. size -= 32;
  295. result += 32;
  296. }
  297. while (size >= 32) {
  298. if ((tmp = cpu_to_le32p(p++)) != ~0U)
  299. goto found_middle;
  300. result += 32;
  301. size -= 32;
  302. }
  303. if (!size)
  304. return result;
  305. tmp = cpu_to_le32p(p);
  306. found_first:
  307. tmp |= ~0U << size;
  308. if (tmp == ~0UL)        /* Are any bits zero? */
  309. return result + size; /* Nope. */
  310. found_middle:
  311. return result + ffz(tmp);
  312. }
  313. /* Bitmap functions for the minix filesystem.  */
  314. #define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr)
  315. #define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr))
  316. #define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
  317. #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
  318. #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
  319. #endif /* __KERNEL__ */
  320. #endif /* _PPC_BITOPS_H */
  321. #endif /* __KERNEL__ */