[PATCH] powerpc: Merge bitops.h

Here's a revised version.  This re-introduces the set_bits() function
from ppc64, which I removed because I thought it was unused (it exists
on no other arch).  In fact it is used in the powermac interrupt code
(but not on pSeries).

- We use LARXL/STCXL macros to generate the right (32 or 64 bit)
  instructions, similar to LDL/STL from ppc_asm.h, used in fpu.S

- ppc32 previously used a full "sync" barrier at the end of
  test_and_*_bit(), whereas ppc64 used an "isync".  The merged version
  uses "isync", since I believe that's sufficient.

- The ppc64 versions of then minix_*() bitmap functions have changed
  semantics.  Previously on ppc64, these functions were big-endian
  (that is bit 0 was the LSB in the first 64-bit, big-endian word).
  On ppc32 (and x86, for that matter, they were little-endian.  As far
  as I can tell, the big-endian usage was simply wrong - I guess
  no-one ever tried to use minixfs on ppc64.

- On ppc32 find_next_bit() and find_next_zero_bit() are no longer
  inline (they were already out-of-line on ppc64).

- For ppc64, sched_find_first_bit() has moved from mmu_context.h to
  the merged bitops.  What it was doing in mmu_context.h in the first
  place, I have no idea.

- The fls() function is now implemented using the cntlzw instruction
  on ppc64, instead of generic_fls(), as it already was on ppc32.

- For ARCH=ppc, this patch requires adding arch/powerpc/lib to the
  arch/ppc/Makefile.  This in turn requires some changes to
  arch/powerpc/lib/Makefile which didn't correctly handle ARCH=ppc.

Built and running on G5.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 8bc5403..47d6f7e 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -81,15 +81,6 @@
 EXPORT_SYMBOL(ucSystemType);
 #endif
 
-#if !defined(__INLINE_BITOPS)
-EXPORT_SYMBOL(set_bit);
-EXPORT_SYMBOL(clear_bit);
-EXPORT_SYMBOL(change_bit);
-EXPORT_SYMBOL(test_and_set_bit);
-EXPORT_SYMBOL(test_and_clear_bit);
-EXPORT_SYMBOL(test_and_change_bit);
-#endif /* __INLINE_BITOPS */
-
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index dfb3391..34f5c2e 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -3,13 +3,14 @@
 #
 
 ifeq ($(CONFIG_PPC_MERGE),y)
-obj-y			:= string.o
+obj-y			:= string.o strcase.o
+obj-$(CONFIG_PPC32)	+= div64.o copy_32.o checksum_32.o
 endif
 
-obj-y			+= strcase.o
-obj-$(CONFIG_PPC32)	+= div64.o copy_32.o checksum_32.o
+obj-y			+= bitops.o
 obj-$(CONFIG_PPC64)	+= checksum_64.o copypage_64.o copyuser_64.o \
-			   memcpy_64.o usercopy_64.o mem_64.o string.o
+			   memcpy_64.o usercopy_64.o mem_64.o string.o \
+			   strcase.o
 obj-$(CONFIG_PPC_ISERIES) += e2a.o
 obj-$(CONFIG_XMON)	+= sstep.o
 
diff --git a/arch/ppc64/kernel/bitops.c b/arch/powerpc/lib/bitops.c
similarity index 66%
rename from arch/ppc64/kernel/bitops.c
rename to arch/powerpc/lib/bitops.c
index ae329e8..b67ce30 100644
--- a/arch/ppc64/kernel/bitops.c
+++ b/arch/powerpc/lib/bitops.c
@@ -1,79 +1,40 @@
-/*
- * These are too big to be inlined.
- */
-
-#include <linux/kernel.h>
+#include <linux/types.h>
 #include <linux/module.h>
-#include <linux/bitops.h>
 #include <asm/byteorder.h>
+#include <asm/bitops.h>
 
-unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
-				 unsigned long offset)
-{
-	const unsigned long *p = addr + (offset >> 6);
-	unsigned long result = offset & ~63UL;
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset &= 63UL;
-	if (offset) {
-		tmp = *(p++);
-		tmp |= ~0UL >> (64 - offset);
-		if (size < 64)
-			goto found_first;
-		if (~tmp)
-			goto found_middle;
-		size -= 64;
-		result += 64;
-	}
-	while (size & ~63UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 64;
-		size -= 64;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp |= ~0UL << size;
-	if (tmp == ~0UL)	/* Are any bits zero? */
-		return result + size;	/* Nope. */
-found_middle:
-	return result + ffz(tmp);
-}
-
-EXPORT_SYMBOL(find_next_zero_bit);
-
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
 unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
 			    unsigned long offset)
 {
-	const unsigned long *p = addr + (offset >> 6);
-	unsigned long result = offset & ~63UL;
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
 	unsigned long tmp;
 
 	if (offset >= size)
 		return size;
 	size -= result;
-	offset &= 63UL;
+	offset %= BITS_PER_LONG;
 	if (offset) {
 		tmp = *(p++);
 		tmp &= (~0UL << offset);
-		if (size < 64)
+		if (size < BITS_PER_LONG)
 			goto found_first;
 		if (tmp)
 			goto found_middle;
-		size -= 64;
-		result += 64;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
 	}
-	while (size & ~63UL) {
+	while (size & ~(BITS_PER_LONG-1)) {
 		if ((tmp = *(p++)))
 			goto found_middle;
-		result += 64;
-		size -= 64;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
 	}
 	if (!size)
 		return result;
@@ -86,9 +47,52 @@
 found_middle:
 	return result + __ffs(tmp);
 }
-
 EXPORT_SYMBOL(find_next_bit);
 
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+				 unsigned long offset)
+{
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset %= BITS_PER_LONG;
+	if (offset) {
+		tmp = *(p++);
+		tmp |= ~0UL >> (BITS_PER_LONG - offset);
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (~tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+	while (size & ~(BITS_PER_LONG-1)) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp |= ~0UL << size;
+	if (tmp == ~0UL)	/* Are any bits zero? */
+		return result + size;	/* Nope. */
+found_middle:
+	return result + ffz(tmp);
+}
+EXPORT_SYMBOL(find_next_zero_bit);
+
 static inline unsigned int ext2_ilog2(unsigned int x)
 {
 	int lz;
@@ -106,8 +110,8 @@
 	return rc;
 }
 
-unsigned long find_next_zero_le_bit(const unsigned long *addr, unsigned long size,
-				    unsigned long offset)
+unsigned long find_next_zero_le_bit(const unsigned long *addr,
+				    unsigned long size, unsigned long offset)
 {
 	const unsigned int *p = ((const unsigned int *)addr) + (offset >> 5);
 	unsigned int result = offset & ~31;
@@ -143,5 +147,4 @@
 found_middle:
 	return result + ext2_ffz(tmp);
 }
-
 EXPORT_SYMBOL(find_next_zero_le_bit);
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 94d5716..e719a49 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -66,7 +66,8 @@
 core-y				+= arch/ppc/kernel/ arch/powerpc/kernel/ \
 				   arch/ppc/platforms/ \
 				   arch/ppc/mm/ arch/ppc/lib/ \
-				   arch/ppc/syslib/ arch/powerpc/sysdev/
+				   arch/ppc/syslib/ arch/powerpc/sysdev/ \
+				   arch/powerpc/lib/
 core-$(CONFIG_4xx)		+= arch/ppc/platforms/4xx/
 core-$(CONFIG_83xx)		+= arch/ppc/platforms/83xx/
 core-$(CONFIG_85xx)		+= arch/ppc/platforms/85xx/
diff --git a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c
deleted file mode 100644
index 7f53d19..0000000
--- a/arch/ppc/kernel/bitops.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- */
-
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-
-/*
- * If the bitops are not inlined in bitops.h, they are defined here.
- *  -- paulus
- */
-#if !__INLINE_BITOPS
-void set_bit(int nr, volatile void * addr)
-{
-	unsigned long old;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-	
-	__asm__ __volatile__(SMP_WMB "\n\
-1:	lwarx	%0,0,%3 \n\
-	or	%0,%0,%2 \n"
-	PPC405_ERR77(0,%3)
-"	stwcx.	%0,0,%3 \n\
-	bne	1b"
-	SMP_MB
-	: "=&r" (old), "=m" (*p)
-	: "r" (mask), "r" (p), "m" (*p)
-	: "cc" );
-}
-
-void clear_bit(int nr, volatile void *addr)
-{
-	unsigned long old;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-
-	__asm__ __volatile__(SMP_WMB "\n\
-1:	lwarx	%0,0,%3 \n\
-	andc	%0,%0,%2 \n"
-	PPC405_ERR77(0,%3)
-"	stwcx.	%0,0,%3 \n\
-	bne	1b"
-	SMP_MB
-	: "=&r" (old), "=m" (*p)
-	: "r" (mask), "r" (p), "m" (*p)
-	: "cc");
-}
-
-void change_bit(int nr, volatile void *addr)
-{
-	unsigned long old;
-	unsigned long mask = 1 << (nr & 0x1f);
-	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
-
-	__asm__ __volatile__(SMP_WMB "\n\
-1:	lwarx	%0,0,%3 \n\
-	xor	%0,%0,%2 \n"
-	PPC405_ERR77(0,%3)
-"	stwcx.	%0,0,%3 \n\
-	bne	1b"
-	SMP_MB
-	: "=&r" (old), "=m" (*p)
-	: "r" (mask), "r" (p), "m" (*p)
-	: "cc");
-}
-
-int test_and_set_bit(int nr, volatile void *addr)
-{
-	unsigned int old, t;
-	unsigned int mask = 1 << (nr & 0x1f);
-	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
-
-	__asm__ __volatile__(SMP_WMB "\n\
-1:	lwarx	%0,0,%4 \n\
-	or	%1,%0,%3 \n"
-	PPC405_ERR77(0,%4)
-"	stwcx.	%1,0,%4 \n\
-	bne	1b"
-	SMP_MB
-	: "=&r" (old), "=&r" (t), "=m" (*p)
-	: "r" (mask), "r" (p), "m" (*p)
-	: "cc");
-
-	return (old & mask) != 0;
-}
-
-int test_and_clear_bit(int nr, volatile void *addr)
-{
-	unsigned int old, t;
-	unsigned int mask = 1 << (nr & 0x1f);
-	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
-
-	__asm__ __volatile__(SMP_WMB "\n\
-1:	lwarx	%0,0,%4 \n\
-	andc	%1,%0,%3 \n"
-	PPC405_ERR77(0,%4)
-"	stwcx.	%1,0,%4 \n\
-	bne	1b"
-	SMP_MB
-	: "=&r" (old), "=&r" (t), "=m" (*p)
-	: "r" (mask), "r" (p), "m" (*p)
-	: "cc");
-
-	return (old & mask) != 0;
-}
-
-int test_and_change_bit(int nr, volatile void *addr)
-{
-	unsigned int old, t;
-	unsigned int mask = 1 << (nr & 0x1f);
-	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
-
-	__asm__ __volatile__(SMP_WMB "\n\
-1:	lwarx	%0,0,%4 \n\
-	xor	%1,%0,%3 \n"
-	PPC405_ERR77(0,%4)
-"	stwcx.	%1,0,%4 \n\
-	bne	1b"
-	SMP_MB
-	: "=&r" (old), "=&r" (t), "=m" (*p)
-	: "r" (mask), "r" (p), "m" (*p)
-	: "cc");
-
-	return (old & mask) != 0;
-}
-#endif /* !__INLINE_BITOPS */
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
index 247d2fc..990df09 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -13,7 +13,7 @@
 
 obj-y               +=	irq.o idle.o dma.o \
 			signal.o \
-			align.o bitops.o pacaData.o \
+			align.o pacaData.o \
 			udbg.o ioctl32.o \
 			rtc.o \
 			cpu_setup_power4.o \