s390/bitops: use generic find bit functions / reimplement _left variant
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Wed, 18 Sep 2013 09:45:36 +0000 (11:45 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 24 Oct 2013 15:16:55 +0000 (17:16 +0200)
Just like all other architectures we should use out-of-line find bit
operations, since the inline variant bloat the size of the kernel image.
And also like all other architecures we should only supply optimized
variants of the __ffs, ffs, etc. primitives.

Therefore this patch removes the inlined s390 find bit functions and uses
the generic out-of-line variants instead.

The optimization of the primitives follows with the next patch.

With this patch also the functions find_first_bit_left() and
find_next_bit_left() have been reimplemented, since logically, they are
nothing else but a find_first_bit()/find_next_bit() implementation that
use an inverted __fls() instead of __ffs().
Also the restriction that these functions only work on machines which
support the "flogr" instruction is gone now.

This reduces the size of the kernel image (defconfig, -march=z9-109)
by 144,482 bytes.
Alone the size of the function build_sched_domains() gets reduced from
7 KB to 3,5 KB.

We also git rid of unused functions like find_first_bit_le()...

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/Kconfig
arch/s390/include/asm/bitops.h
arch/s390/kernel/Makefile
arch/s390/kernel/bitmap.c [deleted file]
arch/s390/lib/Makefile
arch/s390/lib/find.c [new file with mode: 0644]

index 7143793..a02177f 100644 (file)
@@ -99,6 +99,7 @@ config S390
        select CLONE_BACKWARDS2
        select GENERIC_CLOCKEVENTS
        select GENERIC_CPU_DEVICES if !SMP
+       select GENERIC_FIND_FIRST_BIT
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_TIME_VSYSCALL_OLD
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
index 16df62d..e5ca859 100644 (file)
@@ -1,10 +1,40 @@
 /*
- *  S390 version
- *    Copyright IBM Corp. 1999
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *    Copyright IBM Corp. 1999,2013
  *
- *  Derived from "include/asm-i386/bitops.h"
- *    Copyright (C) 1992, Linus Torvalds
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ *
+ * The description below was taken in large parts from the powerpc
+ * bitops header file:
+ * Within a word, bits are numbered LSB first.  Lot's of places make
+ * this assumption by directly testing bits with (val & (1<<nr)).
+ * This can cause confusion for large (> 1 word) bitmaps on a
+ * big-endian system because, unlike little endian, the number of each
+ * bit depends on the word size.
+ *
+ * The bitop functions are defined to work on unsigned longs, so for an
+ * s390x system the bits end up numbered:
+ *   |63..............0|127............64|191...........128|255...........196|
+ * and on s390:
+ *   |31.....0|63....31|95....64|127...96|159..128|191..160|223..192|255..224|
+ *
+ * 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 (64b) or 3-4 (32b) in the bit
+ * number field needs to be reversed compared to the big-endian bit
+ * fields. This can be achieved by XOR with 0x38 (64b) or 0x18 (32b).
+ *
+ * We also have special functions which work with an MSB0 encoding:
+ * on an s390x system the bits are numbered:
+ *   |0..............63|64............127|128...........191|192...........255|
+ * and on s390:
+ *   |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ *
+ * The main difference is that bit 0-63 (64b) or 0-31 (32b) in the bit
+ * number field needs to be reversed compared to the LSB0 encoded bit
+ * fields. This can be achieved by XOR with 0x3f (64b) or 0x1f (32b).
  *
  */
 
 #include <linux/typecheck.h>
 #include <linux/compiler.h>
 
-/*
- * 32 bit bitops format:
- * bit 0 is the LSB of *addr; bit 31 is the MSB of *addr;
- * bit 32 is the LSB of *(addr+4). That combined with the
- * big endian byte order on S390 give the following bit
- * order in memory:
- *    1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 \
- *    0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00
- * after that follows the next long with bit numbers
- *    3f 3e 3d 3c 3b 3a 39 38 37 36 35 34 33 32 31 30
- *    2f 2e 2d 2c 2b 2a 29 28 27 26 25 24 23 22 21 20
- * The reason for this bit ordering is the fact that
- * in the architecture independent code bits operations
- * of the form "flags |= (1 << bitnr)" are used INTERMIXED
- * with operation of the form "set_bit(bitnr, flags)".
- *
- * 64 bit bitops format:
- * bit 0 is the LSB of *addr; bit 63 is the MSB of *addr;
- * bit 64 is the LSB of *(addr+8). That combined with the
- * big endian byte order on S390 give the following bit
- * order in memory:
- *    3f 3e 3d 3c 3b 3a 39 38 37 36 35 34 33 32 31 30
- *    2f 2e 2d 2c 2b 2a 29 28 27 26 25 24 23 22 21 20
- *    1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10
- *    0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00
- * after that follows the next long with bit numbers
- *    7f 7e 7d 7c 7b 7a 79 78 77 76 75 74 73 72 71 70
- *    6f 6e 6d 6c 6b 6a 69 68 67 66 65 64 63 62 61 60
- *    5f 5e 5d 5c 5b 5a 59 58 57 56 55 54 53 52 51 50
- *    4f 4e 4d 4c 4b 4a 49 48 47 46 45 44 43 42 41 40
- * The reason for this bit ordering is the fact that
- * in the architecture independent code bits operations
- * of the form "flags |= (1 << bitnr)" are used INTERMIXED
- * with operation of the form "set_bit(bitnr, flags)".
- */
-
-/* bitmap tables from arch/s390/kernel/bitmap.c */
-extern const char _zb_findmap[];
-extern const char _sb_findmap[];
-
 #ifndef CONFIG_64BIT
 
 #define __BITOPS_OR            "or"
@@ -310,522 +300,24 @@ static inline int test_bit(unsigned long nr, const volatile unsigned long *ptr)
 }
 
 /*
- * Optimized find bit helper functions.
- */
-
-/**
- * __ffz_word_loop - find byte offset of first long != -1UL
- * @addr: pointer to array of unsigned long
- * @size: size of the array in bits
- */
-static inline unsigned long __ffz_word_loop(const unsigned long *addr,
-                                           unsigned long size)
-{
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-       unsigned long bytes = 0;
-
-       asm volatile(
-#ifndef CONFIG_64BIT
-               "       ahi     %1,-1\n"
-               "       sra     %1,5\n"
-               "       jz      1f\n"
-               "0:     c       %2,0(%0,%3)\n"
-               "       jne     1f\n"
-               "       la      %0,4(%0)\n"
-               "       brct    %1,0b\n"
-               "1:\n"
-#else
-               "       aghi    %1,-1\n"
-               "       srag    %1,%1,6\n"
-               "       jz      1f\n"
-               "0:     cg      %2,0(%0,%3)\n"
-               "       jne     1f\n"
-               "       la      %0,8(%0)\n"
-               "       brct    %1,0b\n"
-               "1:\n"
-#endif
-               : "+&a" (bytes), "+&d" (size)
-               : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr)
-               : "cc" );
-       return bytes;
-}
-
-/**
- * __ffs_word_loop - find byte offset of first long != 0UL
- * @addr: pointer to array of unsigned long
- * @size: size of the array in bits
- */
-static inline unsigned long __ffs_word_loop(const unsigned long *addr,
-                                           unsigned long size)
-{
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-       unsigned long bytes = 0;
-
-       asm volatile(
-#ifndef CONFIG_64BIT
-               "       ahi     %1,-1\n"
-               "       sra     %1,5\n"
-               "       jz      1f\n"
-               "0:     c       %2,0(%0,%3)\n"
-               "       jne     1f\n"
-               "       la      %0,4(%0)\n"
-               "       brct    %1,0b\n"
-               "1:\n"
-#else
-               "       aghi    %1,-1\n"
-               "       srag    %1,%1,6\n"
-               "       jz      1f\n"
-               "0:     cg      %2,0(%0,%3)\n"
-               "       jne     1f\n"
-               "       la      %0,8(%0)\n"
-               "       brct    %1,0b\n"
-               "1:\n"
-#endif
-               : "+&a" (bytes), "+&a" (size)
-               : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr)
-               : "cc" );
-       return bytes;
-}
-
-/**
- * __ffz_word - add number of the first unset bit
- * @nr: base value the bit number is added to
- * @word: the word that is searched for unset bits
- */
-static inline unsigned long __ffz_word(unsigned long nr, unsigned long word)
-{
-#ifdef CONFIG_64BIT
-       if ((word & 0xffffffff) == 0xffffffff) {
-               word >>= 32;
-               nr += 32;
-       }
-#endif
-       if ((word & 0xffff) == 0xffff) {
-               word >>= 16;
-               nr += 16;
-       }
-       if ((word & 0xff) == 0xff) {
-               word >>= 8;
-               nr += 8;
-       }
-       return nr + _zb_findmap[(unsigned char) word];
-}
-
-/**
- * __ffs_word - add number of the first set bit
- * @nr: base value the bit number is added to
- * @word: the word that is searched for set bits
- */
-static inline unsigned long __ffs_word(unsigned long nr, unsigned long word)
-{
-#ifdef CONFIG_64BIT
-       if ((word & 0xffffffff) == 0) {
-               word >>= 32;
-               nr += 32;
-       }
-#endif
-       if ((word & 0xffff) == 0) {
-               word >>= 16;
-               nr += 16;
-       }
-       if ((word & 0xff) == 0) {
-               word >>= 8;
-               nr += 8;
-       }
-       return nr + _sb_findmap[(unsigned char) word];
-}
-
-
-/**
- * __load_ulong_be - load big endian unsigned long
- * @p: pointer to array of unsigned long
- * @offset: byte offset of source value in the array
- */
-static inline unsigned long __load_ulong_be(const unsigned long *p,
-                                           unsigned long offset)
-{
-       p = (unsigned long *)((unsigned long) p + offset);
-       return *p;
-}
-
-/**
- * __load_ulong_le - load little endian unsigned long
- * @p: pointer to array of unsigned long
- * @offset: byte offset of source value in the array
- */
-static inline unsigned long __load_ulong_le(const unsigned long *p,
-                                           unsigned long offset)
-{
-       unsigned long word;
-
-       p = (unsigned long *)((unsigned long) p + offset);
-#ifndef CONFIG_64BIT
-       asm volatile(
-               "       ic      %0,%O1(%R1)\n"
-               "       icm     %0,2,%O1+1(%R1)\n"
-               "       icm     %0,4,%O1+2(%R1)\n"
-               "       icm     %0,8,%O1+3(%R1)"
-               : "=&d" (word) : "Q" (*p) : "cc");
-#else
-       asm volatile(
-               "       lrvg    %0,%1"
-               : "=d" (word) : "m" (*p) );
-#endif
-       return word;
-}
-
-/*
- * The various find bit functions.
- */
-
-/*
- * ffz - find first zero in word.
- * @word: The word to search
- *
- * Undefined if no zero exists, so code should check against ~0UL first.
- */
-static inline unsigned long ffz(unsigned long word)
-{
-       return __ffz_word(0, word);
-}
-
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline unsigned long __ffs (unsigned long word)
-{
-       return __ffs_word(0, word);
-}
-
-/**
- * ffs - find first bit set
- * @x: the word to search
- *
- * This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-static inline int ffs(int x)
-{
-       if (!x)
-               return 0;
-       return __ffs_word(1, x);
-}
-
-/**
- * find_first_zero_bit - find the first zero bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first zero bit, not the number of the byte
- * containing a bit.
- */
-static inline unsigned long find_first_zero_bit(const unsigned long *addr,
-                                               unsigned long size)
-{
-       unsigned long bytes, bits;
-
-        if (!size)
-                return 0;
-       bytes = __ffz_word_loop(addr, size);
-       bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
-       return (bits < size) ? bits : size;
-}
-#define find_first_zero_bit find_first_zero_bit
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-static inline unsigned long find_first_bit(const unsigned long * addr,
-                                          unsigned long size)
-{
-       unsigned long bytes, bits;
-
-        if (!size)
-                return 0;
-       bytes = __ffs_word_loop(addr, size);
-       bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
-       return (bits < size) ? bits : size;
-}
-#define find_first_bit find_first_bit
-
-/*
- * Big endian variant whichs starts bit counting from left using
- * the flogr (find leftmost one) instruction.
+ * ATTENTION:
+ * find_first_bit_left() and find_next_bit_left() use MSB0 encoding.
  */
