Path: blob/main/sys/compat/linuxkpi/common/include/linux/bitops.h
39604 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#ifdef __LP64__40#define BITS_PER_LONG 6441#else42#define BITS_PER_LONG 3243#endif4445#define BITS_PER_LONG_LONG 644647#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))48#define BITMAP_LAST_WORD_MASK(n) (~0UL >> (BITS_PER_LONG - (n)))49#define BITS_TO_LONGS(n) howmany((n), BITS_PER_LONG)50#define BIT_MASK(nr) (1UL << ((nr) & (BITS_PER_LONG - 1)))51#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)52#define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))53#define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))54#define BITS_PER_BYTE 855#define BITS_PER_TYPE(t) (sizeof(t) * BITS_PER_BYTE)56#define BITS_TO_BYTES(n) howmany((n), BITS_PER_BYTE)5758#define hweight8(x) bitcount((uint8_t)(x))59#define hweight16(x) bitcount16(x)60#define hweight32(x) bitcount32(x)61#define hweight64(x) bitcount64(x)62#define hweight_long(x) bitcountl(x)6364#define HWEIGHT8(x) (__builtin_popcountg((uint8_t)(x)))65#define HWEIGHT16(x) (__builtin_popcountg((uint16_t)(x)))66#define HWEIGHT32(x) (__builtin_popcountg((uint32_t)(x)))67#define HWEIGHT64(x) (__builtin_popcountg((uint64_t)(x)))6869static inline int70__ffs(int mask)71{72return (ffs(mask) - 1);73}7475static inline int76__fls(int mask)77{78return (fls(mask) - 1);79}8081static inline int82__ffsl(long mask)83{84return (ffsl(mask) - 1);85}8687static inline unsigned long88__ffs64(uint64_t mask)89{90return (ffsll(mask) - 1);91}9293static inline int94__flsl(long mask)95{96return (flsl(mask) - 1);97}9899static inline int100fls64(uint64_t mask)101{102return (flsll(mask));103}104105static inline uint32_t106ror32(uint32_t word, unsigned int shift)107{108return ((word >> shift) | (word << (32 - shift)));109}110111#define ffz(mask) __ffs(~(mask))112113static inline int get_count_order(unsigned int count)114{115int order;116117order = fls(count) - 1;118if (count & (count - 1))119order++;120return order;121}122123static inline unsigned long124find_first_bit(const unsigned long *addr, unsigned long size)125{126long mask;127int bit;128129for (bit = 0; size >= BITS_PER_LONG;130size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {131if (*addr == 0)132continue;133return (bit + __ffsl(*addr));134}135if (size) {136mask = (*addr) & BITMAP_LAST_WORD_MASK(size);137if (mask)138bit += __ffsl(mask);139else140bit += size;141}142return (bit);143}144145static inline unsigned long146find_first_zero_bit(const unsigned long *addr, unsigned long size)147{148long mask;149int bit;150151for (bit = 0; size >= BITS_PER_LONG;152size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {153if (~(*addr) == 0)154continue;155return (bit + __ffsl(~(*addr)));156}157if (size) {158mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);159if (mask)160bit += __ffsl(mask);161else162bit += size;163}164return (bit);165}166167static inline unsigned long168find_last_bit(const unsigned long *addr, unsigned long size)169{170long mask;171int offs;172int bit;173int pos;174175pos = size / BITS_PER_LONG;176offs = size % BITS_PER_LONG;177bit = BITS_PER_LONG * pos;178addr += pos;179if (offs) {180mask = (*addr) & BITMAP_LAST_WORD_MASK(offs);181if (mask)182return (bit + __flsl(mask));183}184while (pos--) {185addr--;186bit -= BITS_PER_LONG;187if (*addr)188return (bit + __flsl(*addr));189}190return (size);191}192193static inline unsigned long194find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)195{196long mask;197int offs;198int bit;199int pos;200201if (offset >= size)202return (size);203pos = offset / BITS_PER_LONG;204offs = offset % BITS_PER_LONG;205bit = BITS_PER_LONG * pos;206addr += pos;207if (offs) {208mask = (*addr) & ~BITMAP_LAST_WORD_MASK(offs);209if (mask)210return (bit + __ffsl(mask));211if (size - bit <= BITS_PER_LONG)212return (size);213bit += BITS_PER_LONG;214addr++;215}216for (size -= bit; size >= BITS_PER_LONG;217size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {218if (*addr == 0)219continue;220return (bit + __ffsl(*addr));221}222if (size) {223mask = (*addr) & BITMAP_LAST_WORD_MASK(size);224if (mask)225bit += __ffsl(mask);226else227bit += size;228}229return (bit);230}231232static inline unsigned long233find_next_zero_bit(const unsigned long *addr, unsigned long size,234unsigned long offset)235{236long mask;237int offs;238int bit;239int pos;240241if (offset >= size)242return (size);243pos = offset / BITS_PER_LONG;244offs = offset % BITS_PER_LONG;245bit = BITS_PER_LONG * pos;246addr += pos;247if (offs) {248mask = ~(*addr) & ~BITMAP_LAST_WORD_MASK(offs);249if (mask)250return (bit + __ffsl(mask));251if (size - bit <= BITS_PER_LONG)252return (size);253bit += BITS_PER_LONG;254addr++;255}256for (size -= bit; size >= BITS_PER_LONG;257size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {258if (~(*addr) == 0)259continue;260return (bit + __ffsl(~(*addr)));261}262if (size) {263mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);264if (mask)265bit += __ffsl(mask);266else267bit += size;268}269return (bit);270}271272#define __set_bit(i, a) \273atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))274275#define set_bit(i, a) \276atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))277278#define __clear_bit(i, a) \279atomic_clear_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_unlock(i, a) \285atomic_clear_rel_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))286287#define test_bit(i, a) \288!!(READ_ONCE(((volatile const unsigned long *)(a))[BIT_WORD(i)]) & BIT_MASK(i))289290static inline void291__assign_bit(long bit, volatile unsigned long *addr, bool value)292{293if (value)294__set_bit(bit, addr);295else296__clear_bit(bit, addr);297}298299static inline int300test_and_clear_bit(long bit, volatile unsigned long *var)301{302long val;303304var += BIT_WORD(bit);305bit %= BITS_PER_LONG;306bit = (1UL << bit);307308val = *var;309while (!atomic_fcmpset_long(var, &val, val & ~bit))310;311return !!(val & bit);312}313314static inline int315__test_and_clear_bit(long bit, volatile unsigned long *var)316{317long val;318319var += BIT_WORD(bit);320bit %= BITS_PER_LONG;321bit = (1UL << bit);322323val = *var;324*var &= ~bit;325326return !!(val & bit);327}328329static inline int330test_and_set_bit(long bit, volatile unsigned long *var)331{332long val;333334var += BIT_WORD(bit);335bit %= BITS_PER_LONG;336bit = (1UL << bit);337338val = *var;339while (!atomic_fcmpset_long(var, &val, val | bit))340;341return !!(val & bit);342}343344static inline int345__test_and_set_bit(long bit, volatile unsigned long *var)346{347long val;348349var += BIT_WORD(bit);350bit %= BITS_PER_LONG;351bit = (1UL << bit);352353val = *var;354*var |= bit;355356return !!(val & bit);357}358359enum {360REG_OP_ISFREE,361REG_OP_ALLOC,362REG_OP_RELEASE,363};364365static inline int366linux_reg_op(unsigned long *bitmap, int pos, int order, int reg_op)367{368int nbits_reg;369int index;370int offset;371int nlongs_reg;372int nbitsinlong;373unsigned long mask;374int i;375int ret = 0;376377nbits_reg = 1 << order;378index = pos / BITS_PER_LONG;379offset = pos - (index * BITS_PER_LONG);380nlongs_reg = BITS_TO_LONGS(nbits_reg);381nbitsinlong = MIN(nbits_reg, BITS_PER_LONG);382383mask = (1UL << (nbitsinlong - 1));384mask += mask - 1;385mask <<= offset;386387switch (reg_op) {388case REG_OP_ISFREE:389for (i = 0; i < nlongs_reg; i++) {390if (bitmap[index + i] & mask)391goto done;392}393ret = 1;394break;395396case REG_OP_ALLOC:397for (i = 0; i < nlongs_reg; i++)398bitmap[index + i] |= mask;399break;400401case REG_OP_RELEASE:402for (i = 0; i < nlongs_reg; i++)403bitmap[index + i] &= ~mask;404break;405}406done:407return ret;408}409410#define for_each_set_bit(bit, addr, size) \411for ((bit) = find_first_bit((addr), (size)); \412(bit) < (size); \413(bit) = find_next_bit((addr), (size), (bit) + 1))414415#define for_each_clear_bit(bit, addr, size) \416for ((bit) = find_first_zero_bit((addr), (size)); \417(bit) < (size); \418(bit) = find_next_zero_bit((addr), (size), (bit) + 1))419420static inline uint64_t421sign_extend64(uint64_t value, int index)422{423uint8_t shift = 63 - index;424425return ((int64_t)(value << shift) >> shift);426}427428static inline uint32_t429sign_extend32(uint32_t value, int index)430{431uint8_t shift = 31 - index;432433return ((int32_t)(value << shift) >> shift);434}435436#endif /* _LINUXKPI_LINUX_BITOPS_H_ */437438439