summaryrefslogtreecommitdiffstats
path: root/include/asm-ppc/bitops.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-ppc/bitops.h')
-rw-r--r--include/asm-ppc/bitops.h181
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 */