-static inline unsigned long __flo_word(unsigned long nr, unsigned long val)
-{
-       register unsigned long bit asm("2") = val;
-       register unsigned long out asm("3");
-
-       asm volatile (
-               "       .insn   rre,0xb9830000,%[bit],%[bit]\n"
-               : [bit] "+d" (bit), [out] "=d" (out) : : "cc");
-       return nr + bit;
-}
-
-/*
- * 64 bit special left bitops format:
- * order in memory:
- *    00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
- *    10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
- *    20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
- *    30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
- * after that follows the next long with bit numbers
- *    40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
- *    50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
- *    60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
- *    70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
- * The reason for this bit ordering is the fact that
- * the hardware sets bits in a bitmap starting at bit 0
- * and we don't want to scan the bitmap from the 'wrong
- * end'.
- */
-static inline unsigned long find_first_bit_left(const unsigned long *addr,
-                                               unsigned long size)
-{
-       unsigned long bytes, bits;
-
-       if (!size)
-               return 0;
-       bytes = __ffs_word_loop(addr, size);
-       bits = __flo_word(bytes * 8, __load_ulong_be(addr, bytes));
-       return (bits < size) ? bits : size;
-}
+unsigned long find_first_bit_left(const unsigned long *addr, unsigned long size);
+unsigned long find_next_bit_left(const unsigned long *addr, unsigned long size,
+                                unsigned long offset);
 
