]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
[PATCH] LOG2: Implement a general integer log2 facility in the kernel
authorDavid Howells <dhowells@redhat.com>
Fri, 8 Dec 2006 10:37:49 +0000 (02:37 -0800)
committerLinus Torvalds <torvalds@woody.osdl.org>
Fri, 8 Dec 2006 16:28:51 +0000 (08:28 -0800)
This facility provides three entry points:

ilog2() Log base 2 of unsigned long
ilog2_u32() Log base 2 of u32
ilog2_u64() Log base 2 of u64

These facilities can either be used inside functions on dynamic data:

int do_something(long q)
{
...;
y = ilog2(x)
...;
}

Or can be used to statically initialise global variables with constant values:

unsigned n = ilog2(27);

When performing static initialisation, the compiler will report "error:
initializer element is not constant" if asked to take a log of zero or of
something not reducible to a constant.  They treat negative numbers as
unsigned.

When not dealing with a constant, they fall back to using fls() which permits
them to use arch-specific log calculation instructions - such as BSR on
x86/x86_64 or SCAN on FRV - if available.

[akpm@osdl.org: MMC fix]
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: David Howells <dhowells@redhat.com>
Cc: Wojtek Kaniewski <wojtekka@toxygen.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
36 files changed:
arch/alpha/Kconfig
arch/arm/Kconfig
arch/arm26/Kconfig
arch/avr32/Kconfig
arch/cris/Kconfig
arch/frv/Kconfig
arch/h8300/Kconfig
arch/i386/Kconfig.cpu
arch/ia64/Kconfig
arch/m32r/Kconfig
arch/m68k/Kconfig
arch/m68knommu/Kconfig
arch/mips/Kconfig
arch/parisc/Kconfig
arch/powerpc/Kconfig
arch/ppc/Kconfig
arch/s390/Kconfig
arch/sh/Kconfig
arch/sh64/Kconfig
arch/sparc/Kconfig
arch/sparc64/Kconfig
arch/v850/Kconfig
arch/x86_64/Kconfig
arch/xtensa/Kconfig
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/ulp/iser/iser_memory.c
drivers/md/dm-crypt.c
drivers/mmc/tifm_sd.c
fs/ext2/super.c
fs/ext3/super.c
include/asm-frv/bitops.h
include/linux/kernel.h
include/linux/log2.h [new file with mode: 0644]
mm/page_alloc.c

index 7e55ea66c6d4ad1e41fdaa02ae09c3aabf1991b1..84caf50725b53e829df2a39baa059084d63663e4 100644 (file)
@@ -25,6 +25,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index 8c05d4321ae99bab420a7772e0fc4a621e3d6151..aa1d400d721a662f3dbae57a3cb9eea8bc6b6522 100644 (file)
@@ -74,6 +74,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_HWEIGHT
        bool
        default y
index c14fe918bc4cf5e0cfb8aec5871c95be1c761cb3..74eba8b5a8ca41c5576b30c691b56344f0a416ce 100644 (file)
@@ -41,6 +41,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_HWEIGHT
        bool
        default y
index 5f1694eea8426d45da17fd8b7c24f79b5915c234..bb059a4e1df94a757eac011ad007552a8649be69 100644 (file)
@@ -45,6 +45,14 @@ config GENERIC_TIME
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_BUST_SPINLOCK
        bool
 
index 6a1238a29d6c4d98d46156a1863e4a342478d7db..3474309e049c857ac2192c50fe1429358aff0dfc 100644 (file)
@@ -16,6 +16,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index cf1c446e003ac6cad36c4a354872d0b41b2a2925..7561d7b72e75408bb05f3998008c2cee2b1debcf 100644 (file)
@@ -41,6 +41,14 @@ config TIME_LOW_RES
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default y
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default y
+
 mainmenu "Fujitsu FR-V Kernel Configuration"
 
 source "init/Kconfig"
index cabf0bfffc534a06b1e9850d8d814cd98fa988a4..34a84bc4baf59ae515c1a0b0c899deee21604ef4 100644 (file)
@@ -29,6 +29,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default n
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index 821fd269ca580137c5e959e1398f9ff17fb05089..2aecfba4ac4f8fe702a2c0fc279877f10ee792f8 100644 (file)
@@ -248,6 +248,14 @@ config RWSEM_XCHGADD_ALGORITHM
        depends on !M386
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_CALIBRATE_DELAY
        bool
        default y
