Path: blob/main/sys/compat/linuxkpi/common/include/linux/bitops.h
102156 views
/*-1* Copyright (c) 2010 Isilon Systems, Inc.2* Copyright (c) 2010 iX Systems, Inc.3* Copyright (c) 2010 Panasas, Inc.4* Copyright (c) 2013-2017 Mellanox Technologies, Ltd.5* All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice unmodified, this list of conditions, and the following12* disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR18* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES19* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.20* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,21* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT22* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF26* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27*/28#ifndef _LINUXKPI_LINUX_BITOPS_H_29#define _LINUXKPI_LINUX_BITOPS_H_3031#include <sys/param.h>32#include <sys/types.h>33#include <sys/systm.h>34#include <sys/errno.h>35#include <sys/libkern.h>3637#define BIT(nr) (1UL << (nr))38#define BIT_ULL(nr) (1ULL << (nr))39#define BITS_PER_LONG (__SIZEOF_LONG__ * __CHAR_BIT__)40#define BITS_PER_LONG_LONG (__SIZEOF_LONG_LONG__ * __CHAR_BIT__)4142#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))43#define BITMAP_LAST_WORD_MASK(n) (~0UL >> (BITS_PER_LONG - (n)))44#define BITS_TO_LONGS(n) howmany((n), BITS_PER_LONG)45#define BIT_MASK(nr) (1UL << ((nr) & (BITS_PER_LONG - 1)))46#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)47#define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))48#define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))49#define BITS_PER_BYTE 850#define BITS_PER_TYPE(t) (sizeof(t) * BITS_PER_BYTE)51#define BITS_TO_BYTES(n) howmany((n), BITS_PER_BYTE)5253#if __has_builtin(__builtin_popcountg)54#define HWEIGHT8(x) (__builtin_popcountg((uint8_t)(x)))55#define HWEIGHT16(x) (__builtin_popcountg((uint16_t)(x)))56#define HWEIGHT32(x) (__builtin_popcountg((uint32_t)(x)))57#define HWEIGHT64(x) (__builtin_popcountg((uint64_t)(x)))58#else59/* LLVM before 19, gcc before 14. */60#define HWEIGHT8(x) (__const_bitcount8((uint8_t)(x)))61#define HWEIGHT16(x) (__const_bitcount16((uint16_t)(x)))62#define HWEIGHT32(x) (__const_bitcount32((uint32_t)(x)))63#define HWEIGHT64(x) (__const_bitcount64((uint64_t)(x)))64#endif6566#define hweight8(x) (__builtin_constant_p(x) ? HWEIGHT8(x) : bitcount((uint8_t)(x)))67#define hweight16(x) (__builtin_constant_p(x) ? HWEIGHT16(x) : bitcount16(x))68#define hweight32(x) (__builtin_constant_p(x) ? HWEIGHT32(x) : bitcount32(x))69#define hweight64(x) (__builtin_constant_p(x) ? HWEIGHT64(x) : bitcount64(x))70#define hweight_long(x) bitcountl(x)7172static inline int73__ffs(int mask)74{75return (ffs(mask) - 1);76}7778static inline int79__fls(int mask)80{81return (fls(mask) - 1);82}8384static inline int85__ffsl(long mask)86{87return (ffsl(mask) - 1);88}8990static inline unsigned long91__ffs64(uint64_t mask)92{93return (ffsll(mask) - 1);94}9596static inline int97__flsl(long mask)98{99return (flsl(mask) - 1);100}101102static inline int103fls64(uint64_t mask)104{105return (flsll(mask));106}107108static inline uint32_t109ror32(uint32_t word, unsigned int shift)110{111return ((word >> shift) | (word << (32 - shift)));112}113114#define ffz(mask) __ffs(~(mask))115116static inline int get_count_order(unsigned int count)117{118int order;119120order = fls(count) - 1;121if (count & (count - 1))122order++;123return order;124}125126static inline unsigned long127find_first_bit(const unsigned long *addr, unsigned long size)128{129long mask;130int bit;131132for (bit = 0; size >= BITS_PER_LONG;133size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {134if (*addr == 0)135continue;136return (bit + __ffsl(*addr));137}138if (size) {139mask = (*addr) & BITMAP_LAST_WORD_MASK(size);140if (mask)141bit += __ffsl(mask);142else143bit += size;144}145return (bit);146}147148static inline unsigned long149find_first_zero_bit(const unsigned long *addr, unsigned long size)150{151long mask;152int bit;153154for (bit = 0; size >= BITS_PER_LONG;155size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {156if (~(*addr) == 0)157continue;158return (bit + __ffsl(~(*addr)));159}160if (size) {161mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);162if (mask)163bit += __ffsl(mask);164else165bit += size;166}167return (bit);168}169170static inline unsigned long171find_last_bit(const unsigned long *addr, unsigned long size)172{173long mask;174int offs;175int bit;176int pos;177178pos = size / BITS_PER_LONG;179offs = size % BITS_PER_LONG;180bit = BITS_PER_LONG * pos;181addr += pos;182if (offs) {183mask = (*addr) & BITMAP_LAST_WORD_MASK(offs);184if (mask)185return (bit + __flsl(mask));186}187while (pos--) {188addr--;189bit -= BITS_PER_LONG;190if (*addr)191return (bit + __flsl(*addr));192}193return (size);194}195196static inline unsigned long197find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)198{199long mask;200int offs;201int bit;202int pos;203204if (offset >= size)205return (size);206pos = offset / BITS_PER_LONG;207offs = offset % BITS_PER_LONG;208bit = BITS_PER_LONG * pos;209addr += pos;210if (offs) {211mask = (*addr) & ~BITMAP_LAST_WORD_MASK(offs);212if (mask)213return (bit + __ffsl(mask));214if (size - bit <= BITS_PER_LONG)215return (size);216bit += BITS_PER_LONG;217addr++;218}219for (size -= bit; size >= BITS_PER_LONG;220size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {221if (*addr == 0)222continue;223return (bit + __ffsl(*addr));224}225if (size) {226mask = (*addr) & BITMAP_LAST_WORD_MASK(size);227if (mask)228bit += __ffsl(mask);229else230bit += size;231}232return (bit);233}234235static inline unsigned long236find_next_zero_bit(const unsigned long *addr, unsigned long size,237unsigned long offset)238{239long mask;240int offs;241int bit;242int pos;243244if (offset >= size)245return (size);246pos = offset / BITS_PER_LONG;247offs = offset % BITS_PER_LONG;248bit = BITS_PER_LONG * pos;249addr += pos;250if (offs) {251mask = ~(*addr) & ~BITMAP_LAST_WORD_MASK(offs);252if (mask)253return (bit + __ffsl(mask));254if (size - bit <= BITS_PER_LONG)255return (size);256bit += BITS_PER_LONG;257addr++;258}259for (size -= bit; size >= BITS_PER_LONG;260size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {261if (~(*addr) == 0)262continue;263return (bit + __ffsl(~(*addr)));264}265if (size) {266mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);267if (mask)268bit += __ffsl(mask);269else270bit += size;271}272return (bit);273}274275#define __set_bit(i, a) \276atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))277278#define set_bit(i, a) \279atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))280281#define __clear_bit(i, a) \282atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))283284#define clear_bit(i, a) \285atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))286287#define clear_bit_unlock(i, a) \288atomic_clear_rel_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))289290#define test_bit(i, a) \291!!(READ_ONCE(((volatile const unsigned long *)(a))[BIT_WORD(i)]) & BIT_MASK(i))292293static inline void294__assign_bit(long bit, volatile unsigned long *addr, bool value)295{296if (value)297__set_bit(bit, addr);298else299__clear_bit(bit, addr);300}301302static inline int303test_and_clear_bit(long bit, volatile unsigned long *var)304{305long val;306307var += BIT_WORD(bit);308bit %= BITS_PER_LONG;309bit = (1UL << bit);310311val = *var;312while (!atomic_fcmpset_long(var, &val, val & ~bit))313;314return !!(val & bit);315}316317static inline int318__test_and_clear_bit(long bit, volatile unsigned long *var)319{320long val;321322var += BIT_WORD(bit);323bit %= BITS_PER_LONG;324bit = (1UL << bit);325326val = *var;327*var &= ~bit;328329return !!(val & bit);330}331332static inline int333test_and_set_bit(long bit, volatile unsigned long *var)334{335long val;336337var += BIT_WORD(bit);338bit %= BITS_PER_LONG;339bit = (1UL << bit);340341val = *var;342while (!atomic_fcmpset_long(var, &val, val | bit))343;344return !!(val & bit);345}346347static inline int348__test_and_set_bit(long bit, volatile unsigned long *var)349{350long val;351352var += BIT_WORD(bit);353bit %= BITS_PER_LONG;354bit = (1UL << bit);355356val = *var;357*var |= bit;358359return !!(val & bit);360}361362enum {363REG_OP_ISFREE,364REG_OP_ALLOC,365REG_OP_RELEASE,366};367368static inline int369linux_reg_op(unsigned long *bitmap, int pos, int order, int reg_op)370{371int nbits_reg;372int index;373int offset;374int nlongs_reg;375int nbitsinlong;376unsigned long mask;377int i;378int ret = 0;379380nbits_reg = 1 << order;381index = pos / BITS_PER_LONG;382offset = pos - (index * BITS_PER_LONG);383nlongs_reg = BITS_TO_LONGS(nbits_reg);384nbitsinlong = MIN(nbits_reg, BITS_PER_LONG);385386mask = (1UL << (nbitsinlong - 1));387mask += mask - 1;388mask <<= offset;389390switch (reg_op) {391case REG_OP_ISFREE:392for (i = 0; i < nlongs_reg; i++) {393if (bitmap[index + i] & mask)394goto done;395}396ret = 1;397break;398399case REG_OP_ALLOC:400for (i = 0; i < nlongs_reg; i++)401bitmap[index + i] |= mask;402break;403404case REG_OP_RELEASE:405for (i = 0; i < nlongs_reg; i++)406bitmap[index + i] &= ~mask;407break;408}409done:410return ret;411}412413#define for_each_set_bit(bit, addr, size) \414for ((bit) = find_first_bit((addr), (size)); \415(bit) < (size); \416(bit) = find_next_bit((addr), (size), (bit) + 1))417418#define for_each_clear_bit(bit, addr, size) \419for ((bit) = find_first_zero_bit((addr), (size)); \420(bit) < (size); \421(bit) = find_next_zero_bit((addr), (size), (bit) + 1))422423static inline uint64_t424sign_extend64(uint64_t value, int index)425{426uint8_t shift = 63 - index;427428return ((int64_t)(value << shift) >> shift);429}430431static inline uint32_t432sign_extend32(uint32_t value, int index)433{434uint8_t shift = 31 - index;435436return ((int32_t)(value << shift) >> shift);437}438439static inline uint64_t440rol64(uint64_t word, unsigned int shift)441{442return ((word << (shift & 63)) | (word >> ((-shift) & 63)));443}444445static inline uint32_t446rol32(uint32_t word, unsigned int shift)447{448return ((word << (shift & 31)) | (word >> ((-shift) & 31)));449}450451#endif /* _LINUXKPI_LINUX_BITOPS_H_ */452453454