-static inline int find_next_bit_left(const unsigned long *addr,
-                                    unsigned long size,
-                                    unsigned long offset)
-{
-       const unsigned long *p;
-       unsigned long bit, set;
-
-       if (offset >= size)
-               return size;
-       bit = offset & (BITS_PER_LONG - 1);
-       offset -= bit;
-       size -= offset;
-       p = addr + offset / BITS_PER_LONG;
-       if (bit) {
-               set = __flo_word(0, *p & (~0UL >> bit));
-               if (set >= size)
-                       return size + offset;
-               if (set < BITS_PER_LONG)
-                       return set + offset;
-               offset += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-               p++;
-       }
-       return offset + find_first_bit_left(p, size);
-}
-
-#define for_each_set_bit_left(bit, addr, size)                         \
-       for ((bit) = find_first_bit_left((addr), (size));               \
-            (bit) < (size);                                            \
-            (bit) = find_next_bit_left((addr), (size), (bit) + 1))
-
-/* same as for_each_set_bit() but use bit as value to start with */
-#define for_each_set_bit_left_cont(bit, addr, size)                    \
-       for ((bit) = find_next_bit_left((addr), (size), (bit));         \
-            (bit) < (size);                                            \
-            (bit) = find_next_bit_left((addr), (size), (bit) + 1))
-
-/**
- * find_next_zero_bit - find the first zero 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
- */
-static inline int find_next_zero_bit (const unsigned long * addr,
-                                     unsigned long size,
-                                     unsigned long offset)
-{
-        const unsigned long *p;
-       unsigned long bit, set;
-
-       if (offset >= size)
-               return size;
-       bit = offset & (BITS_PER_LONG - 1);
-       offset -= bit;
-       size -= offset;
-       p = addr + offset / BITS_PER_LONG;
-       if (bit) {
-               /*
-                * __ffz_word returns BITS_PER_LONG
-                * if no zero bit is present in the word.
-                */
-               set = __ffz_word(bit, *p >> bit);
-               if (set >= size)
-                       return size + offset;
-               if (set < BITS_PER_LONG)
-                       return set + offset;
-               offset += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-               p++;
-       }
-       return offset + find_first_zero_bit(p, size);
-}
-#define find_next_zero_bit find_next_zero_bit
-
-/**
- * find_next_bit - find the first 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
- */
-static inline int find_next_bit (const unsigned long * addr,
-                                unsigned long size,
-                                unsigned long offset)
-{
-        const unsigned long *p;
-       unsigned long bit, set;
-
-       if (offset >= size)
-               return size;
-       bit = offset & (BITS_PER_LONG - 1);
-       offset -= bit;
-       size -= offset;
-       p = addr + offset / BITS_PER_LONG;
-       if (bit) {
-               /*
-                * __ffs_word returns BITS_PER_LONG
-                * if no one bit is present in the word.
-                */
-               set = __ffs_word(0, *p & (~0UL << bit));
-               if (set >= size)
-                       return size + offset;
-               if (set < BITS_PER_LONG)
-                       return set + offset;
-               offset += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-               p++;
-       }
-       return offset + find_first_bit(p, size);
-}
-#define find_next_bit find_next_bit
-
-/*
- * Every architecture must define this function. It's the fastest
- * way of searching a 140-bit bitmap where the first 100 bits are
- * unlikely to be set. It's guaranteed that at least one of the 140
- * bits is cleared.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-       return find_first_bit(b, 140);
-}
-
-#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/ffs.h>
 #include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/fls64.h>
-
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
-
-/*
- * ATTENTION: intel byte ordering convention for ext2 and minix !!
- * bit 0 is the LSB of addr; bit 31 is the MSB of addr;
- * bit 32 is the LSB of (addr+4).
- * That combined with the little endian byte order of Intel gives the
- * following bit order in memory:
- *    07 06 05 04 03 02 01 00 15 14 13 12 11 10 09 08 \
- *    23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
- */
-
-static inline int find_first_zero_bit_le(void *vaddr, unsigned int size)
-{
-       unsigned long bytes, bits;
-
-        if (!size)
-                return 0;
-       bytes = __ffz_word_loop(vaddr, size);
-       bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes));
-       return (bits < size) ? bits : size;
-}
-#define find_first_zero_bit_le find_first_zero_bit_le
-
-static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
-                                         unsigned long offset)
-{
-        unsigned long *addr = vaddr, *p;
-       unsigned long bit, set;
-
-        if (offset >= size)
-                return size;
-       bit = offset & (BITS_PER_LONG - 1);
-       offset -= bit;
-       size -= offset;
-       p = addr + offset / BITS_PER_LONG;
-        if (bit) {
-               /*
-                * s390 version of ffz returns BITS_PER_LONG
-                * if no zero bit is present in the word.
-                */
-               set = __ffz_word(bit, __load_ulong_le(p, 0) >> bit);
-               if (set >= size)
-                       return size + offset;
-               if (set < BITS_PER_LONG)
-                       return set + offset;
-               offset += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-               p++;
-        }
-       return offset + find_first_zero_bit_le(p, size);
-}
-#define find_next_zero_bit_le find_next_zero_bit_le
-
-static inline unsigned long find_first_bit_le(void *vaddr, unsigned long size)
-{
-       unsigned long bytes, bits;
-
-       if (!size)
-               return 0;
-       bytes = __ffs_word_loop(vaddr, size);
-       bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes));
-       return (bits < size) ? bits : size;
-}
-#define find_first_bit_le find_first_bit_le
-
-static inline int find_next_bit_le(void *vaddr, unsigned long size,
-                                    unsigned long offset)
-{
-       unsigned long *addr = vaddr, *p;
-       unsigned long bit, set;
-
-       if (offset >= size)
-               return size;
-       bit = offset & (BITS_PER_LONG - 1);
-       offset -= bit;
-       size -= offset;
-       p = addr + offset / BITS_PER_LONG;
-       if (bit) {
-               /*
-                * s390 version of ffz returns BITS_PER_LONG
-                * if no zero bit is present in the word.
-                */
-               set = __ffs_word(0, __load_ulong_le(p, 0) & (~0UL << bit));
-               if (set >= size)
-                       return size + offset;
-               if (set < BITS_PER_LONG)
-                       return set + offset;
-               offset += BITS_PER_LONG;
-               size -= BITS_PER_LONG;
-               p++;
-       }
-       return offset + find_first_bit_le(p, size);
-}
-#define find_next_bit_le find_next_bit_le
-
+#include <asm-generic/bitops/sched.h>
 #include <asm-generic/bitops/le.h>
