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