index 75d839715b2f8deedb47df757440a9bb22ce1bbb..fcacfe291b9b7450b5537ec8cbb0aab258e92f5e 100644 (file)
@@ -34,6 +34,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index 41fd490af3b47a93c70e829a561506151f1e6e09..f383dab973f5ea62d86f914a5774357be3ea7a4d 100644 (file)
@@ -214,6 +214,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default n
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index 7bc14461a6ac5082f785f887a73964cbcbe3b280..70a577c89c7c84d279d9ce9f9c08f1c0bbaa08db 100644 (file)
@@ -17,6 +17,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_HWEIGHT
        bool
        default y
index aa70dde54228266f55027b7544e4de6520215af9..25993c2a8fbbeb4c540218980f05d22c60a9dfcb 100644 (file)
@@ -25,6 +25,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default n
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index d8af858fe3f5eb2b319bfc2101e152e33b14b6c1..57af8d8cf46f42fb760f19fbbedba423ba1e0293 100644 (file)
@@ -819,6 +819,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index d2101237442e8bbfa345788f4b49c950d6848a17..0f9ff618c6d7205c7d86f856cd78b9898b89e85a 100644 (file)
@@ -25,6 +25,14 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
index 291c95ac4b313d4f791367f583ead200a4b11788..97c7a212cddad6f357787d136775913915013cd2 100644 (file)
@@ -41,6 +41,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_HWEIGHT
        bool
        default y
index f76a146cff137f28c65a5e839aca007a9de63069..692b5ba53209c27bdc7ac898d2be43c36889b887 100644 (file)
@@ -19,6 +19,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default y
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_HWEIGHT
        bool
        default y
index 583d9ff0a571a4c75a1370472e9c03ff7333a076..45e47bfb68a9912a0d331c37fa1b0fc10da26776 100644 (file)
@@ -22,6 +22,14 @@ config RWSEM_XCHGADD_ALGORITHM
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config GENERIC_HWEIGHT
        bool
        default y
index d83d64af31f277d5451507d2b60fcc13c3a0af33..8e24c40662e301fc10b65e5c3aca02210f62ab67 100644 (file)
@@ -59,6 +59,14 @@ config LOCKDEP_SUPPORT
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 source "init/Kconfig"
 
 menu "System type"
index 58c678e0666786709a6da152d24fa3d9df158dfd..7bc0744b7ab6aca55207c96740c48c793fa286e4 100644 (file)
@@ -39,6 +39,14 @@ config RWSEM_XCHGADD_ALGORITHM
 config GENERIC_ISA_DMA
        bool
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 source init/Kconfig
 
 menu "System type"
index 92a7c8a636d3c8679ec34eab437ab4a8273d55e4..d0dec1ea2eed93345091981a64c6028f9ae474ff 100644 (file)
@@ -166,6 +166,14 @@ config ARCH_MAY_HAVE_PC_FDC
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config SUN_PM
        bool
        default y
index b627f8dbcaad5da32b4b5ffe1cad244d820bc898..d391d11f245ab0d8d06ce6a9e92c95a1b4b989f8 100644 (file)
@@ -34,6 +34,14 @@ config ARCH_MAY_HAVE_PC_FDC
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 config AUDIT_ARCH
        bool
        default y
index 37ec644603ab886eb3221f7606488ce760dceb85..bcf825875d1706f4c108d4d75a5f24bbd814ba6b 100644 (file)
@@ -38,6 +38,14 @@ config TIME_LOW_RES
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 # Turn off some random 386 crap that can affect device config
 config ISA
        bool
index 3254a616c69ee4b8a056408dd89972724ef74ba9..3ac581d1720220cddf2601eed541064352bc3152 100644 (file)
@@ -101,6 +101,14 @@ config GENERIC_BUG
        default y
        depends on BUG
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 source "init/Kconfig"
 
 
index c1e69a1f92a4bf5adbc94e9f5417487502607cf4..9eccfbd1b536a4850132a7ead6a814d828f086f6 100644 (file)
@@ -34,6 +34,14 @@ config GENERIC_HARDIRQS
        bool
        default y
 
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
 source "init/Kconfig"
 
 menu "Processor type and features"
