1 /* 2 * bitops.h: Bit string operations on the ppc 3 */ 4 5 #ifndef _PPC_BITOPS_H 6 #define _PPC_BITOPS_H 7 8 #include <asm/byteorder.h> 9 #include <asm-generic/bitops/__ffs.h> 10 11 extern void set_bit(int nr, volatile void *addr); 12 extern void clear_bit(int nr, volatile void *addr); 13 extern void change_bit(int nr, volatile void *addr); 14 extern int test_and_set_bit(int nr, volatile void *addr); 15 extern int test_and_clear_bit(int nr, volatile void *addr); 16 extern int test_and_change_bit(int nr, volatile void *addr); 17 18 /* 19 * Arguably these bit operations don't imply any memory barrier or 20 * SMP ordering, but in fact a lot of drivers expect them to imply 21 * both, since they do on x86 cpus. 22 */ 23 #ifdef CONFIG_SMP 24 #define SMP_WMB "eieio\n" 25 #define SMP_MB "\nsync" 26 #else 27 #define SMP_WMB 28 #define SMP_MB 29 #endif /* CONFIG_SMP */ 30 31 #define __INLINE_BITOPS 1 32 33 #if __INLINE_BITOPS 34 /* 35 * These used to be if'd out here because using : "cc" as a constraint 36 * resulted in errors from egcs. Things may be OK with gcc-2.95. 37 */ 38 extern __inline__ void set_bit(int nr, volatile void * addr) 39 { 40 unsigned long old; 41 unsigned long mask = 1 << (nr & 0x1f); 42 unsigned long *p = ((unsigned long *)addr) + (nr >> 5); 43 44 __asm__ __volatile__(SMP_WMB "\ 45 1: lwarx %0,0,%3\n\ 46 or %0,%0,%2\n\ 47 stwcx. %0,0,%3\n\ 48 bne 1b" 49 SMP_MB 50 : "=&r" (old), "=m" (*p) 51 : "r" (mask), "r" (p), "m" (*p) 52 : "cc" ); 53 } 54 55 extern __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 61 __asm__ __volatile__(SMP_WMB "\ 62 1: lwarx %0,0,%3\n\ 63 andc %0,%0,%2\n\ 64 stwcx. %0,0,%3\n\ 65 bne 1b" 66 SMP_MB 67 : "=&r" (old), "=m" (*p) 68 : "r" (mask), "r" (p), "m" (*p) 69 : "cc"); 70 } 71 72 extern __inline__ void change_bit(int nr, volatile void *addr) 73 { 74 unsigned long old; 75 unsigned long mask = 1 << (nr & 0x1f); 76 unsigned long *p = ((unsigned long *)addr) + (nr >> 5); 77 78 __asm__ __volatile__(SMP_WMB "\ 79 1: lwarx %0,0,%3\n\ 80 xor %0,%0,%2\n\ 81 stwcx. %0,0,%3\n\ 82 bne 1b" 83 SMP_MB 84 : "=&r" (old), "=m" (*p) 85 : "r" (mask), "r" (p), "m" (*p) 86 : "cc"); 87 } 88 89 extern __inline__ int test_and_set_bit(int nr, volatile void *addr) 90 { 91 unsigned int old, t; 92 unsigned int mask = 1 << (nr & 0x1f); 93 volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); 94 95 __asm__ __volatile__(SMP_WMB "\ 96 1: lwarx %0,0,%4\n\ 97 or %1,%0,%3\n\ 98 stwcx. %1,0,%4\n\ 99 bne 1b" 100 SMP_MB 101 : "=&r" (old), "=&r" (t), "=m" (*p) 102 : "r" (mask), "r" (p), "m" (*p) 103 : "cc"); 104 105 return (old & mask) != 0; 106 } 107 108 extern __inline__ int test_and_clear_bit(int nr, volatile void *addr) 109 { 110 unsigned int old, t; 111 unsigned int mask = 1 << (nr & 0x1f); 112 volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); 113 114 __asm__ __volatile__(SMP_WMB "\ 115 1: lwarx %0,0,%4\n\ 116 andc %1,%0,%3\n\ 117 stwcx. %1,0,%4\n\ 118 bne 1b" 119 SMP_MB 120 : "=&r" (old), "=&r" (t), "=m" (*p) 121 : "r" (mask), "r" (p), "m" (*p) 122 : "cc"); 123 124 return (old & mask) != 0; 125 } 126 127 extern __inline__ int test_and_change_bit(int nr, volatile void *addr) 128 { 129 unsigned int old, t; 130 unsigned int mask = 1 << (nr & 0x1f); 131 volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5); 132 133 __asm__ __volatile__(SMP_WMB "\ 134 1: lwarx %0,0,%4\n\ 135 xor %1,%0,%3\n\ 136 stwcx. %1,0,%4\n\ 137 bne 1b" 138 SMP_MB 139 : "=&r" (old), "=&r" (t), "=m" (*p) 140 : "r" (mask), "r" (p), "m" (*p) 141 : "cc"); 142 143 return (old & mask) != 0; 144 } 145 #endif /* __INLINE_BITOPS */ 146 147 extern __inline__ int test_bit(int nr, __const__ volatile void *addr) 148 { 149 __const__ unsigned int *p = (__const__ unsigned int *) addr; 150 151 return ((p[nr >> 5] >> (nr & 0x1f)) & 1) != 0; 152 } 153 154 /* Return the bit position of the most significant 1 bit in a word */ 155 /* - the result is undefined when x == 0 */ 156 extern __inline__ int __ilog2(unsigned int x) 157 { 158 int lz; 159 160 asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); 161 return 31 - lz; 162 } 163 164 extern __inline__ int ffz(unsigned int x) 165 { 166 if ((x = ~x) == 0) 167 return 32; 168 return __ilog2(x & -x); 169 } 170 171 /* 172 * fls: find last (most-significant) bit set. 173 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 174 * 175 * On powerpc, __ilog2(0) returns -1, but this is not safe in general 176 */ 177 static __inline__ int fls(unsigned int x) 178 { 179 return __ilog2(x) + 1; 180 } 181 #define PLATFORM_FLS 182 183 /** 184 * fls64 - find last set bit in a 64-bit word 185 * @x: the word to search 186 * 187 * This is defined in a similar way as the libc and compiler builtin 188 * ffsll, but returns the position of the most significant set bit. 189 * 190 * fls64(value) returns 0 if value is 0 or the position of the last 191 * set bit if value is nonzero. The last (most significant) bit is 192 * at position 64. 193 */ 194 #if BITS_PER_LONG == 32 195 static inline int fls64(__u64 x) 196 { 197 __u32 h = x >> 32; 198 if (h) 199 return fls(h) + 32; 200 return fls(x); 201 } 202 #elif BITS_PER_LONG == 64 203 static inline int fls64(__u64 x) 204 { 205 if (x == 0) 206 return 0; 207 return __ilog2(x) + 1; 208 } 209 #else 210 #error BITS_PER_LONG not 32 or 64 211 #endif 212 213 #ifdef __KERNEL__ 214 215 /* 216 * ffs: find first bit set. This is defined the same way as 217 * the libc and compiler builtin ffs routines, therefore 218 * differs in spirit from the above ffz (man ffs). 219 */ 220 extern __inline__ int ffs(int x) 221 { 222 return __ilog2(x & -x) + 1; 223 } 224 #define PLATFORM_FFS 225 226 /* 227 * hweightN: returns the hamming weight (i.e. the number 228 * of bits set) of a N-bit word 229 */ 230 231 #define hweight32(x) generic_hweight32(x) 232 #define hweight16(x) generic_hweight16(x) 233 #define hweight8(x) generic_hweight8(x) 234 235 #endif /* __KERNEL__ */ 236 237 /* 238 * This implementation of find_{first,next}_zero_bit was stolen from 239 * Linus' asm-alpha/bitops.h. 240 */ 241 #define find_first_zero_bit(addr, size) \ 242 find_next_zero_bit((addr), (size), 0) 243 244 extern __inline__ unsigned long find_next_zero_bit(void * addr, 245 unsigned long size, unsigned long offset) 246 { 247 unsigned int * p = ((unsigned int *) addr) + (offset >> 5); 248 unsigned int result = offset & ~31UL; 249 unsigned int tmp; 250 251 if (offset >= size) 252 return size; 253 size -= result; 254 offset &= 31UL; 255 if (offset) { 256 tmp = *p++; 257 tmp |= ~0UL >> (32-offset); 258 if (size < 32) 259 goto found_first; 260 if (tmp != ~0U) 261 goto found_middle; 262 size -= 32; 263 result += 32; 264 } 265 while (size >= 32) { 266 if ((tmp = *p++) != ~0U) 267 goto found_middle; 268 result += 32; 269 size -= 32; 270 } 271 if (!size) 272 return result; 273 tmp = *p; 274 found_first: 275 tmp |= ~0UL << size; 276 found_middle: 277 return result + ffz(tmp); 278 } 279 280 281 #define _EXT2_HAVE_ASM_BITOPS_ 282 283 #ifdef __KERNEL__ 284 /* 285 * test_and_{set,clear}_bit guarantee atomicity without 286 * disabling interrupts. 287 */ 288 #define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x18, addr) 289 #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x18, addr) 290 291 #else 292 extern __inline__ int ext2_set_bit(int nr, void * addr) 293 { 294 int mask; 295 unsigned char *ADDR = (unsigned char *) addr; 296 int oldbit; 297 298 ADDR += nr >> 3; 299 mask = 1 << (nr & 0x07); 300 oldbit = (*ADDR & mask) ? 1 : 0; 301 *ADDR |= mask; 302 return oldbit; 303 } 304 305 extern __inline__ int ext2_clear_bit(int nr, void * addr) 306 { 307 int mask; 308 unsigned char *ADDR = (unsigned char *) addr; 309 int oldbit; 310 311 ADDR += nr >> 3; 312 mask = 1 << (nr & 0x07); 313 oldbit = (*ADDR & mask) ? 1 : 0; 314 *ADDR = *ADDR & ~mask; 315 return oldbit; 316 } 317 #endif /* __KERNEL__ */ 318 319 extern __inline__ int ext2_test_bit(int nr, __const__ void * addr) 320 { 321 __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; 322 323 return (ADDR[nr >> 3] >> (nr & 7)) & 1; 324 } 325 326 /* 327 * This implementation of ext2_find_{first,next}_zero_bit was stolen from 328 * Linus' asm-alpha/bitops.h and modified for a big-endian machine. 329 */ 330 331 #define ext2_find_first_zero_bit(addr, size) \ 332 ext2_find_next_zero_bit((addr), (size), 0) 333 334 static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, 335 unsigned long size, unsigned long offset) 336 { 337 unsigned int *p = ((unsigned int *) addr) + (offset >> 5); 338 unsigned int result = offset & ~31UL; 339 unsigned int tmp; 340 341 if (offset >= size) 342 return size; 343 size -= result; 344 offset &= 31UL; 345 if (offset) { 346 tmp = cpu_to_le32p(p++); 347 tmp |= ~0UL >> (32-offset); 348 if (size < 32) 349 goto found_first; 350 if (tmp != ~0U) 351 goto found_middle; 352 size -= 32; 353 result += 32; 354 } 355 while (size >= 32) { 356 if ((tmp = cpu_to_le32p(p++)) != ~0U) 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 |= ~0U << size; 366 found_middle: 367 return result + ffz(tmp); 368 } 369 370 /* Bitmap functions for the minix filesystem. */ 371 #define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr) 372 #define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr)) 373 #define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr) 374 #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr) 375 #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size) 376 377 #endif /* _PPC_BITOPS_H */ 378