xref: /freebsd-src/sys/compat/linuxkpi/common/include/linux/bitops.h (revision f674f016c03d49e14f1c651ed088a6f2d01a62ee)
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