index 21422a3336ad19d4e4f4c522d68d6bd1770a7613..7ec7c4b937f9d82419f2ffab20e9d400590ad9e0 100644 (file)
@@ -124,7 +124,7 @@ static int mthca_query_device(struct ib_device *ibdev,
                props->max_map_per_fmr = 255;
        else
                props->max_map_per_fmr =
-                       (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1;
+                       (1 << (32 - ilog2(mdev->limits.num_mpts))) - 1;
 
        err = 0;
  out:
@@ -816,7 +816,7 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda
                lkey = ucmd.lkey;
        }
 
-       ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+       ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries), &status);
        if (status)
                ret = -EINVAL;
 
index 33e3ba7937f1950baa4c70bffd21f900b1878068..d844a2569b471f1dcfc5b63ddacbc31b45db22df 100644 (file)
@@ -636,11 +636,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
 
        if (mthca_is_memfree(dev)) {
                if (qp->rq.max)
-                       qp_context->rq_size_stride = long_log2(qp->rq.max) << 3;
+                       qp_context->rq_size_stride = ilog2(qp->rq.max) << 3;
                qp_context->rq_size_stride |= qp->rq.wqe_shift - 4;
 
                if (qp->sq.max)
-                       qp_context->sq_size_stride = long_log2(qp->sq.max) << 3;
+                       qp_context->sq_size_stride = ilog2(qp->sq.max) << 3;
                qp_context->sq_size_stride |= qp->sq.wqe_shift - 4;
        }
 
index 34d2c4768962126230e5edc5e5414753daaa0e2d..10684da33d5853e18e0cea25d9b219fbcd2b3b54 100644 (file)
@@ -120,7 +120,7 @@ static void mthca_arbel_init_srq_context(struct mthca_dev *dev,
 
        memset(context, 0, sizeof *context);
 
-       logsize = long_log2(srq->max);
+       logsize = ilog2(srq->max);
        context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn);
        context->lkey = cpu_to_be32(srq->mr.ibmr.lkey);
        context->db_index = cpu_to_be32(srq->db_index);
@@ -213,7 +213,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
        if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
                return -EINVAL;
 
-       srq->wqe_shift = long_log2(ds);
+       srq->wqe_shift = ilog2(ds);
 
        srq->srqn = mthca_alloc(&dev->srq_table.alloc);
        if (srq->srqn == -1)
