patch-1.3.44 linux/include/asm-sparc/bitops.h

Next file: linux/include/asm-sparc/bsderrno.h
Previous file: linux/include/asm-sparc/auxio.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
@@ -1,13 +1,17 @@
+/* $Id: bitops.h,v 1.17 1995/11/25 02:31:15 davem Exp $
+ * bitops.h: Bit string operations on the Sparc.
+ *
+ * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
+ */
+
 #ifndef _SPARC_BITOPS_H
 #define _SPARC_BITOPS_H
 
 #include <linux/kernel.h>
-#include <asm/system.h>
-
-/*
- * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
- */
 
+#ifdef __KERNEL__
+#include <asm/system.h>
+#endif
 
 /* 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
@@ -15,264 +19,67 @@
  * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
  */
 
-/* For now, the sun4c implementation will disable and enable traps
- * in order to insure atomicity. Things will have to be different
- * for sun4m (ie. SMP) no doubt.
- */
-
-/* These routines now do things in little endian byte order. */
-
-/* Our unsigned long accesses on the Sparc look like this:
- * Big Endian:
- *    byte 0    byte 1      byte 2    byte 3
- *  0000 0000  0000 0000  0000 0000  0000 0000
- *  31     24  23     16  15      8  7       0
- *
- * We want to set the bits in a little-endian fashion:
- * Little Endian:
- *    byte 3    byte 2      byte 1    byte 0
- *  0000 0000  0000 0000  0000 0000  0000 0000
- *  31     24  23     16  15      8  7       0
- */
-
-/* #define __LITTLE_ENDIAN_BITOPS */
-
-extern __inline__ unsigned int set_bit(unsigned int nr, void *vaddr)
+extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
 {
+	int mask, flags;
+	unsigned long *ADDR = (unsigned long *) addr;
+	unsigned long oldbit;
 
-
-#ifdef __LITTLE_ENDIAN_BITOPS
-
-
-        int retval;
-        unsigned char *addr = (unsigned char *)vaddr;
-	unsigned char mask;
-#ifndef TEST_BITOPS
-        unsigned long flags;
-#endif
-
-        addr += nr >> 3;
-        mask = 1 << (nr & 0x7);
-
-#ifndef TEST_BITOPS
-	save_flags(flags);
-	cli();
-#endif
-
-        retval = (mask & *addr) != 0;
-        *addr |= mask;
-
-#ifndef TEST_BITOPS
-	restore_flags(flags);
-#endif
-
-        return retval;
-
-#else  /* BIG ENDIAN BITOPS */
-
-
-	int retval;
-	unsigned long *addr = vaddr;
-	unsigned long mask;
-#ifndef TEST_BITOPS
-	unsigned long flags;
-#endif
-
-	addr += nr>>5;
-	mask = 1 << (nr&31);
-
-#ifndef TEST_BITOPS
-	save_flags(flags);
-	cli();
-#endif
-
-	retval = (mask & *addr) != 0;
-	*addr |= mask;
-
-#ifndef TEST_BITOPS
+	ADDR += nr >> 5;
+	mask = 1 << (nr & 31);
+	save_flags(flags); cli();
+	oldbit = (mask & *ADDR);
+	*ADDR |= mask;
 	restore_flags(flags);
-#endif
-
-	return retval;
-
-
-#endif
+	return oldbit != 0;
 }
 
-extern __inline__ unsigned int clear_bit(unsigned int nr, void *vaddr)
+extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
 {
-#ifdef __LITTLE_ENDIAN_BITOPS
-
-
-        int retval;
-        unsigned char *addr = (unsigned char *)vaddr;
-	unsigned char mask;
-#ifndef TEST_BITOPS
-        unsigned long flags;
-#endif
-
-        addr += nr >> 3;
-        mask = 1 << (nr & 7);
-
-#ifndef TEST_BITOPS
-	save_flags(flags);
-	cli();
-#endif
+	int mask, flags;
+	unsigned long *ADDR = (unsigned long *) addr;
+	unsigned long oldbit;
 
-        retval = (mask & *addr) != 0;
-        *addr &= ~mask;
-
-#ifndef TEST_BITOPS
+	ADDR += nr >> 5;
+	mask = 1 << (nr & 31);
+	save_flags(flags); cli();
+	oldbit = (mask & *ADDR);
+	*ADDR &= ~mask;
 	restore_flags(flags);
-#endif
-
-        return retval;
-
-
-#else   /* BIG ENDIAN BITOPS */
-
-
-	int retval;
-	unsigned long *addr = vaddr;
-	unsigned long mask;
-#ifndef TEST_BITOPS
-	unsigned long flags;
-#endif
-
-	addr += nr>>5;
-	mask = 1 << (nr&31);
-
-#ifndef TEST_BITOPS
-	save_flags(flags);
-	cli();
-#endif
-
-	retval = (mask & *addr) != 0;
-	*addr &= ~mask;
-
-#ifndef TEST_BITOPS
-	restore_flags(flags);
-#endif
-
-	return retval;
-
-
-#endif
+	return oldbit != 0;
 }
 
