540 lines
16 KiB
C
540 lines
16 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/* Copyright (c) 2023, Intel Corporation
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef _ICE_BITOPS_H_
|
|
#define _ICE_BITOPS_H_
|
|
|
|
#include "ice_defs.h"
|
|
#include "ice_osdep.h"
|
|
|
|
/* Define the size of the bitmap chunk */
|
|
typedef u32 ice_bitmap_t;
|
|
|
|
/* NOTE!
|
|
* Do not use any of the functions declared in this file
|
|
* on memory that was not declared with ice_declare_bitmap.
|
|
* Not following this rule might cause issues like split
|
|
* locks.
|
|
*/
|
|
|
|
/* Number of bits per bitmap chunk */
|
|
#define BITS_PER_CHUNK (BITS_PER_BYTE * sizeof(ice_bitmap_t))
|
|
/* Determine which chunk a bit belongs in */
|
|
#define BIT_CHUNK(nr) ((nr) / BITS_PER_CHUNK)
|
|
/* How many chunks are required to store this many bits */
|
|
#define BITS_TO_CHUNKS(sz) (((sz) + BITS_PER_CHUNK - 1) / BITS_PER_CHUNK)
|
|
/* Which bit inside a chunk this bit corresponds to */
|
|
#define BIT_IN_CHUNK(nr) ((nr) % BITS_PER_CHUNK)
|
|
/* How many bits are valid in the last chunk, assumes nr > 0 */
|
|
#define LAST_CHUNK_BITS(nr) ((((nr) - 1) % BITS_PER_CHUNK) + 1)
|
|
/* Generate a bitmask of valid bits in the last chunk, assumes nr > 0 */
|
|
#define LAST_CHUNK_MASK(nr) (((ice_bitmap_t)~0) >> \
|
|
(BITS_PER_CHUNK - LAST_CHUNK_BITS(nr)))
|
|
|
|
#define ice_declare_bitmap(A, sz) \
|
|
ice_bitmap_t A[BITS_TO_CHUNKS(sz)]
|
|
|
|
static inline bool ice_is_bit_set_internal(u16 nr, const ice_bitmap_t *bitmap)
|
|
{
|
|
return !!(*bitmap & BIT(nr));
|
|
}
|
|
|
|
/*
|
|
* If atomic version of the bitops are required, each specific OS
|
|
* implementation will need to implement OS/platform specific atomic
|
|
* version of the functions below:
|
|
*
|
|
* ice_clear_bit_internal
|
|
* ice_set_bit_internal
|
|
* ice_test_and_clear_bit_internal
|
|
* ice_test_and_set_bit_internal
|
|
*
|
|
* and define macro ICE_ATOMIC_BITOPS to overwrite the default non-atomic
|
|
* implementation.
|
|
*/
|
|
static inline void ice_clear_bit_internal(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
*bitmap &= ~BIT(nr);
|
|
}
|
|
|
|
static inline void ice_set_bit_internal(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
*bitmap |= BIT(nr);
|
|
}
|
|
|
|
static inline bool ice_test_and_clear_bit_internal(u16 nr,
|
|
ice_bitmap_t *bitmap)
|
|
{
|
|
if (ice_is_bit_set_internal(nr, bitmap)) {
|
|
ice_clear_bit_internal(nr, bitmap);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool ice_test_and_set_bit_internal(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
if (ice_is_bit_set_internal(nr, bitmap))
|
|
return true;
|
|
|
|
ice_set_bit_internal(nr, bitmap);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* ice_is_bit_set - Check state of a bit in a bitmap
|
|
* @bitmap: the bitmap to check
|
|
* @nr: the bit to check
|
|
*
|
|
* Returns true if bit nr of bitmap is set. False otherwise. Assumes that nr
|
|
* is less than the size of the bitmap.
|
|
*/
|
|
static inline bool ice_is_bit_set(const ice_bitmap_t *bitmap, u16 nr)
|
|
{
|
|
return ice_is_bit_set_internal(BIT_IN_CHUNK(nr),
|
|
&bitmap[BIT_CHUNK(nr)]);
|
|
}
|
|
|
|
/**
|
|
* ice_clear_bit - Clear a bit in a bitmap
|
|
* @bitmap: the bitmap to change
|
|
* @nr: the bit to change
|
|
*
|
|
* Clears the bit nr in bitmap. Assumes that nr is less than the size of the
|
|
* bitmap.
|
|
*/
|
|
static inline void ice_clear_bit(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
ice_clear_bit_internal(BIT_IN_CHUNK(nr), &bitmap[BIT_CHUNK(nr)]);
|
|
}
|
|
|
|
/**
|
|
* ice_set_bit - Set a bit in a bitmap
|
|
* @bitmap: the bitmap to change
|
|
* @nr: the bit to change
|
|
*
|
|
* Sets the bit nr in bitmap. Assumes that nr is less than the size of the
|
|
* bitmap.
|
|
*/
|
|
static inline void ice_set_bit(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
ice_set_bit_internal(BIT_IN_CHUNK(nr), &bitmap[BIT_CHUNK(nr)]);
|
|
}
|
|
|
|
/**
|
|
* ice_test_and_clear_bit - Atomically clear a bit and return the old bit value
|
|
* @nr: the bit to change
|
|
* @bitmap: the bitmap to change
|
|
*
|
|
* Check and clear the bit nr in bitmap. Assumes that nr is less than the size
|
|
* of the bitmap.
|
|
*/
|
|
static inline bool
|
|
ice_test_and_clear_bit(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
return ice_test_and_clear_bit_internal(BIT_IN_CHUNK(nr),
|
|
&bitmap[BIT_CHUNK(nr)]);
|
|
}
|
|
|
|
/**
|
|
* ice_test_and_set_bit - Atomically set a bit and return the old bit value
|
|
* @nr: the bit to change
|
|
* @bitmap: the bitmap to change
|
|
*
|
|
* Check and set the bit nr in bitmap. Assumes that nr is less than the size of
|
|
* the bitmap.
|
|
*/
|
|
static inline bool
|
|
ice_test_and_set_bit(u16 nr, ice_bitmap_t *bitmap)
|
|
{
|
|
return ice_test_and_set_bit_internal(BIT_IN_CHUNK(nr),
|
|
&bitmap[BIT_CHUNK(nr)]);
|
|
}
|
|
|
|
/* ice_zero_bitmap - set bits of bitmap to zero.
|
|
* @bmp: bitmap to set zeros
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* Set all of the bits in a bitmap to zero. Note that this function assumes it
|
|
* operates on an ice_bitmap_t which was declared using ice_declare_bitmap. It
|
|
* will zero every bit in the last chunk, even if those bits are beyond the
|
|
* size.
|
|
*/
|
|
static inline void ice_zero_bitmap(ice_bitmap_t *bmp, u16 size)
|
|
{
|
|
ice_memset(bmp, 0, BITS_TO_CHUNKS(size) * sizeof(ice_bitmap_t),
|
|
ICE_NONDMA_MEM);
|
|
}
|
|
|
|
/**
|
|
* ice_and_bitmap - bitwise AND 2 bitmaps and store result in dst bitmap
|
|
* @dst: Destination bitmap that receive the result of the operation
|
|
* @bmp1: The first bitmap to intersect
|
|
* @bmp2: The second bitmap to intersect wit the first
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* This function performs a bitwise AND on two "source" bitmaps of the same size
|
|
* and stores the result to "dst" bitmap. The "dst" bitmap must be of the same
|
|
* size as the "source" bitmaps to avoid buffer overflows. This function returns
|
|
* a non-zero value if at least one bit location from both "source" bitmaps is
|
|
* non-zero.
|
|
*/
|
|
static inline int
|
|
ice_and_bitmap(ice_bitmap_t *dst, const ice_bitmap_t *bmp1,
|
|
const ice_bitmap_t *bmp2, u16 size)
|
|
{
|
|
ice_bitmap_t res = 0, mask;
|
|
u16 i;
|
|
|
|
/* Handle all but the last chunk */
|
|
for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++) {
|
|
dst[i] = bmp1[i] & bmp2[i];
|
|
res |= dst[i];
|
|
}
|
|
|
|
/* We want to take care not to modify any bits outside of the bitmap
|
|
* size, even in the destination bitmap. Thus, we won't directly
|
|
* assign the last bitmap, but instead use a bitmask to ensure we only
|
|
* modify bits which are within the size, and leave any bits above the
|
|
* size value alone.
|
|
*/
|
|
mask = LAST_CHUNK_MASK(size);
|
|
dst[i] = (dst[i] & ~mask) | ((bmp1[i] & bmp2[i]) & mask);
|
|
res |= dst[i] & mask;
|
|
|
|
return res != 0;
|
|
}
|
|
|
|
/**
|
|
* ice_or_bitmap - bitwise OR 2 bitmaps and store result in dst bitmap
|
|
* @dst: Destination bitmap that receive the result of the operation
|
|
* @bmp1: The first bitmap to intersect
|
|
* @bmp2: The second bitmap to intersect wit the first
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* This function performs a bitwise OR on two "source" bitmaps of the same size
|
|
* and stores the result to "dst" bitmap. The "dst" bitmap must be of the same
|
|
* size as the "source" bitmaps to avoid buffer overflows.
|
|
*/
|
|
static inline void
|
|
ice_or_bitmap(ice_bitmap_t *dst, const ice_bitmap_t *bmp1,
|
|
const ice_bitmap_t *bmp2, u16 size)
|
|
{
|
|
ice_bitmap_t mask;
|
|
u16 i;
|
|
|
|
/* Handle all but last chunk */
|
|
for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++)
|
|
dst[i] = bmp1[i] | bmp2[i];
|
|
|
|
/* We want to only OR bits within the size. Furthermore, we also do
|
|
* not want to modify destination bits which are beyond the specified
|
|
* size. Use a bitmask to ensure that we only modify the bits that are
|
|
* within the specified size.
|
|
*/
|
|
mask = LAST_CHUNK_MASK(size);
|
|
dst[i] = (dst[i] & ~mask) | ((bmp1[i] | bmp2[i]) & mask);
|
|
}
|
|
|
|
/**
|
|
* ice_xor_bitmap - bitwise XOR 2 bitmaps and store result in dst bitmap
|
|
* @dst: Destination bitmap that receive the result of the operation
|
|
* @bmp1: The first bitmap of XOR operation
|
|
* @bmp2: The second bitmap to XOR with the first
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* This function performs a bitwise XOR on two "source" bitmaps of the same size
|
|
* and stores the result to "dst" bitmap. The "dst" bitmap must be of the same
|
|
* size as the "source" bitmaps to avoid buffer overflows.
|
|
*/
|
|
static inline void
|
|
ice_xor_bitmap(ice_bitmap_t *dst, const ice_bitmap_t *bmp1,
|
|
const ice_bitmap_t *bmp2, u16 size)
|
|
{
|
|
ice_bitmap_t mask;
|
|
u16 i;
|
|
|
|
/* Handle all but last chunk */
|
|
for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++)
|
|
dst[i] = bmp1[i] ^ bmp2[i];
|
|
|
|
/* We want to only XOR bits within the size. Furthermore, we also do
|
|
* not want to modify destination bits which are beyond the specified
|
|
* size. Use a bitmask to ensure that we only modify the bits that are
|
|
* within the specified size.
|
|
*/
|
|
mask = LAST_CHUNK_MASK(size);
|
|
dst[i] = (dst[i] & ~mask) | ((bmp1[i] ^ bmp2[i]) & mask);
|
|
}
|
|
|
|
/**
|
|
* ice_andnot_bitmap - bitwise ANDNOT 2 bitmaps and result in dst bitmap
|
|
* @dst: Destination bitmap that receive the result of the operation
|
|
* @bmp1: The first bitmap of ANDNOT operation
|
|
* @bmp2: The second bitmap to ANDNOT operation
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* This function performs a bitwise ANDNOT on two "source" bitmaps of the same
|
|
* size, and stores the result to "dst" bitmap. The "dst" bitmap must be of the
|
|
* same size as the "source" bitmaps to avoid buffer overflows.
|
|
*/
|
|
static inline void
|
|
ice_andnot_bitmap(ice_bitmap_t *dst, const ice_bitmap_t *bmp1,
|
|
const ice_bitmap_t *bmp2, u16 size)
|
|
{
|
|
ice_bitmap_t mask;
|
|
u16 i;
|
|
|
|
/* Handle all but last chunk */
|
|
for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++)
|
|
dst[i] = bmp1[i] & ~bmp2[i];
|
|
|
|
/* We want to only clear bits within the size. Furthermore, we also do
|
|
* not want to modify destination bits which are beyond the specified
|
|
* size. Use a bitmask to ensure that we only modify the bits that are
|
|
* within the specified size.
|
|
*/
|
|
mask = LAST_CHUNK_MASK(size);
|
|
dst[i] = (dst[i] & ~mask) | ((bmp1[i] & ~bmp2[i]) & mask);
|
|
}
|
|
|
|
/**
|
|
* ice_find_next_bit - Find the index of the next set bit of a bitmap
|
|
* @bitmap: the bitmap to scan
|
|
* @size: the size in bits of the bitmap
|
|
* @offset: the offset to start at
|
|
*
|
|
* Scans the bitmap and returns the index of the first set bit which is equal
|
|
* to or after the specified offset. Will return size if no bits are set.
|
|
*/
|
|
static inline u16
|
|
ice_find_next_bit(const ice_bitmap_t *bitmap, u16 size, u16 offset)
|
|
{
|
|
u16 i, j;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
|
|
/* Since the starting position may not be directly on a chunk
|
|
* boundary, we need to be careful to handle the first chunk specially
|
|
*/
|
|
i = BIT_CHUNK(offset);
|
|
if (bitmap[i] != 0) {
|
|
u16 off = i * BITS_PER_CHUNK;
|
|
|
|
for (j = offset % BITS_PER_CHUNK; j < BITS_PER_CHUNK; j++) {
|
|
if (ice_is_bit_set(bitmap, off + j))
|
|
return min(size, (u16)(off + j));
|
|
}
|
|
}
|
|
|
|
/* Now we handle the remaining chunks, if any */
|
|
for (i++; i < BITS_TO_CHUNKS(size); i++) {
|
|
if (bitmap[i] != 0) {
|
|
u16 off = i * BITS_PER_CHUNK;
|
|
|
|
for (j = 0; j < BITS_PER_CHUNK; j++) {
|
|
if (ice_is_bit_set(bitmap, off + j))
|
|
return min(size, (u16)(off + j));
|
|
}
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* ice_find_first_bit - Find the index of the first set bit of a bitmap
|
|
* @bitmap: the bitmap to scan
|
|
* @size: the size in bits of the bitmap
|
|
*
|
|
* Scans the bitmap and returns the index of the first set bit. Will return
|
|
* size if no bits are set.
|
|
*/
|
|
static inline u16 ice_find_first_bit(const ice_bitmap_t *bitmap, u16 size)
|
|
{
|
|
return ice_find_next_bit(bitmap, size, 0);
|
|
}
|
|
|
|
#define ice_for_each_set_bit(_bitpos, _addr, _maxlen) \
|
|
for ((_bitpos) = ice_find_first_bit((_addr), (_maxlen)); \
|
|
(_bitpos) < (_maxlen); \
|
|
(_bitpos) = ice_find_next_bit((_addr), (_maxlen), (_bitpos) + 1))
|
|
|
|
/**
|
|
* ice_is_any_bit_set - Return true of any bit in the bitmap is set
|
|
* @bitmap: the bitmap to check
|
|
* @size: the size of the bitmap
|
|
*
|
|
* Equivalent to checking if ice_find_first_bit returns a value less than the
|
|
* bitmap size.
|
|
*/
|
|
static inline bool ice_is_any_bit_set(ice_bitmap_t *bitmap, u16 size)
|
|
{
|
|
return ice_find_first_bit(bitmap, size) < size;
|
|
}
|
|
|
|
/**
|
|
* ice_cp_bitmap - copy bitmaps.
|
|
* @dst: bitmap destination
|
|
* @src: bitmap to copy from
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* This function copy bitmap from src to dst. Note that this function assumes
|
|
* it is operating on a bitmap declared using ice_declare_bitmap. It will copy
|
|
* the entire last chunk even if this contains bits beyond the size.
|
|
*/
|
|
static inline void ice_cp_bitmap(ice_bitmap_t *dst, ice_bitmap_t *src, u16 size)
|
|
{
|
|
ice_memcpy(dst, src, BITS_TO_CHUNKS(size) * sizeof(ice_bitmap_t),
|
|
ICE_NONDMA_TO_NONDMA);
|
|
}
|
|
|
|
/**
|
|
* ice_bitmap_set - set a number of bits in bitmap from a starting position
|
|
* @dst: bitmap destination
|
|
* @pos: first bit position to set
|
|
* @num_bits: number of bits to set
|
|
*
|
|
* This function sets bits in a bitmap from pos to (pos + num_bits) - 1.
|
|
* Note that this function assumes it is operating on a bitmap declared using
|
|
* ice_declare_bitmap.
|
|
*/
|
|
static inline void
|
|
ice_bitmap_set(ice_bitmap_t *dst, u16 pos, u16 num_bits)
|
|
{
|
|
u16 i;
|
|
|
|
for (i = pos; i < pos + num_bits; i++)
|
|
ice_set_bit(i, dst);
|
|
}
|
|
|
|
/**
|
|
* ice_bitmap_hweight - hamming weight of bitmap
|
|
* @bm: bitmap pointer
|
|
* @size: size of bitmap (in bits)
|
|
*
|
|
* This function determines the number of set bits in a bitmap.
|
|
* Note that this function assumes it is operating on a bitmap declared using
|
|
* ice_declare_bitmap.
|
|
*/
|
|
static inline int
|
|
ice_bitmap_hweight(ice_bitmap_t *bm, u16 size)
|
|
{
|
|
int count = 0;
|
|
u16 bit = 0;
|
|
|
|
while (size > (bit = ice_find_next_bit(bm, size, bit))) {
|
|
count++;
|
|
bit++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* ice_cmp_bitmap - compares two bitmaps.
|
|
* @bmp1: the bitmap to compare
|
|
* @bmp2: the bitmap to compare with bmp1
|
|
* @size: Size of the bitmaps in bits
|
|
*
|
|
* This function compares two bitmaps, and returns result as true or false.
|
|
*/
|
|
static inline bool
|
|
ice_cmp_bitmap(ice_bitmap_t *bmp1, ice_bitmap_t *bmp2, u16 size)
|
|
{
|
|
ice_bitmap_t mask;
|
|
u16 i;
|
|
|
|
/* Handle all but last chunk */
|
|
for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++)
|
|
if (bmp1[i] != bmp2[i])
|
|
return false;
|
|
|
|
/* We want to only compare bits within the size */
|
|
mask = LAST_CHUNK_MASK(size);
|
|
if ((bmp1[i] & mask) != (bmp2[i] & mask))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* ice_bitmap_from_array32 - copies u32 array source into bitmap destination
|
|
* @dst: the destination bitmap
|
|
* @src: the source u32 array
|
|
* @size: size of the bitmap (in bits)
|
|
*
|
|
* This function copies the src bitmap stored in an u32 array into the dst
|
|
* bitmap stored as an ice_bitmap_t.
|
|
*/
|
|
static inline void
|
|
ice_bitmap_from_array32(ice_bitmap_t *dst, u32 *src, u16 size)
|
|
{
|
|
u32 remaining_bits, i;
|
|
|
|
#define BITS_PER_U32 (sizeof(u32) * BITS_PER_BYTE)
|
|
/* clear bitmap so we only have to set when iterating */
|
|
ice_zero_bitmap(dst, size);
|
|
|
|
for (i = 0; i < (u32)(size / BITS_PER_U32); i++) {
|
|
u32 bit_offset = i * BITS_PER_U32;
|
|
u32 entry = src[i];
|
|
u32 j;
|
|
|
|
for (j = 0; j < BITS_PER_U32; j++) {
|
|
if (entry & BIT(j))
|
|
ice_set_bit((u16)(j + bit_offset), dst);
|
|
}
|
|
}
|
|
|
|
/* still need to check the leftover bits (i.e. if size isn't evenly
|
|
* divisible by BITS_PER_U32
|
|
**/
|
|
remaining_bits = size % BITS_PER_U32;
|
|
if (remaining_bits) {
|
|
u32 bit_offset = i * BITS_PER_U32;
|
|
u32 entry = src[i];
|
|
u32 j;
|
|
|
|
for (j = 0; j < remaining_bits; j++) {
|
|
if (entry & BIT(j))
|
|
ice_set_bit((u16)(j + bit_offset), dst);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef BIT_CHUNK
|
|
#undef BIT_IN_CHUNK
|
|
#undef LAST_CHUNK_BITS
|
|
#undef LAST_CHUNK_MASK
|
|
|
|
#endif /* _ICE_BITOPS_H_ */
|