index 5e122501fd80bdf35c1ba6608c2fe15b74c1202e..3aedd59b8a847edf20ecf2f75dece524f1e837da 100644 (file)
@@ -114,7 +114,7 @@ int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task  *iser_ctask,
 
        if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
                mem = (void *)__get_free_pages(GFP_NOIO,
-                     long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+                     ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
        else
                mem = kmalloc(cmd_data_len, GFP_NOIO);
 
@@ -211,7 +211,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
 
        if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
                free_pages((unsigned long)mem_copy->copy_buf,
-                          long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+                          ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
        else
                kfree(mem_copy->copy_buf);
 
index a1086ee8cccde1828860a24ee8667100e88dd701..96152868525b7715282ac36ac84d58ce38e66378 100644 (file)
@@ -220,7 +220,7 @@ static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
                              const char *opts)
 {
        unsigned int bs = crypto_blkcipher_blocksize(cc->tfm);
-       int log = long_log2(bs);
+       int log = ilog2(bs);
 
        /* we need to calculate how far we must shift the sector count
         * to get the cipher block count, we use this shift in _gen */
index e846499a004c676751659b40dc03e5c3e6ed509d..f18ad998b3cb05bf85925b83802c608dbfc899a1 100644 (file)
@@ -387,7 +387,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
 
        writel(TIFM_FIFO_INT_SETALL,
                sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-       writel(long_log2(cmd->data->blksz) - 2,
+       writel(ilog2(cmd->data->blksz) - 2,
                        sock->addr + SOCK_FIFO_PAGE_SIZE);
        writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
        writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
index 255cef5f7420f7d10fe4282c47e25bf9e597342e..6347c2dbdd819ad405082e83cbaa2966be185d77 100644 (file)
@@ -597,8 +597,6 @@ static int ext2_check_descriptors (struct super_block * sb)
        return 1;
 }
 
-#define log2(n) ffz(~(n))
 /*
  * Maximal file size.  There is a direct, and {,double-,triple-}indirect
  * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
@@ -834,9 +832,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_sbh = bh;
        sbi->s_mount_state = le16_to_cpu(es->s_state);
        sbi->s_addr_per_block_bits =
-               log2 (EXT2_ADDR_PER_BLOCK(sb));
+               ilog2 (EXT2_ADDR_PER_BLOCK(sb));
        sbi->s_desc_per_block_bits =
-               log2 (EXT2_DESC_PER_BLOCK(sb));
+               ilog2 (EXT2_DESC_PER_BLOCK(sb));
 
        if (sb->s_magic != EXT2_SUPER_MAGIC)
                goto cantfind_ext2;
index 580b8a6ca979a67b2412a9b8b2f16aaa4e232b92..b34886734a44d0417221231ba454bd6aa5aba2a5 100644 (file)
@@ -1347,8 +1347,6 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
 }
 
-#define log2(n) ffz(~(n))
-
 /*
  * Maximal file size.  There is a direct, and {,double-,triple-}indirect
  * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
@@ -1597,8 +1595,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc);
        sbi->s_sbh = bh;
        sbi->s_mount_state = le16_to_cpu(es->s_state);
-       sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
-       sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
+       sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb));
+       sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb));
        for (i=0; i < 4; i++)
                sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
        sbi->s_def_hash_version = es->s_def_hash_version;
index 1f70d47148bdb702e55126a0e854731d565ee9cd..f8560edf59ff8f30859b78c7142f461803bee1ee 100644 (file)
@@ -256,6 +256,50 @@ int __ffs(unsigned long x)
        return 31 - bit;
 }
 
+/*
+ * special slimline version of fls() for calculating ilog2_u32()
+ * - note: no protection against n == 0
+ */
+#define ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+       int bit;
+       asm("scan %1,gr0,%0" : "=r"(bit) : "r"(n));
+       return 31 - bit;
+}
+
+/*
+ * special slimline version of fls64() for calculating ilog2_u64()
+ * - note: no protection against n == 0
+ */
+#define ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+       union {
+               u64 ll;
+               struct { u32 h, l; };
+       } _;
+       int bit, x, y;
+
+       _.ll = n;
+
+       asm("   subcc           %3,gr0,gr0,icc0         \n"
+           "   ckeq            icc0,cc4                \n"
+           "   cscan.p         %3,gr0,%0       ,cc4,0  \n"
+           "   setlos          #63,%1                  \n"
+           "   cscan.p         %4,gr0,%0       ,cc4,1  \n"
+           "   setlos          #31,%2                  \n"
+           "   csub.p          %1,%0,%0        ,cc4,0  \n"
+           "   csub            %2,%0,%0        ,cc4,1  \n"
+           : "=&r"(bit), "=r"(x), "=r"(y)
+           : "0r"(_.h), "r"(_.l)
+           : "icc0", "cc4"
+           );
+       return bit;
+}
+
 #include <asm-generic/bitops/sched.h>
 #include <asm-generic/bitops/hweight.h>
 
index 6738283ac38550a1258b69fdf6b9e537c6abe1b2..3710cce16642fd9e04464a463d912363e2560f7f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 #include <linux/bitops.h>
+#include <linux/log2.h>
 #include <asm/byteorder.h>
 #include <asm/bug.h>
 
@@ -157,14 +158,6 @@ static inline int printk(const char *s, ...) { return 0; }
 
 unsigned long int_sqrt(unsigned long);
 
