diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /include/asm-ppc/bitops.h | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'include/asm-ppc/bitops.h')
-rw-r--r-- | include/asm-ppc/bitops.h | 181 |
1 files changed, 108 insertions, 73 deletions
diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h index 5e0407abd..959f2b302 100644 --- a/include/asm-ppc/bitops.h +++ b/include/asm-ppc/bitops.h @@ -1,39 +1,32 @@ #ifndef _ASM_PPC_BITOPS_H_ #define _ASM_PPC_BITOPS_H_ -/* - * For the benefit of those who are trying to port Linux to another - * architecture, here are some C-language equivalents. You should - * recode these in the native assembly language, if at all possible. - * To guarantee atomicity, these routines call cli() and sti() to - * disable interrupts while they operate. (You have to provide inline - * routines to cli() and sti().) - * - * Also note, these routines assume that you have 32 bit integers. - * You will have to change this if you are trying to port Linux to the - * Alpha architecture or to a Cray. :-) - * - * C language equivalents written by Theodore Ts'o, 9/26/92 - */ - -#include "asm/system.h" /* For cli/sti declaration */ +#include <asm/system.h> +#include <asm/byteorder.h> #define BIT(n) 1<<(n&0x1F) typedef unsigned long BITFIELD; + +/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' + * is in the highest of the four bytes and bit '31' is the high bit + * within the first byte. powerpc is BIG-Endian. Unless noted otherwise + * all bit-ops return 0 if bit was previously clear and != 0 otherwise. + */ extern __inline__ int set_bit(int nr, void * add) { - int mask, oldbit; BITFIELD *addr = add; - + long mask,oldbit; +#ifdef __KERNEL__ int s = _disable_interrupts(); +#endif addr += nr >> 5; mask = BIT(nr); oldbit = (mask & *addr) != 0; *addr |= mask; +#ifdef __KERNEL__ _enable_interrupts(s); - - +#endif return oldbit; } @@ -41,12 +34,16 @@ extern __inline__ int change_bit(int nr, void *add) { BITFIELD *addr = add; int mask, retval; +#ifdef __KERNEL__ int s = _disable_interrupts(); +#endif addr += nr >> 5; mask = BIT(nr); retval = (mask & *addr) != 0; *addr ^= mask; +#ifdef __KERNEL__ _enable_interrupts(s); +#endif return retval; } @@ -54,77 +51,115 @@ extern __inline__ int clear_bit(int nr, void *add) { BITFIELD *addr = add; int mask, retval; +#ifdef __KERNEL__ int s = _disable_interrupts(); +#endif addr += nr >> 5; mask = BIT(nr); retval = (mask & *addr) != 0; *addr &= ~mask; +#ifdef __KERNEL__ _enable_interrupts(s); +#endif return retval; } -extern __inline__ int test_bit(int nr, void *add) +#define _EXT2_HAVE_ASM_BITOPS_ +#define ext2_find_first_zero_bit(addr, size) \ + ext2_find_next_zero_bit((addr), (size), 0) + + +extern __inline__ int ext2_set_bit(int nr, void * addr) { - int mask; - BITFIELD *addr = add; +#ifdef __KERNEL__ + int s = _disable_interrupts(); +#endif + int mask; + unsigned char *ADDR = (unsigned char *) addr; + int oldbit; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + oldbit = (*ADDR & mask) ? 1 : 0; + *ADDR |= mask; +#ifdef __KERNEL__ + _enable_interrupts(s); +#endif + return oldbit; +} - addr += nr >> 5; - mask = BIT(nr); - return ((mask & *addr) != 0); +extern __inline__ int ext2_clear_bit(int nr, void * addr) +{ +#ifdef __KERNEL__ + int s = _disable_interrupts(); +#endif + int mask; + unsigned char *ADDR = (unsigned char *) addr; + int oldbit; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + oldbit = (*ADDR & mask) ? 1 : 0; + *ADDR = *ADDR & ~mask; +#ifdef __KERNEL__ + _enable_interrupts(s); +#endif + return oldbit; } -#if 0 -extern __inline__ int find_first_zero_bit(void *add, int len) + + +/* The following routine need not be atomic. */ +extern __inline__ unsigned long test_bit(int nr, void *addr) { - int mask, nr, i; - BITFIELD *addr = add; - nr = 0; - while (len) - { - if (~*addr != 0) - { /* Contains at least one zero */ - for (i = 0; i < 32; i++, nr++) - { - mask = BIT(nr); - if ((mask & *addr) == 0) - { - return (nr); - } - } - } - len -= 32; - addr++; - nr += 32; - } - return (0); /* Shouldn't happen */ + return 1UL & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31)); } -extern __inline__ int find_next_zero_bit(void *add, int len, int nr) +extern __inline__ int ext2_test_bit(int nr, __const__ void * addr) { - int mask, i; - BITFIELD *addr = add; - addr += nr >> 5; - len -= nr; - while (len) - { - if (*addr != 0xFFFFFFFF) - { /* Contains at least one zero */ - for (i = 0; i < 32; i++, nr++) - { - mask = BIT(nr); - if ((mask & *addr) == 0) - { -printk("Bit: %d(%d), Pat: %x\n", nr, nr&0x1F, *addr); - return (nr); - } - } - } - len -= 32; - addr++; - nr += 32; + int mask; + __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return ((mask & *ADDR) != 0); +} + +extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if(offset) { + tmp = *(p++); + tmp |= le32_to_cpu(~0UL >> (32-offset)); + if(size < 32) + goto found_first; + if(~tmp) + goto found_middle; + size -= 32; + result += 32; } - return (0); /* Shouldn't happen */ + while(size & ~31UL) { + if(~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if(!size) + return result; + tmp = *p; + +found_first: + return result + ffz(le32_to_cpu(tmp) | (~0UL << size)); +found_middle: + return result + ffz(le32_to_cpu(tmp)); } -#endif + #endif /* _ASM_PPC_BITOPS_H */ |