-
 #include <asm-generic/bitops/ext2-atomic-setbit.h>
 
 #endif /* _S390_BITOPS_H */
index 4bb2a46..2403303 100644 (file)
@@ -28,7 +28,7 @@ CFLAGS_ptrace.o               += -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
 CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
 
-obj-y  := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o
+obj-y  := traps.o time.o process.o base.o early.o setup.o vtime.o
 obj-y  += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
 obj-y  += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o
 obj-y  += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
diff --git a/arch/s390/kernel/bitmap.c b/arch/s390/kernel/bitmap.c
deleted file mode 100644 (file)
index 5cdb813..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *    Bitmaps for set_bit, clear_bit, test_and_set_bit, ...
- *    See include/asm/{bitops.h|posix_types.h} for details
- *
- *    Copyright IBM Corp. 1999, 2009
- *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
- */
-
-#include <linux/bitops.h>
-#include <linux/module.h>
-
-const char _zb_findmap[] = {
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,
-       0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 };
-EXPORT_SYMBOL(_zb_findmap);
-
-const char _sb_findmap[] = {
-       8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
-       4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 };
-EXPORT_SYMBOL(_sb_findmap);
index 20b0e97..e506c5f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for s390-specific library files..
 #
 
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o find.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
 obj-$(CONFIG_64BIT) += mem64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