-extern __inline__ unsigned int change_bit(unsigned int nr, void *vaddr)
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
 {
-#ifdef __LITTLE_ENDIAN_BITOPS
-
-
-        int retval;
-        unsigned char *addr = (unsigned char *)vaddr;
-	unsigned char mask;
-#ifndef TEST_BITOPS
-        unsigned long flags;
-#endif
-
-        addr += nr >> 3;
-        mask = 1 << (nr & 7);
-
-#ifndef TEST_BITOPS
-	save_flags(flags);
-	cli();
-#endif
-
-        retval = (mask & *addr) != 0;
-        *addr ^= mask;
-
-#ifndef TEST_BITOPS
-	restore_flags(flags);
-#endif
-
-        return retval;
-
-
-#else   /* BIG ENDIAN BITOPS */
-
-
-	int retval;
-	unsigned long *addr = vaddr;
-	unsigned long mask;
-#ifndef TEST_BITOPS
-	unsigned long flags;
-#endif
-
-	addr += nr>>5;
-	mask = 1 << (nr&31);
-
-#ifndef TEST_BITOPS
-	save_flags(flags);
-	cli();
-#endif
+	int mask, flags;
+	unsigned long *ADDR = (unsigned long *) addr;
+	unsigned long oldbit;
 
-	retval = (mask & *addr) != 0;
-	*addr ^= mask;
-
-#ifndef TEST_BITOPS
+	ADDR += nr >> 5;
+	mask = 1 << (nr & 31);
+	save_flags(flags); cli();
+	oldbit = (mask & *ADDR);
+	*ADDR ^= mask;
 	restore_flags(flags);
-#endif
-
-	return retval;
-
-
-#endif
+	return oldbit != 0;
 }
 
 /* The following routine need not be atomic. */
-
-extern __inline__ unsigned int test_bit(int nr, void *vaddr)
+extern __inline__ unsigned long test_bit(int nr, const void *addr)
 {
-#ifdef __LITTLE_ENDIAN_BITOPS
-
-        unsigned char mask;
-        unsigned char *addr = (unsigned char *)vaddr;
-
-        addr += nr >> 3;
-        mask = 1 << (nr & 7);
-        return ((mask & *addr) != 0);
-
-#else   /* BIG ENDIAN BITOPS */
-
-	unsigned long mask;
-	unsigned long *addr = vaddr;
-
-	addr += (nr>>5);
-	mask = 1 << (nr&31);
-	return ((mask & *addr) != 0);
-
-#endif
+	return 1UL & (((int *) addr)[nr >> 5] >> (nr & 31));
 }
 
-/* There has to be a faster way to do this, sigh... */
-
+/* The easy/cheese version for now. */
 extern __inline__ unsigned long ffz(unsigned long word)
 {
-  register unsigned long cnt;
-
-  cnt = 0;
-
-#ifdef __LITTLE_ENDIAN_BITOPS
-
-  for(int byte_bit = 24; byte_bit >=0; byte_bit -= 8)
-	  for(int bit = 0; bit<8; bit++)
-		  if((word>>(byte_bit+bit))&1)
-			  cnt++;
-		  else
-			  return cnt;
-
-#else /* BIT ENDIAN BITOPS */
-  while(cnt<32) {
-	  if(!((word>>cnt)&1))
-		  return cnt;
-	  else
-		  cnt++;
-  }
-  return cnt;
-#endif
+	unsigned long result = 0;
 
+	while(word & 1) {
+		result++;
+		word >>= 1;
+	}
+	return result;
 }
 
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
@@ -280,15 +87,9 @@
  * on Linus's ALPHA routines, which are pretty portable BTW.
  */
 
-extern __inline__ unsigned long
-find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
-#ifdef __LITTLE_ENDIAN_BITOPS
-
-	/* FOO, needs to be written */
-
-#else   /* BIG ENDIAN BITOPS */
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
 	unsigned long tmp;
 
@@ -296,10 +97,9 @@
 		return size;
 	size -= result;
 	offset &= 31UL;
-	if (offset) 
-	{
+	if (offset) {
 		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
+		tmp |= ~0UL << (32-offset);
 		if (size < 32)
 			goto found_first;
 		if (~tmp)
@@ -307,8 +107,7 @@
 		size -= 32;
 		result += 32;
 	}
-	while (size & ~32UL) 
-	{
+	while (size & ~31UL) {
 		if (~(tmp = *(p++)))
 			goto found_middle;
 		result += 32;
@@ -319,10 +118,9 @@
 	tmp = *p;
 
 found_first:
-	tmp |= ~0UL << size;
+	tmp |= ~0UL >> size;
 found_middle:
 	return result + ffz(tmp);
-#endif
 }
 
 /* Linus sez that gcc can optimize the following correctly, we'll see if this
@@ -332,6 +130,85 @@
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
 
+/* Now for the ext2 filesystem bit operations and helper routines. */
+
+extern __inline__ int ext2_set_bit(int nr,void * addr)
+{
+	int		mask, retval, flags;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	save_flags(flags); cli();
+	retval = (mask & *ADDR) != 0;
+	*ADDR |= mask;
+	restore_flags(flags);
+	return retval;
+}
+
+extern __inline__ int ext2_clear_bit(int nr, void * addr)
+{
+	int		mask, retval, flags;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	save_flags(flags); cli();
+	retval = (mask & *ADDR) != 0;
+	*ADDR &= ~mask;
+	restore_flags(flags);
+	return retval;
+}
+
+extern __inline__ int ext2_test_bit(int nr, const void * addr)
+{
+	int			mask;
+	const unsigned char	*ADDR = (const unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	return ((mask & *ADDR) != 0);
+}
+
+#define ext2_find_first_zero_bit(addr, size) \
+        ext2_find_next_zero_bit((addr), (size), 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 |= ~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:
+	tmp = ((tmp>>24) | ((tmp>>8)&0xff00) | ((tmp<<8)&0xff0000) | (tmp<<24));
+	return result + ffz(tmp);
+}
 
 #endif /* defined(_SPARC_BITOPS_H) */
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this