18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky * Copyright (c) 2010 Panasas, Inc.
5c9dd0b48SHans Petter Selasky * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky * All rights reserved.
78d59ecb2SHans Petter Selasky *
88d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without
98d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions
108d59ecb2SHans Petter Selasky * are met:
118d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
128d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following
138d59ecb2SHans Petter Selasky * disclaimer.
148d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
158d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
168d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution.
178d59ecb2SHans Petter Selasky *
188d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288d59ecb2SHans Petter Selasky */
29307f78f3SVladimir Kondratyev #ifndef _LINUXKPI_LINUX_BITOPS_H_
30307f78f3SVladimir Kondratyev #define _LINUXKPI_LINUX_BITOPS_H_
318d59ecb2SHans Petter Selasky
321e3db1deSHans Petter Selasky #include <sys/param.h>
338d59ecb2SHans Petter Selasky #include <sys/types.h>
348d59ecb2SHans Petter Selasky #include <sys/systm.h>
358e7baabcSHans Petter Selasky #include <sys/errno.h>
363cfeca84SHans Petter Selasky #include <sys/libkern.h>
378d59ecb2SHans Petter Selasky
388d59ecb2SHans Petter Selasky #define BIT(nr) (1UL << (nr))
39797046eeSHans Petter Selasky #define BIT_ULL(nr) (1ULL << (nr))
408d59ecb2SHans Petter Selasky #ifdef __LP64__
418d59ecb2SHans Petter Selasky #define BITS_PER_LONG 64
428d59ecb2SHans Petter Selasky #else
438d59ecb2SHans Petter Selasky #define BITS_PER_LONG 32
448d59ecb2SHans Petter Selasky #endif
453cfeca84SHans Petter Selasky
465d503e30SHans Petter Selasky #define BITS_PER_LONG_LONG 64
475d503e30SHans Petter Selasky
488d59ecb2SHans Petter Selasky #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
498d59ecb2SHans Petter Selasky #define BITMAP_LAST_WORD_MASK(n) (~0UL >> (BITS_PER_LONG - (n)))
508d59ecb2SHans Petter Selasky #define BITS_TO_LONGS(n) howmany((n), BITS_PER_LONG)
518d59ecb2SHans Petter Selasky #define BIT_MASK(nr) (1UL << ((nr) & (BITS_PER_LONG - 1)))
528d59ecb2SHans Petter Selasky #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
53b5c54182SHans Petter Selasky #define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))
545d503e30SHans Petter Selasky #define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))
558d59ecb2SHans Petter Selasky #define BITS_PER_BYTE 8
56884aaac6SHans Petter Selasky #define BITS_PER_TYPE(t) (sizeof(t) * BITS_PER_BYTE)
57*f674f016SBjoern A. Zeeb #define BITS_TO_BYTES(n) howmany((n), BITS_PER_BYTE)
588d59ecb2SHans Petter Selasky
593cfeca84SHans Petter Selasky #define hweight8(x) bitcount((uint8_t)(x))
603cfeca84SHans Petter Selasky #define hweight16(x) bitcount16(x)
613cfeca84SHans Petter Selasky #define hweight32(x) bitcount32(x)
623cfeca84SHans Petter Selasky #define hweight64(x) bitcount64(x)
633cfeca84SHans Petter Selasky #define hweight_long(x) bitcountl(x)
643cfeca84SHans Petter Selasky
654cc8a9daSBjoern A. Zeeb #define HWEIGHT8(x) (bitcount8((uint8_t)(x)) + 1)
664cc8a9daSBjoern A. Zeeb #define HWEIGHT16(x) (bitcount16(x) + 1)
674cc8a9daSBjoern A. Zeeb #define HWEIGHT32(x) (bitcount32(x) + 1)
684cc8a9daSBjoern A. Zeeb #define HWEIGHT64(x) (bitcount64(x) + 1)
694cc8a9daSBjoern A. Zeeb
708d59ecb2SHans Petter Selasky static inline int
__ffs(int mask)718d59ecb2SHans Petter Selasky __ffs(int mask)
728d59ecb2SHans Petter Selasky {
738d59ecb2SHans Petter Selasky return (ffs(mask) - 1);
748d59ecb2SHans Petter Selasky }
758d59ecb2SHans Petter Selasky
768d59ecb2SHans Petter Selasky static inline int
__fls(int mask)778d59ecb2SHans Petter Selasky __fls(int mask)
788d59ecb2SHans Petter Selasky {
798d59ecb2SHans Petter Selasky return (fls(mask) - 1);
808d59ecb2SHans Petter Selasky }
818d59ecb2SHans Petter Selasky
828d59ecb2SHans Petter Selasky static inline int
__ffsl(long mask)838d59ecb2SHans Petter Selasky __ffsl(long mask)
848d59ecb2SHans Petter Selasky {
858d59ecb2SHans Petter Selasky return (ffsl(mask) - 1);
868d59ecb2SHans Petter Selasky }
878d59ecb2SHans Petter Selasky
88d17b78aaSBjoern A. Zeeb static inline unsigned long
__ffs64(uint64_t mask)89d17b78aaSBjoern A. Zeeb __ffs64(uint64_t mask)
90d17b78aaSBjoern A. Zeeb {
91d17b78aaSBjoern A. Zeeb return (ffsll(mask) - 1);
92d17b78aaSBjoern A. Zeeb }
93d17b78aaSBjoern A. Zeeb
948d59ecb2SHans Petter Selasky static inline int
__flsl(long mask)958d59ecb2SHans Petter Selasky __flsl(long mask)
968d59ecb2SHans Petter Selasky {
978d59ecb2SHans Petter Selasky return (flsl(mask) - 1);
988d59ecb2SHans Petter Selasky }
998d59ecb2SHans Petter Selasky
1003cfeca84SHans Petter Selasky static inline int
fls64(uint64_t mask)1013cfeca84SHans Petter Selasky fls64(uint64_t mask)
1023cfeca84SHans Petter Selasky {
1033cfeca84SHans Petter Selasky return (flsll(mask));
1043cfeca84SHans Petter Selasky }
1053cfeca84SHans Petter Selasky
10683cfd834SHans Petter Selasky static inline uint32_t
ror32(uint32_t word,unsigned int shift)10783cfd834SHans Petter Selasky ror32(uint32_t word, unsigned int shift)
10883cfd834SHans Petter Selasky {
10983cfd834SHans Petter Selasky return ((word >> shift) | (word << (32 - shift)));
11083cfd834SHans Petter Selasky }
1118d59ecb2SHans Petter Selasky
1128d59ecb2SHans Petter Selasky #define ffz(mask) __ffs(~(mask))
1138d59ecb2SHans Petter Selasky
get_count_order(unsigned int count)1148d59ecb2SHans Petter Selasky static inline int get_count_order(unsigned int count)
1158d59ecb2SHans Petter Selasky {
1168d59ecb2SHans Petter Selasky int order;
1178d59ecb2SHans Petter Selasky
1188d59ecb2SHans Petter Selasky order = fls(count) - 1;
1198d59ecb2SHans Petter Selasky if (count & (count - 1))
1208d59ecb2SHans Petter Selasky order++;
1218d59ecb2SHans Petter Selasky return order;
1228d59ecb2SHans Petter Selasky }
1238d59ecb2SHans Petter Selasky
1248d59ecb2SHans Petter Selasky static inline unsigned long
find_first_bit(const unsigned long * addr,unsigned long size)125425da8ebSHans Petter Selasky find_first_bit(const unsigned long *addr, unsigned long size)
1268d59ecb2SHans Petter Selasky {
1278d59ecb2SHans Petter Selasky long mask;
1288d59ecb2SHans Petter Selasky int bit;
1298d59ecb2SHans Petter Selasky
1308d59ecb2SHans Petter Selasky for (bit = 0; size >= BITS_PER_LONG;
1318d59ecb2SHans Petter Selasky size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
1328d59ecb2SHans Petter Selasky if (*addr == 0)
1338d59ecb2SHans Petter Selasky continue;
1348d59ecb2SHans Petter Selasky return (bit + __ffsl(*addr));
1358d59ecb2SHans Petter Selasky }
1368d59ecb2SHans Petter Selasky if (size) {
1378d59ecb2SHans Petter Selasky mask = (*addr) & BITMAP_LAST_WORD_MASK(size);
1388d59ecb2SHans Petter Selasky if (mask)
1398d59ecb2SHans Petter Selasky bit += __ffsl(mask);
1408d59ecb2SHans Petter Selasky else
1418d59ecb2SHans Petter Selasky bit += size;
1428d59ecb2SHans Petter Selasky }
1438d59ecb2SHans Petter Selasky return (bit);
1448d59ecb2SHans Petter Selasky }
1458d59ecb2SHans Petter Selasky
1468d59ecb2SHans Petter Selasky static inline unsigned long
find_first_zero_bit(const unsigned long * addr,unsigned long size)147425da8ebSHans Petter Selasky find_first_zero_bit(const unsigned long *addr, unsigned long size)
1488d59ecb2SHans Petter Selasky {
1498d59ecb2SHans Petter Selasky long mask;
1508d59ecb2SHans Petter Selasky int bit;
1518d59ecb2SHans Petter Selasky
1528d59ecb2SHans Petter Selasky for (bit = 0; size >= BITS_PER_LONG;
1538d59ecb2SHans Petter Selasky size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
1548d59ecb2SHans Petter Selasky if (~(*addr) == 0)
1558d59ecb2SHans Petter Selasky continue;
1568d59ecb2SHans Petter Selasky return (bit + __ffsl(~(*addr)));
1578d59ecb2SHans Petter Selasky }
1588d59ecb2SHans Petter Selasky if (size) {
1598d59ecb2SHans Petter Selasky mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);
1608d59ecb2SHans Petter Selasky if (mask)
1618d59ecb2SHans Petter Selasky bit += __ffsl(mask);
1628d59ecb2SHans Petter Selasky else
1638d59ecb2SHans Petter Selasky bit += size;
1648d59ecb2SHans Petter Selasky }
1658d59ecb2SHans Petter Selasky return (bit);
1668d59ecb2SHans Petter Selasky }
1678d59ecb2SHans Petter Selasky
1688d59ecb2SHans Petter Selasky static inline unsigned long
find_last_bit(const unsigned long * addr,unsigned long size)169425da8ebSHans Petter Selasky find_last_bit(const unsigned long *addr, unsigned long size)
1708d59ecb2SHans Petter Selasky {
1718d59ecb2SHans Petter Selasky long mask;
1728d59ecb2SHans Petter Selasky int offs;
1738d59ecb2SHans Petter Selasky int bit;
1748d59ecb2SHans Petter Selasky int pos;
1758d59ecb2SHans Petter Selasky
1768d59ecb2SHans Petter Selasky pos = size / BITS_PER_LONG;
1778d59ecb2SHans Petter Selasky offs = size % BITS_PER_LONG;
1788d59ecb2SHans Petter Selasky bit = BITS_PER_LONG * pos;
1798d59ecb2SHans Petter Selasky addr += pos;
1808d59ecb2SHans Petter Selasky if (offs) {
1818d59ecb2SHans Petter Selasky mask = (*addr) & BITMAP_LAST_WORD_MASK(offs);
1828d59ecb2SHans Petter Selasky if (mask)
1838d59ecb2SHans Petter Selasky return (bit + __flsl(mask));
1848d59ecb2SHans Petter Selasky }
1859ad5ce9dSHans Petter Selasky while (pos--) {
1868d59ecb2SHans Petter Selasky addr--;
1878d59ecb2SHans Petter Selasky bit -= BITS_PER_LONG;
1888d59ecb2SHans Petter Selasky if (*addr)
1899ad5ce9dSHans Petter Selasky return (bit + __flsl(*addr));
1908d59ecb2SHans Petter Selasky }
1918d59ecb2SHans Petter Selasky return (size);
1928d59ecb2SHans Petter Selasky }
1938d59ecb2SHans Petter Selasky
1948d59ecb2SHans Petter Selasky static inline unsigned long
find_next_bit(const unsigned long * addr,unsigned long size,unsigned long offset)195425da8ebSHans Petter Selasky find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
1968d59ecb2SHans Petter Selasky {
1978d59ecb2SHans Petter Selasky long mask;
1988d59ecb2SHans Petter Selasky int offs;
1998d59ecb2SHans Petter Selasky int bit;
2008d59ecb2SHans Petter Selasky int pos;
2018d59ecb2SHans Petter Selasky
2028d59ecb2SHans Petter Selasky if (offset >= size)
2038d59ecb2SHans Petter Selasky return (size);
2048d59ecb2SHans Petter Selasky pos = offset / BITS_PER_LONG;
2058d59ecb2SHans Petter Selasky offs = offset % BITS_PER_LONG;
2068d59ecb2SHans Petter Selasky bit = BITS_PER_LONG * pos;
2078d59ecb2SHans Petter Selasky addr += pos;
2088d59ecb2SHans Petter Selasky if (offs) {
2098d59ecb2SHans Petter Selasky mask = (*addr) & ~BITMAP_LAST_WORD_MASK(offs);
2108d59ecb2SHans Petter Selasky if (mask)
2118d59ecb2SHans Petter Selasky return (bit + __ffsl(mask));
2128d59ecb2SHans Petter Selasky if (size - bit <= BITS_PER_LONG)
2138d59ecb2SHans Petter Selasky return (size);
2148d59ecb2SHans Petter Selasky bit += BITS_PER_LONG;
2158d59ecb2SHans Petter Selasky addr++;
2168d59ecb2SHans Petter Selasky }
2178d59ecb2SHans Petter Selasky for (size -= bit; size >= BITS_PER_LONG;
2188d59ecb2SHans Petter Selasky size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
2198d59ecb2SHans Petter Selasky if (*addr == 0)
2208d59ecb2SHans Petter Selasky continue;
2218d59ecb2SHans Petter Selasky return (bit + __ffsl(*addr));
2228d59ecb2SHans Petter Selasky }
2238d59ecb2SHans Petter Selasky if (size) {
2248d59ecb2SHans Petter Selasky mask = (*addr) & BITMAP_LAST_WORD_MASK(size);
2258d59ecb2SHans Petter Selasky if (mask)
2268d59ecb2SHans Petter Selasky bit += __ffsl(mask);
2278d59ecb2SHans Petter Selasky else
2288d59ecb2SHans Petter Selasky bit += size;
2298d59ecb2SHans Petter Selasky }
2308d59ecb2SHans Petter Selasky return (bit);
2318d59ecb2SHans Petter Selasky }
2328d59ecb2SHans Petter Selasky
2338d59ecb2SHans Petter Selasky static inline unsigned long
find_next_zero_bit(const unsigned long * addr,unsigned long size,unsigned long offset)234425da8ebSHans Petter Selasky find_next_zero_bit(const unsigned long *addr, unsigned long size,
2358d59ecb2SHans Petter Selasky unsigned long offset)
2368d59ecb2SHans Petter Selasky {
2378d59ecb2SHans Petter Selasky long mask;
2388d59ecb2SHans Petter Selasky int offs;
2398d59ecb2SHans Petter Selasky int bit;
2408d59ecb2SHans Petter Selasky int pos;
2418d59ecb2SHans Petter Selasky
2428d59ecb2SHans Petter Selasky if (offset >= size)
2438d59ecb2SHans Petter Selasky return (size);
2448d59ecb2SHans Petter Selasky pos = offset / BITS_PER_LONG;
2458d59ecb2SHans Petter Selasky offs = offset % BITS_PER_LONG;
2468d59ecb2SHans Petter Selasky bit = BITS_PER_LONG * pos;
2478d59ecb2SHans Petter Selasky addr += pos;
2488d59ecb2SHans Petter Selasky if (offs) {
2498d59ecb2SHans Petter Selasky mask = ~(*addr) & ~BITMAP_LAST_WORD_MASK(offs);
2508d59ecb2SHans Petter Selasky if (mask)
2518d59ecb2SHans Petter Selasky return (bit + __ffsl(mask));
2528d59ecb2SHans Petter Selasky if (size - bit <= BITS_PER_LONG)
2538d59ecb2SHans Petter Selasky return (size);
2548d59ecb2SHans Petter Selasky bit += BITS_PER_LONG;
2558d59ecb2SHans Petter Selasky addr++;
2568d59ecb2SHans Petter Selasky }
2578d59ecb2SHans Petter Selasky for (size -= bit; size >= BITS_PER_LONG;
2588d59ecb2SHans Petter Selasky size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
2598d59ecb2SHans Petter Selasky if (~(*addr) == 0)
2608d59ecb2SHans Petter Selasky continue;
2618d59ecb2SHans Petter Selasky return (bit + __ffsl(~(*addr)));
2628d59ecb2SHans Petter Selasky }
2638d59ecb2SHans Petter Selasky if (size) {
2648d59ecb2SHans Petter Selasky mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);
2658d59ecb2SHans Petter Selasky if (mask)
2668d59ecb2SHans Petter Selasky bit += __ffsl(mask);
2678d59ecb2SHans Petter Selasky else
2688d59ecb2SHans Petter Selasky bit += size;
2698d59ecb2SHans Petter Selasky }
2708d59ecb2SHans Petter Selasky return (bit);
2718d59ecb2SHans Petter Selasky }
2728d59ecb2SHans Petter Selasky
2738d59ecb2SHans Petter Selasky #define __set_bit(i, a) \
274425da8ebSHans Petter Selasky atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
2758d59ecb2SHans Petter Selasky
2768d59ecb2SHans Petter Selasky #define set_bit(i, a) \
277425da8ebSHans Petter Selasky atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
2788d59ecb2SHans Petter Selasky
2798d59ecb2SHans Petter Selasky #define __clear_bit(i, a) \
280425da8ebSHans Petter Selasky atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
2818d59ecb2SHans Petter Selasky
2828d59ecb2SHans Petter Selasky #define clear_bit(i, a) \
283425da8ebSHans Petter Selasky atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
2848d59ecb2SHans Petter Selasky
28574d3a635SHans Petter Selasky #define clear_bit_unlock(i, a) \
28674d3a635SHans Petter Selasky atomic_clear_rel_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
28774d3a635SHans Petter Selasky
2888d59ecb2SHans Petter Selasky #define test_bit(i, a) \
28907fdea36SHans Petter Selasky !!(READ_ONCE(((volatile const unsigned long *)(a))[BIT_WORD(i)]) & BIT_MASK(i))
2908d59ecb2SHans Petter Selasky
291425da8ebSHans Petter Selasky static inline int
test_and_clear_bit(long bit,volatile unsigned long * var)292425da8ebSHans Petter Selasky test_and_clear_bit(long bit, volatile unsigned long *var)
2938d59ecb2SHans Petter Selasky {
2948d59ecb2SHans Petter Selasky long val;
2958d59ecb2SHans Petter Selasky
2968d59ecb2SHans Petter Selasky var += BIT_WORD(bit);
2978d59ecb2SHans Petter Selasky bit %= BITS_PER_LONG;
2988d59ecb2SHans Petter Selasky bit = (1UL << bit);
2998d59ecb2SHans Petter Selasky
3006402bc3dSHans Petter Selasky val = *var;
3016402bc3dSHans Petter Selasky while (!atomic_fcmpset_long(var, &val, val & ~bit))
3026402bc3dSHans Petter Selasky ;
3038d59ecb2SHans Petter Selasky return !!(val & bit);
3048d59ecb2SHans Petter Selasky }
3058d59ecb2SHans Petter Selasky
306425da8ebSHans Petter Selasky static inline int
__test_and_clear_bit(long bit,volatile unsigned long * var)307cffaf933SHans Petter Selasky __test_and_clear_bit(long bit, volatile unsigned long *var)
308cffaf933SHans Petter Selasky {
309cffaf933SHans Petter Selasky long val;
310cffaf933SHans Petter Selasky
311cffaf933SHans Petter Selasky var += BIT_WORD(bit);
312cffaf933SHans Petter Selasky bit %= BITS_PER_LONG;
313cffaf933SHans Petter Selasky bit = (1UL << bit);
314cffaf933SHans Petter Selasky
315cffaf933SHans Petter Selasky val = *var;
316cffaf933SHans Petter Selasky *var &= ~bit;
317cffaf933SHans Petter Selasky
318cffaf933SHans Petter Selasky return !!(val & bit);
319cffaf933SHans Petter Selasky }
320cffaf933SHans Petter Selasky
321cffaf933SHans Petter Selasky static inline int
test_and_set_bit(long bit,volatile unsigned long * var)322425da8ebSHans Petter Selasky test_and_set_bit(long bit, volatile unsigned long *var)
3238d59ecb2SHans Petter Selasky {
3248d59ecb2SHans Petter Selasky long val;
3258d59ecb2SHans Petter Selasky
3268d59ecb2SHans Petter Selasky var += BIT_WORD(bit);
3278d59ecb2SHans Petter Selasky bit %= BITS_PER_LONG;
3288d59ecb2SHans Petter Selasky bit = (1UL << bit);
3298d59ecb2SHans Petter Selasky
3306402bc3dSHans Petter Selasky val = *var;
3316402bc3dSHans Petter Selasky while (!atomic_fcmpset_long(var, &val, val | bit))
3326402bc3dSHans Petter Selasky ;
3338d59ecb2SHans Petter Selasky return !!(val & bit);
3348d59ecb2SHans Petter Selasky }
3358d59ecb2SHans Petter Selasky
336cffaf933SHans Petter Selasky static inline int
__test_and_set_bit(long bit,volatile unsigned long * var)337cffaf933SHans Petter Selasky __test_and_set_bit(long bit, volatile unsigned long *var)
338cffaf933SHans Petter Selasky {
339cffaf933SHans Petter Selasky long val;
340cffaf933SHans Petter Selasky
341cffaf933SHans Petter Selasky var += BIT_WORD(bit);
342cffaf933SHans Petter Selasky bit %= BITS_PER_LONG;
343cffaf933SHans Petter Selasky bit = (1UL << bit);
344cffaf933SHans Petter Selasky
345cffaf933SHans Petter Selasky val = *var;
346cffaf933SHans Petter Selasky *var |= bit;
347cffaf933SHans Petter Selasky
348cffaf933SHans Petter Selasky return !!(val & bit);
349cffaf933SHans Petter Selasky }
350cffaf933SHans Petter Selasky
3518d59ecb2SHans Petter Selasky enum {
3528d59ecb2SHans Petter Selasky REG_OP_ISFREE,
3538d59ecb2SHans Petter Selasky REG_OP_ALLOC,
3548d59ecb2SHans Petter Selasky REG_OP_RELEASE,
3558d59ecb2SHans Petter Selasky };
3568d59ecb2SHans Petter Selasky
357425da8ebSHans Petter Selasky static inline int
linux_reg_op(unsigned long * bitmap,int pos,int order,int reg_op)358c9dd0b48SHans Petter Selasky linux_reg_op(unsigned long *bitmap, int pos, int order, int reg_op)
3598d59ecb2SHans Petter Selasky {
3608d59ecb2SHans Petter Selasky int nbits_reg;
3618d59ecb2SHans Petter Selasky int index;
3628d59ecb2SHans Petter Selasky int offset;
3638d59ecb2SHans Petter Selasky int nlongs_reg;
3648d59ecb2SHans Petter Selasky int nbitsinlong;
3658d59ecb2SHans Petter Selasky unsigned long mask;
3668d59ecb2SHans Petter Selasky int i;
3678d59ecb2SHans Petter Selasky int ret = 0;
3688d59ecb2SHans Petter Selasky
3698d59ecb2SHans Petter Selasky nbits_reg = 1 << order;
3708d59ecb2SHans Petter Selasky index = pos / BITS_PER_LONG;
3718d59ecb2SHans Petter Selasky offset = pos - (index * BITS_PER_LONG);
3728d59ecb2SHans Petter Selasky nlongs_reg = BITS_TO_LONGS(nbits_reg);
373a399cf13SHans Petter Selasky nbitsinlong = MIN(nbits_reg, BITS_PER_LONG);
3748d59ecb2SHans Petter Selasky
3758d59ecb2SHans Petter Selasky mask = (1UL << (nbitsinlong - 1));
3768d59ecb2SHans Petter Selasky mask += mask - 1;
3778d59ecb2SHans Petter Selasky mask <<= offset;
3788d59ecb2SHans Petter Selasky
3798d59ecb2SHans Petter Selasky switch (reg_op) {
3808d59ecb2SHans Petter Selasky case REG_OP_ISFREE:
3818d59ecb2SHans Petter Selasky for (i = 0; i < nlongs_reg; i++) {
3828d59ecb2SHans Petter Selasky if (bitmap[index + i] & mask)
3838d59ecb2SHans Petter Selasky goto done;
3848d59ecb2SHans Petter Selasky }
3858d59ecb2SHans Petter Selasky ret = 1;
3868d59ecb2SHans Petter Selasky break;
3878d59ecb2SHans Petter Selasky
3888d59ecb2SHans Petter Selasky case REG_OP_ALLOC:
3898d59ecb2SHans Petter Selasky for (i = 0; i < nlongs_reg; i++)
3908d59ecb2SHans Petter Selasky bitmap[index + i] |= mask;
3918d59ecb2SHans Petter Selasky break;
3928d59ecb2SHans Petter Selasky
3938d59ecb2SHans Petter Selasky case REG_OP_RELEASE:
3948d59ecb2SHans Petter Selasky for (i = 0; i < nlongs_reg; i++)
3958d59ecb2SHans Petter Selasky bitmap[index + i] &= ~mask;
3968d59ecb2SHans Petter Selasky break;
3978d59ecb2SHans Petter Selasky }
3988d59ecb2SHans Petter Selasky done:
3998d59ecb2SHans Petter Selasky return ret;
4008d59ecb2SHans Petter Selasky }
4018d59ecb2SHans Petter Selasky
4028d59ecb2SHans Petter Selasky #define for_each_set_bit(bit, addr, size) \
4038d59ecb2SHans Petter Selasky for ((bit) = find_first_bit((addr), (size)); \
4048d59ecb2SHans Petter Selasky (bit) < (size); \
4058d59ecb2SHans Petter Selasky (bit) = find_next_bit((addr), (size), (bit) + 1))
4068d59ecb2SHans Petter Selasky
4079bce524eSHans Petter Selasky #define for_each_clear_bit(bit, addr, size) \
4089bce524eSHans Petter Selasky for ((bit) = find_first_zero_bit((addr), (size)); \
4099bce524eSHans Petter Selasky (bit) < (size); \
4109bce524eSHans Petter Selasky (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
411e2829794SHans Petter Selasky
4123cfeca84SHans Petter Selasky static inline uint64_t
sign_extend64(uint64_t value,int index)4133cfeca84SHans Petter Selasky sign_extend64(uint64_t value, int index)
4143cfeca84SHans Petter Selasky {
4153cfeca84SHans Petter Selasky uint8_t shift = 63 - index;
4163cfeca84SHans Petter Selasky
4173cfeca84SHans Petter Selasky return ((int64_t)(value << shift) >> shift);
4183cfeca84SHans Petter Selasky }
4193cfeca84SHans Petter Selasky
420ea4dea83SBjoern A. Zeeb static inline uint32_t
sign_extend32(uint32_t value,int index)421ea4dea83SBjoern A. Zeeb sign_extend32(uint32_t value, int index)
422ea4dea83SBjoern A. Zeeb {
423ea4dea83SBjoern A. Zeeb uint8_t shift = 31 - index;
424ea4dea83SBjoern A. Zeeb
425ea4dea83SBjoern A. Zeeb return ((int32_t)(value << shift) >> shift);
426ea4dea83SBjoern A. Zeeb }
427ea4dea83SBjoern A. Zeeb
428307f78f3SVladimir Kondratyev #endif /* _LINUXKPI_LINUX_BITOPS_H_ */
429