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)
57f674f016SBjoern 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
65*7cbc4d87SJean-Sébastien Pédron #define HWEIGHT8(x) (__builtin_popcountg((uint8_t)(x)))
66*7cbc4d87SJean-Sébastien Pédron #define HWEIGHT16(x) (__builtin_popcountg((uint16_t)(x)))
67*7cbc4d87SJean-Sébastien Pédron #define HWEIGHT32(x) (__builtin_popcountg((uint32_t)(x)))
68*7cbc4d87SJean-Sébastien Pédron #define HWEIGHT64(x) (__builtin_popcountg((uint64_t)(x)))
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
2913fd7fd49SJean-Sébastien Pédron static inline void
__assign_bit(long bit,volatile unsigned long * addr,bool value)2923fd7fd49SJean-Sébastien Pédron __assign_bit(long bit, volatile unsigned long *addr, bool value)
2933fd7fd49SJean-Sébastien Pédron {
2943fd7fd49SJean-Sébastien Pédron if (value)
2953fd7fd49SJean-Sébastien Pédron __set_bit(bit, addr);
2963fd7fd49SJean-Sébastien Pédron else
2973fd7fd49SJean-Sébastien Pédron __clear_bit(bit, addr);
2983fd7fd49SJean-Sébastien Pédron }
2993fd7fd49SJean-Sébastien Pédron
300425da8ebSHans Petter Selasky static inline int
test_and_clear_bit(long bit,volatile unsigned long * var)301425da8ebSHans Petter Selasky test_and_clear_bit(long bit, volatile unsigned long *var)
3028d59ecb2SHans Petter Selasky {
3038d59ecb2SHans Petter Selasky long val;
3048d59ecb2SHans Petter Selasky
3058d59ecb2SHans Petter Selasky var += BIT_WORD(bit);
3068d59ecb2SHans Petter Selasky bit %= BITS_PER_LONG;
3078d59ecb2SHans Petter Selasky bit = (1UL << bit);
3088d59ecb2SHans Petter Selasky
3096402bc3dSHans Petter Selasky val = *var;
3106402bc3dSHans Petter Selasky while (!atomic_fcmpset_long(var, &val, val & ~bit))
3116402bc3dSHans Petter Selasky ;
3128d59ecb2SHans Petter Selasky return !!(val & bit);
3138d59ecb2SHans Petter Selasky }
3148d59ecb2SHans Petter Selasky
315425da8ebSHans Petter Selasky static inline int
__test_and_clear_bit(long bit,volatile unsigned long * var)316cffaf933SHans Petter Selasky __test_and_clear_bit(long bit, volatile unsigned long *var)
317cffaf933SHans Petter Selasky {
318cffaf933SHans Petter Selasky long val;
319cffaf933SHans Petter Selasky
320cffaf933SHans Petter Selasky var += BIT_WORD(bit);
321cffaf933SHans Petter Selasky bit %= BITS_PER_LONG;
322cffaf933SHans Petter Selasky bit = (1UL << bit);
323cffaf933SHans Petter Selasky
324cffaf933SHans Petter Selasky val = *var;
325cffaf933SHans Petter Selasky *var &= ~bit;
326cffaf933SHans Petter Selasky
327cffaf933SHans Petter Selasky return !!(val & bit);
328cffaf933SHans Petter Selasky }
329cffaf933SHans Petter Selasky
330cffaf933SHans Petter Selasky static inline int
test_and_set_bit(long bit,volatile unsigned long * var)331425da8ebSHans Petter Selasky test_and_set_bit(long bit, volatile unsigned long *var)
3328d59ecb2SHans Petter Selasky {
3338d59ecb2SHans Petter Selasky long val;
3348d59ecb2SHans Petter Selasky
3358d59ecb2SHans Petter Selasky var += BIT_WORD(bit);
3368d59ecb2SHans Petter Selasky bit %= BITS_PER_LONG;
3378d59ecb2SHans Petter Selasky bit = (1UL << bit);
3388d59ecb2SHans Petter Selasky
3396402bc3dSHans Petter Selasky val = *var;
3406402bc3dSHans Petter Selasky while (!atomic_fcmpset_long(var, &val, val | bit))
3416402bc3dSHans Petter Selasky ;
3428d59ecb2SHans Petter Selasky return !!(val & bit);
3438d59ecb2SHans Petter Selasky }
3448d59ecb2SHans Petter Selasky
345cffaf933SHans Petter Selasky static inline int
__test_and_set_bit(long bit,volatile unsigned long * var)346cffaf933SHans Petter Selasky __test_and_set_bit(long bit, volatile unsigned long *var)
347cffaf933SHans Petter Selasky {
348cffaf933SHans Petter Selasky long val;
349cffaf933SHans Petter Selasky
350cffaf933SHans Petter Selasky var += BIT_WORD(bit);
351cffaf933SHans Petter Selasky bit %= BITS_PER_LONG;
352cffaf933SHans Petter Selasky bit = (1UL << bit);
353cffaf933SHans Petter Selasky
354cffaf933SHans Petter Selasky val = *var;
355cffaf933SHans Petter Selasky *var |= bit;
356cffaf933SHans Petter Selasky
357cffaf933SHans Petter Selasky return !!(val & bit);
358cffaf933SHans Petter Selasky }
359cffaf933SHans Petter Selasky
3608d59ecb2SHans Petter Selasky enum {
3618d59ecb2SHans Petter Selasky REG_OP_ISFREE,
3628d59ecb2SHans Petter Selasky REG_OP_ALLOC,
3638d59ecb2SHans Petter Selasky REG_OP_RELEASE,
3648d59ecb2SHans Petter Selasky };
3658d59ecb2SHans Petter Selasky
366425da8ebSHans Petter Selasky static inline int
linux_reg_op(unsigned long * bitmap,int pos,int order,int reg_op)367c9dd0b48SHans Petter Selasky linux_reg_op(unsigned long *bitmap, int pos, int order, int reg_op)
3688d59ecb2SHans Petter Selasky {
3698d59ecb2SHans Petter Selasky int nbits_reg;
3708d59ecb2SHans Petter Selasky int index;
3718d59ecb2SHans Petter Selasky int offset;
3728d59ecb2SHans Petter Selasky int nlongs_reg;
3738d59ecb2SHans Petter Selasky int nbitsinlong;
3748d59ecb2SHans Petter Selasky unsigned long mask;
3758d59ecb2SHans Petter Selasky int i;
3768d59ecb2SHans Petter Selasky int ret = 0;
3778d59ecb2SHans Petter Selasky
3788d59ecb2SHans Petter Selasky nbits_reg = 1 << order;
3798d59ecb2SHans Petter Selasky index = pos / BITS_PER_LONG;
3808d59ecb2SHans Petter Selasky offset = pos - (index * BITS_PER_LONG);
3818d59ecb2SHans Petter Selasky nlongs_reg = BITS_TO_LONGS(nbits_reg);
382a399cf13SHans Petter Selasky nbitsinlong = MIN(nbits_reg, BITS_PER_LONG);
3838d59ecb2SHans Petter Selasky
3848d59ecb2SHans Petter Selasky mask = (1UL << (nbitsinlong - 1));
3858d59ecb2SHans Petter Selasky mask += mask - 1;
3868d59ecb2SHans Petter Selasky mask <<= offset;
3878d59ecb2SHans Petter Selasky
3888d59ecb2SHans Petter Selasky switch (reg_op) {
3898d59ecb2SHans Petter Selasky case REG_OP_ISFREE:
3908d59ecb2SHans Petter Selasky for (i = 0; i < nlongs_reg; i++) {
3918d59ecb2SHans Petter Selasky if (bitmap[index + i] & mask)
3928d59ecb2SHans Petter Selasky goto done;
3938d59ecb2SHans Petter Selasky }
3948d59ecb2SHans Petter Selasky ret = 1;
3958d59ecb2SHans Petter Selasky break;
3968d59ecb2SHans Petter Selasky
3978d59ecb2SHans Petter Selasky case REG_OP_ALLOC:
3988d59ecb2SHans Petter Selasky for (i = 0; i < nlongs_reg; i++)
3998d59ecb2SHans Petter Selasky bitmap[index + i] |= mask;
4008d59ecb2SHans Petter Selasky break;
4018d59ecb2SHans Petter Selasky
4028d59ecb2SHans Petter Selasky case REG_OP_RELEASE:
4038d59ecb2SHans Petter Selasky for (i = 0; i < nlongs_reg; i++)
4048d59ecb2SHans Petter Selasky bitmap[index + i] &= ~mask;
4058d59ecb2SHans Petter Selasky break;
4068d59ecb2SHans Petter Selasky }
4078d59ecb2SHans Petter Selasky done:
4088d59ecb2SHans Petter Selasky return ret;
4098d59ecb2SHans Petter Selasky }
4108d59ecb2SHans Petter Selasky
4118d59ecb2SHans Petter Selasky #define for_each_set_bit(bit, addr, size) \
4128d59ecb2SHans Petter Selasky for ((bit) = find_first_bit((addr), (size)); \
4138d59ecb2SHans Petter Selasky (bit) < (size); \
4148d59ecb2SHans Petter Selasky (bit) = find_next_bit((addr), (size), (bit) + 1))
4158d59ecb2SHans Petter Selasky
4169bce524eSHans Petter Selasky #define for_each_clear_bit(bit, addr, size) \
4179bce524eSHans Petter Selasky for ((bit) = find_first_zero_bit((addr), (size)); \
4189bce524eSHans Petter Selasky (bit) < (size); \
4199bce524eSHans Petter Selasky (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
420e2829794SHans Petter Selasky
4213cfeca84SHans Petter Selasky static inline uint64_t
sign_extend64(uint64_t value,int index)4223cfeca84SHans Petter Selasky sign_extend64(uint64_t value, int index)
4233cfeca84SHans Petter Selasky {
4243cfeca84SHans Petter Selasky uint8_t shift = 63 - index;
4253cfeca84SHans Petter Selasky
4263cfeca84SHans Petter Selasky return ((int64_t)(value << shift) >> shift);
4273cfeca84SHans Petter Selasky }
4283cfeca84SHans Petter Selasky
429ea4dea83SBjoern A. Zeeb static inline uint32_t
sign_extend32(uint32_t value,int index)430ea4dea83SBjoern A. Zeeb sign_extend32(uint32_t value, int index)
431ea4dea83SBjoern A. Zeeb {
432ea4dea83SBjoern A. Zeeb uint8_t shift = 31 - index;
433ea4dea83SBjoern A. Zeeb
434ea4dea83SBjoern A. Zeeb return ((int32_t)(value << shift) >> shift);
435ea4dea83SBjoern A. Zeeb }
436ea4dea83SBjoern A. Zeeb
437307f78f3SVladimir Kondratyev #endif /* _LINUXKPI_LINUX_BITOPS_H_ */
438