diff --git a/arch/s390/lib/find.c b/arch/s390/lib/find.c
new file mode 100644 (file)
index 0000000..8963929
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * MSB0 numbered special bitops handling.
+ *
+ * On s390x the bits are numbered:
+ *   |0..............63|64............127|128...........191|192...........255|
+ * and on s390:
+ *   |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ *
+ * The reason for this bit numbering is the fact that the hardware sets bits
+ * in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap
+ * from the 'wrong end'.
+ */
+
+#include <linux/compiler.h>
+#include <linux/bitops.h>
+#include <linux/export.h>
+
+unsigned long find_first_bit_left(const unsigned long *addr, unsigned long size)
+{
+       const unsigned long *p = addr;
+       unsigned long result = 0;
+       unsigned long tmp;
+
+       while (size & ~(BITS_PER_LONG - 1)) {
+               if ((tmp = *(p++)))
+                       goto found;
+               result += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
+       }
+       if (!size)
+               return result;
+       tmp = (*p) & (~0UL << (BITS_PER_LONG - size));
+       if (!tmp)               /* Are any bits set? */
+               return result + size;   /* Nope. */
+found:
+       return result + (__fls(tmp) ^ (BITS_PER_LONG - 1));
+}
+EXPORT_SYMBOL(find_first_bit_left);
+
+unsigned long find_next_bit_left(const unsigned long *addr, unsigned long size,
+                                unsigned long offset)
+{
+       const unsigned long *p = addr + (offset / BITS_PER_LONG);
+       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 >> 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 << (BITS_PER_LONG - size));
+       if (!tmp)               /* Are any bits set? */
+               return result + size;   /* Nope. */
+found_middle:
+       return result + (__fls(tmp) ^ (BITS_PER_LONG - 1));
+}
+EXPORT_SYMBOL(find_next_bit_left);