vserver 1.9.3
[linux-2.6.git] / include / asm-ppc64 / bitops.h
index 3f053b6..a0f8312 100644 (file)
  * it will be a bad memory reference since we want to store in chunks
  * of unsigned long (64 bits here) size.
  *
+ * There are a few little-endian macros used mostly for filesystem bitmaps,
+ * these work on similar bit arrays layouts, but byte-oriented:
+ *
+ *   |7...0|15...8|23...16|31...24|39...32|47...40|55...48|63...56|
+ *
+ * The main difference is that bit 3-5 in the bit number field needs to be
+ * reversed compared to the big-endian bit fields. This can be achieved
+ * by XOR with 0b111000 (0x38).
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
@@ -154,6 +163,20 @@ static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned lo
        return (old & mask) != 0;
 }
 
+static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
+{
+       unsigned long old;
+
+       __asm__ __volatile__(
+"1:    ldarx   %0,0,%3         # set_bit\n\
+       or      %0,%0,%2\n\
+       stdcx.  %0,0,%3\n\
+       bne-    1b"
+       : "=&r" (old), "=m" (*addr)
+       : "r" (mask), "r" (addr), "m" (*addr)
+       : "cc");
+}
+
 /*
  * non-atomic versions
  */
@@ -274,15 +297,15 @@ static __inline__ int ffs(int x)
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
-extern unsigned long find_next_zero_bit(unsigned long *addr, unsigned long size, unsigned long offset);
+extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
 #define find_first_zero_bit(addr, size) \
        find_next_zero_bit((addr), (size), 0)
 
-extern unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset);
+extern unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
 #define find_first_bit(addr, size) \
        find_next_bit((addr), (size), 0)
 
-extern unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset);
+extern unsigned long find_next_zero_le_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
 #define find_first_zero_le_bit(addr, size) \
        find_next_zero_le_bit((addr), (size), 0)
 
@@ -292,71 +315,34 @@ static __inline__ int test_le_bit(unsigned long nr, __const__ unsigned long * ad
        return (ADDR[nr >> 3] >> (nr & 7)) & 1;
 }
 
+#define test_and_clear_le_bit(nr, addr) \
+       test_and_clear_bit((nr) ^ 0x38, (addr))
+#define test_and_set_le_bit(nr, addr) \
+       test_and_set_bit((nr) ^ 0x38, (addr))
+
 /*
  * non-atomic versions
  */
-static __inline__ void __set_le_bit(unsigned long nr, unsigned long *addr)
-{
-       unsigned char *ADDR = (unsigned char *)addr;
-
-       ADDR += nr >> 3;
-       *ADDR |= 1 << (nr & 0x07);
-}
-
-static __inline__ void __clear_le_bit(unsigned long nr, unsigned long *addr)
-{
-       unsigned char *ADDR = (unsigned char *)addr;
-
-       ADDR += nr >> 3;
-       *ADDR &= ~(1 << (nr & 0x07));
-}
 
-static __inline__ int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
-{
-       int mask, retval;
-       unsigned char *ADDR = (unsigned char *)addr;
-
-       ADDR += nr >> 3;
-       mask = 1 << (nr & 0x07);
-       retval = (mask & *ADDR) != 0;
-       *ADDR |= mask;
-       return retval;
-}
-
-static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
-{
-       int mask, retval;
-       unsigned char *ADDR = (unsigned char *)addr;
-
-       ADDR += nr >> 3;
-       mask = 1 << (nr & 0x07);
-       retval = (mask & *ADDR) != 0;
-       *ADDR &= ~mask;
-       return retval;
-}
+#define __set_le_bit(nr, addr) \
+       __set_bit((nr) ^ 0x38, (addr))
+#define __clear_le_bit(nr, addr) \
+       __clear_bit((nr) ^ 0x38, (addr))
+#define __test_and_clear_le_bit(nr, addr) \
+       __test_and_clear_bit((nr) ^ 0x38, (addr))
+#define __test_and_set_le_bit(nr, addr) \
+       __test_and_set_bit((nr) ^ 0x38, (addr))
 
 #define ext2_set_bit(nr,addr) \
-       __test_and_set_le_bit((nr),(unsigned long*)addr)
+       __test_and_set_le_bit((nr), (unsigned long*)addr)
 #define ext2_clear_bit(nr, addr) \
-       __test_and_clear_le_bit((nr),(unsigned long*)addr)
-
-#define ext2_set_bit_atomic(lock, nr, addr)            \
-       ({                                              \
-               int ret;                                \
-               spin_lock(lock);                        \
-               ret = ext2_set_bit((nr), (addr));       \
-               spin_unlock(lock);                      \
-               ret;                                    \
-       })
-
-#define ext2_clear_bit_atomic(lock, nr, addr)          \
-       ({                                              \
-               int ret;                                \
-               spin_lock(lock);                        \
-               ret = ext2_clear_bit((nr), (addr));     \
-               spin_unlock(lock);                      \
-               ret;                                    \
-       })
+       __test_and_clear_le_bit((nr), (unsigned long*)addr)
+
+#define ext2_set_bit_atomic(lock, nr, addr) \
+       test_and_set_le_bit((nr), (unsigned long*)addr)
+#define ext2_clear_bit_atomic(lock, nr, addr) \
+       test_and_clear_le_bit((nr), (unsigned long*)addr)
+
 
 #define ext2_test_bit(nr, addr)      test_le_bit((nr),(unsigned long*)addr)
 #define ext2_find_first_zero_bit(addr, size) \