-static inline int __attribute_pure__ long_log2(unsigned long x)
-{
-       int r = 0;
-       for (x >>= 1; x > 0; x >>= 1)
-               r++;
-       return r;
-}
-
 static inline unsigned long
 __attribute_const__ roundup_pow_of_two(unsigned long x)
 {
diff --git a/include/linux/log2.h b/include/linux/log2.h
new file mode 100644 (file)
index 0000000..3979c60
--- /dev/null
@@ -0,0 +1,131 @@
+/* Integer base 2 logarithm calculation
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_LOG2_H
+#define _LINUX_LOG2_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const, noreturn))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ *   more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+#ifndef CONFIG_ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+       return fls(n) - 1;
+}
+#endif
+
+#ifndef CONFIG_ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+       return fls64(n) - 1;
+}
+#endif
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ *   the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n)                               \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               (n) < 1 ? ____ilog2_NaN() :     \
+               (n) & (1ULL << 63) ? 63 :       \
+               (n) & (1ULL << 62) ? 62 :       \
+               (n) & (1ULL << 61) ? 61 :       \
+               (n) & (1ULL << 60) ? 60 :       \
+               (n) & (1ULL << 59) ? 59 :       \
+               (n) & (1ULL << 58) ? 58 :       \
+               (n) & (1ULL << 57) ? 57 :       \
+               (n) & (1ULL << 56) ? 56 :       \
+               (n) & (1ULL << 55) ? 55 :       \
+               (n) & (1ULL << 54) ? 54 :       \
+               (n) & (1ULL << 53) ? 53 :       \
+               (n) & (1ULL << 52) ? 52 :       \
+               (n) & (1ULL << 51) ? 51 :       \
+               (n) & (1ULL << 50) ? 50 :       \
+               (n) & (1ULL << 49) ? 49 :       \
+               (n) & (1ULL << 48) ? 48 :       \
+               (n) & (1ULL << 47) ? 47 :       \
+               (n) & (1ULL << 46) ? 46 :       \
+               (n) & (1ULL << 45) ? 45 :       \
+               (n) & (1ULL << 44) ? 44 :       \
+               (n) & (1ULL << 43) ? 43 :       \
+               (n) & (1ULL << 42) ? 42 :       \
+               (n) & (1ULL << 41) ? 41 :       \
+               (n) & (1ULL << 40) ? 40 :       \
+               (n) & (1ULL << 39) ? 39 :       \
+               (n) & (1ULL << 38) ? 38 :       \
+               (n) & (1ULL << 37) ? 37 :       \
+               (n) & (1ULL << 36) ? 36 :       \
+               (n) & (1ULL << 35) ? 35 :       \
+               (n) & (1ULL << 34) ? 34 :       \
+               (n) & (1ULL << 33) ? 33 :       \
+               (n) & (1ULL << 32) ? 32 :       \
+               (n) & (1ULL << 31) ? 31 :       \
+               (n) & (1ULL << 30) ? 30 :       \
+               (n) & (1ULL << 29) ? 29 :       \
+               (n) & (1ULL << 28) ? 28 :       \
+               (n) & (1ULL << 27) ? 27 :       \
+               (n) & (1ULL << 26) ? 26 :       \
+               (n) & (1ULL << 25) ? 25 :       \
+               (n) & (1ULL << 24) ? 24 :       \
+               (n) & (1ULL << 23) ? 23 :       \
+               (n) & (1ULL << 22) ? 22 :       \
+               (n) & (1ULL << 21) ? 21 :       \
+               (n) & (1ULL << 20) ? 20 :       \
+               (n) & (1ULL << 19) ? 19 :       \
+               (n) & (1ULL << 18) ? 18 :       \
+               (n) & (1ULL << 17) ? 17 :       \
+               (n) & (1ULL << 16) ? 16 :       \
+               (n) & (1ULL << 15) ? 15 :       \
+               (n) & (1ULL << 14) ? 14 :       \
+               (n) & (1ULL << 13) ? 13 :       \
+               (n) & (1ULL << 12) ? 12 :       \
+               (n) & (1ULL << 11) ? 11 :       \
+               (n) & (1ULL << 10) ? 10 :       \
+               (n) & (1ULL <<  9) ?  9 :       \
+               (n) & (1ULL <<  8) ?  8 :       \
+               (n) & (1ULL <<  7) ?  7 :       \
+               (n) & (1ULL <<  6) ?  6 :       \
+               (n) & (1ULL <<  5) ?  5 :       \
+               (n) & (1ULL <<  4) ?  4 :       \
+               (n) & (1ULL <<  3) ?  3 :       \
+               (n) & (1ULL <<  2) ?  2 :       \
+               (n) & (1ULL <<  1) ?  1 :       \
+               (n) & (1ULL <<  0) ?  0 :       \
+               ____ilog2_NaN()                 \
+                                  ) :          \
+       (sizeof(n) <= 4) ?                      \
+       __ilog2_u32(n) :                        \
+       __ilog2_u64(n)                          \
+ )
+
+#endif /* _LINUX_LOG2_H */
index cace22b3ac25dc0f4af6fe10a7cc0a74c9d32778..18f0e044c43df6c7a3cca2a8b717528d1840a61a 100644 (file)
@@ -3244,7 +3244,7 @@ void *__init alloc_large_system_hash(const char *tablename,
        if (numentries > max)
                numentries = max;
 
-       log2qty = long_log2(numentries);
+       log2qty = ilog2(numentries);
 
        do {
                size = bucketsize << log2qty;
@@ -3266,7 +3266,7 @@ void *__init alloc_large_system_hash(const char *tablename,
        printk("%s hash table entries: %d (order: %d, %lu bytes)\n",
               tablename,
               (1U << log2qty),
-              long_log2(size) - PAGE_SHIFT,
+              ilog2(size) - PAGE_SHIFT,
               size);
 
        if (_hash_shift)