summaryrefslogtreecommitdiffstats
path: root/include/asm-ppc/bitops.h
diff options
context:
space:
mode:
authorMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
committerMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
commite2819e52a162873ff5061de81bb749831bdb5de9 (patch)
tree6067ea700202750ba335a423696f2972700e5f76 /include/asm-ppc/bitops.h
parent17a005074429bbf143e40401f405ae4363e56828 (diff)
Merge to 2.1.38.
IMPORTANT NOTE: I could not figure out what information is the one that should be used for the following files (ie, those that were in our tree, or those that came from Linus' patch), please, check these: include/asm-mips/jazz.h include/asm-mips/jazzdma.h include/asm-mips/ioctls.h
Diffstat (limited to 'include/asm-ppc/bitops.h')
-rw-r--r--include/asm-ppc/bitops.h178
1 files changed, 133 insertions, 45 deletions
diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h
index 959f2b302..3b8a24575 100644
--- a/include/asm-ppc/bitops.h
+++ b/include/asm-ppc/bitops.h
@@ -3,67 +3,155 @@
#include <asm/system.h>
#include <asm/byteorder.h>
+#include <linux/kernel.h> /* for printk */
#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.
+/*
+ * These are ifdef'd out here because using : "cc" as a constraing
+ * results in errors from gcc. -- Cort
*/
-extern __inline__ int set_bit(int nr, void * add)
+#if 0
+extern __inline__ int set_bit(int nr, void * addr)
{
- 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;
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("set_bit(%lx, %p)\n", nr, addr);
+
+ __asm__ __volatile__(
+ "1:lwarx %0,0,%3 \n\t"
+ "or %1,%0,%2 \n\t"
+ "stwcx. %1,0,%3 \n\t"
+ "bne 1b \n\t"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc" */);
+
+n return (old & mask) != 0;
}
-extern __inline__ int change_bit(int nr, void *add)
+extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
{
- 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;
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("clear_bit(%lx, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ andc %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc"*/);
+
+ return (old & mask) != 0;
}
-extern __inline__ int clear_bit(int nr, void *add)
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
{
- 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);
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("change_bit(%lx, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ xor %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc"*/);
+
+ return (old & mask) != 0;
+}
#endif
- return retval;
+
+extern __inline__ int ffz(unsigned int x)
+{
+ int n;
+
+ x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
+ __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+ return 31 - n;
}
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
+{
+ unsigned int * p = ((unsigned int *) addr);
+ unsigned int result = 0;
+ unsigned int tmp;
+
+ if (size == 0)
+ return 0;
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
+ unsigned long offset)
+{
+ unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+ unsigned int result = offset & ~31UL;
+ unsigned int tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+
#define _EXT2_HAVE_ASM_BITOPS_
#define ext2_find_first_zero_bit(addr, size) \
ext2_find_next_zero_bit((addr), (size), 0)