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
- Lines: 466
- Date:
Sat Nov 25 04:31:16 1995
- Orig file:
v1.3.43/linux/include/asm-sparc/bitops.h
- Orig date:
Tue Aug 15 20:39:04 1995
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