199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson #ifndef __INCLUDE_RTE_BITMAP_H__ 699a2dd95SBruce Richardson #define __INCLUDE_RTE_BITMAP_H__ 799a2dd95SBruce Richardson 899a2dd95SBruce Richardson /** 999a2dd95SBruce Richardson * @file 1099a2dd95SBruce Richardson * RTE Bitmap 1199a2dd95SBruce Richardson * 1299a2dd95SBruce Richardson * The bitmap component provides a mechanism to manage large arrays of bits 1399a2dd95SBruce Richardson * through bit get/set/clear and bit array scan operations. 1499a2dd95SBruce Richardson * 1599a2dd95SBruce Richardson * The bitmap scan operation is optimized for 64-bit CPUs using 64/128 byte cache 1699a2dd95SBruce Richardson * lines. The bitmap is hierarchically organized using two arrays (array1 and 1799a2dd95SBruce Richardson * array2), with each bit in array1 being associated with a full cache line 1899a2dd95SBruce Richardson * (512/1024 bits) of bitmap bits, which are stored in array2: the bit in array1 1999a2dd95SBruce Richardson * is set only when there is at least one bit set within its associated array2 2099a2dd95SBruce Richardson * bits, otherwise the bit in array1 is cleared. The read and write operations 2199a2dd95SBruce Richardson * for array1 and array2 are always done in slabs of 64 bits. 2299a2dd95SBruce Richardson * 2399a2dd95SBruce Richardson * This bitmap is not thread safe. For lock free operation on a specific bitmap 2499a2dd95SBruce Richardson * instance, a single writer thread performing bit set/clear operations is 2599a2dd95SBruce Richardson * allowed, only the writer thread can do bitmap scan operations, while there 2699a2dd95SBruce Richardson * can be several reader threads performing bit get operations in parallel with 2799a2dd95SBruce Richardson * the writer thread. When the use of locking primitives is acceptable, the 2899a2dd95SBruce Richardson * serialization of the bit set/clear and bitmap scan operations needs to be 2999a2dd95SBruce Richardson * enforced by the caller, while the bit get operation does not require locking 3099a2dd95SBruce Richardson * the bitmap. 313e4c5be9SThomas Monjalon */ 3299a2dd95SBruce Richardson 3399a2dd95SBruce Richardson #include <string.h> 3430764c0fSStephen Hemminger 3599a2dd95SBruce Richardson #include <rte_common.h> 3699a2dd95SBruce Richardson #include <rte_config.h> 3799a2dd95SBruce Richardson #include <rte_debug.h> 3899a2dd95SBruce Richardson #include <rte_memory.h> 3999a2dd95SBruce Richardson #include <rte_branch_prediction.h> 4099a2dd95SBruce Richardson #include <rte_prefetch.h> 4199a2dd95SBruce Richardson 42*719834a6SMattias Rönnblom #ifdef __cplusplus 43*719834a6SMattias Rönnblom extern "C" { 44*719834a6SMattias Rönnblom #endif 45*719834a6SMattias Rönnblom 4699a2dd95SBruce Richardson /* Slab */ 4799a2dd95SBruce Richardson #define RTE_BITMAP_SLAB_BIT_SIZE 64 4899a2dd95SBruce Richardson #define RTE_BITMAP_SLAB_BIT_SIZE_LOG2 6 4999a2dd95SBruce Richardson #define RTE_BITMAP_SLAB_BIT_MASK (RTE_BITMAP_SLAB_BIT_SIZE - 1) 5099a2dd95SBruce Richardson 5199a2dd95SBruce Richardson /* Cache line (CL) */ 5299a2dd95SBruce Richardson #define RTE_BITMAP_CL_BIT_SIZE (RTE_CACHE_LINE_SIZE * 8) 5399a2dd95SBruce Richardson #define RTE_BITMAP_CL_BIT_SIZE_LOG2 (RTE_CACHE_LINE_SIZE_LOG2 + 3) 5499a2dd95SBruce Richardson #define RTE_BITMAP_CL_BIT_MASK (RTE_BITMAP_CL_BIT_SIZE - 1) 5599a2dd95SBruce Richardson 5699a2dd95SBruce Richardson #define RTE_BITMAP_CL_SLAB_SIZE (RTE_BITMAP_CL_BIT_SIZE / RTE_BITMAP_SLAB_BIT_SIZE) 5799a2dd95SBruce Richardson #define RTE_BITMAP_CL_SLAB_SIZE_LOG2 (RTE_BITMAP_CL_BIT_SIZE_LOG2 - RTE_BITMAP_SLAB_BIT_SIZE_LOG2) 5899a2dd95SBruce Richardson #define RTE_BITMAP_CL_SLAB_MASK (RTE_BITMAP_CL_SLAB_SIZE - 1) 5999a2dd95SBruce Richardson 6099a2dd95SBruce Richardson /** Bitmap data structure */ 6199a2dd95SBruce Richardson struct rte_bitmap { 6299a2dd95SBruce Richardson /* Context for array1 and array2 */ 6399a2dd95SBruce Richardson uint64_t *array1; /**< Bitmap array1 */ 6499a2dd95SBruce Richardson uint64_t *array2; /**< Bitmap array2 */ 6599a2dd95SBruce Richardson uint32_t array1_size; /**< Number of 64-bit slabs in array1 that are actually used */ 6699a2dd95SBruce Richardson uint32_t array2_size; /**< Number of 64-bit slabs in array2 */ 6799a2dd95SBruce Richardson 6899a2dd95SBruce Richardson /* Context for the "scan next" operation */ 6999a2dd95SBruce Richardson uint32_t index1; /**< Bitmap scan: Index of current array1 slab */ 7099a2dd95SBruce Richardson uint32_t offset1; /**< Bitmap scan: Offset of current bit within current array1 slab */ 7199a2dd95SBruce Richardson uint32_t index2; /**< Bitmap scan: Index of current array2 slab */ 7299a2dd95SBruce Richardson uint32_t go2; /**< Bitmap scan: Go/stop condition for current array2 cache line */ 7399a2dd95SBruce Richardson 7499a2dd95SBruce Richardson /* Storage space for array1 and array2 */ 7599a2dd95SBruce Richardson uint8_t memory[]; 7699a2dd95SBruce Richardson }; 7799a2dd95SBruce Richardson 7899a2dd95SBruce Richardson static inline void 7999a2dd95SBruce Richardson __rte_bitmap_index1_inc(struct rte_bitmap *bmp) 8099a2dd95SBruce Richardson { 8199a2dd95SBruce Richardson bmp->index1 = (bmp->index1 + 1) & (bmp->array1_size - 1); 8299a2dd95SBruce Richardson } 8399a2dd95SBruce Richardson 8499a2dd95SBruce Richardson static inline uint64_t 8599a2dd95SBruce Richardson __rte_bitmap_mask1_get(struct rte_bitmap *bmp) 8699a2dd95SBruce Richardson { 8799a2dd95SBruce Richardson return (~1llu) << bmp->offset1; 8899a2dd95SBruce Richardson } 8999a2dd95SBruce Richardson 9099a2dd95SBruce Richardson static inline void 9199a2dd95SBruce Richardson __rte_bitmap_index2_set(struct rte_bitmap *bmp) 9299a2dd95SBruce Richardson { 9399a2dd95SBruce Richardson bmp->index2 = (((bmp->index1 << RTE_BITMAP_SLAB_BIT_SIZE_LOG2) + bmp->offset1) << RTE_BITMAP_CL_SLAB_SIZE_LOG2); 9499a2dd95SBruce Richardson } 9599a2dd95SBruce Richardson 9699a2dd95SBruce Richardson static inline uint32_t 9799a2dd95SBruce Richardson __rte_bitmap_get_memory_footprint(uint32_t n_bits, 9899a2dd95SBruce Richardson uint32_t *array1_byte_offset, uint32_t *array1_slabs, 9999a2dd95SBruce Richardson uint32_t *array2_byte_offset, uint32_t *array2_slabs) 10099a2dd95SBruce Richardson { 10199a2dd95SBruce Richardson uint32_t n_slabs_context, n_slabs_array1, n_cache_lines_context_and_array1; 10299a2dd95SBruce Richardson uint32_t n_cache_lines_array2; 10399a2dd95SBruce Richardson uint32_t n_bytes_total; 10499a2dd95SBruce Richardson 10599a2dd95SBruce Richardson n_cache_lines_array2 = (n_bits + RTE_BITMAP_CL_BIT_SIZE - 1) / RTE_BITMAP_CL_BIT_SIZE; 10699a2dd95SBruce Richardson n_slabs_array1 = (n_cache_lines_array2 + RTE_BITMAP_SLAB_BIT_SIZE - 1) / RTE_BITMAP_SLAB_BIT_SIZE; 10799a2dd95SBruce Richardson n_slabs_array1 = rte_align32pow2(n_slabs_array1); 10899a2dd95SBruce Richardson n_slabs_context = (sizeof(struct rte_bitmap) + (RTE_BITMAP_SLAB_BIT_SIZE / 8) - 1) / (RTE_BITMAP_SLAB_BIT_SIZE / 8); 10999a2dd95SBruce Richardson n_cache_lines_context_and_array1 = (n_slabs_context + n_slabs_array1 + RTE_BITMAP_CL_SLAB_SIZE - 1) / RTE_BITMAP_CL_SLAB_SIZE; 11099a2dd95SBruce Richardson n_bytes_total = (n_cache_lines_context_and_array1 + n_cache_lines_array2) * RTE_CACHE_LINE_SIZE; 11199a2dd95SBruce Richardson 11299a2dd95SBruce Richardson if (array1_byte_offset) { 11399a2dd95SBruce Richardson *array1_byte_offset = n_slabs_context * (RTE_BITMAP_SLAB_BIT_SIZE / 8); 11499a2dd95SBruce Richardson } 11599a2dd95SBruce Richardson if (array1_slabs) { 11699a2dd95SBruce Richardson *array1_slabs = n_slabs_array1; 11799a2dd95SBruce Richardson } 11899a2dd95SBruce Richardson if (array2_byte_offset) { 11999a2dd95SBruce Richardson *array2_byte_offset = n_cache_lines_context_and_array1 * RTE_CACHE_LINE_SIZE; 12099a2dd95SBruce Richardson } 12199a2dd95SBruce Richardson if (array2_slabs) { 12299a2dd95SBruce Richardson *array2_slabs = n_cache_lines_array2 * RTE_BITMAP_CL_SLAB_SIZE; 12399a2dd95SBruce Richardson } 12499a2dd95SBruce Richardson 12599a2dd95SBruce Richardson return n_bytes_total; 12699a2dd95SBruce Richardson } 12799a2dd95SBruce Richardson 12899a2dd95SBruce Richardson static inline void 12999a2dd95SBruce Richardson __rte_bitmap_scan_init(struct rte_bitmap *bmp) 13099a2dd95SBruce Richardson { 13199a2dd95SBruce Richardson bmp->index1 = bmp->array1_size - 1; 13299a2dd95SBruce Richardson bmp->offset1 = RTE_BITMAP_SLAB_BIT_SIZE - 1; 13399a2dd95SBruce Richardson __rte_bitmap_index2_set(bmp); 13499a2dd95SBruce Richardson bmp->index2 += RTE_BITMAP_CL_SLAB_SIZE; 13599a2dd95SBruce Richardson 13699a2dd95SBruce Richardson bmp->go2 = 0; 13799a2dd95SBruce Richardson } 13899a2dd95SBruce Richardson 13999a2dd95SBruce Richardson /** 14099a2dd95SBruce Richardson * Bitmap memory footprint calculation 14199a2dd95SBruce Richardson * 14299a2dd95SBruce Richardson * @param n_bits 14399a2dd95SBruce Richardson * Number of bits in the bitmap 14499a2dd95SBruce Richardson * @return 14599a2dd95SBruce Richardson * Bitmap memory footprint measured in bytes on success, 0 on error 14699a2dd95SBruce Richardson */ 14799a2dd95SBruce Richardson static inline uint32_t 14899a2dd95SBruce Richardson rte_bitmap_get_memory_footprint(uint32_t n_bits) { 14999a2dd95SBruce Richardson /* Check input arguments */ 15099a2dd95SBruce Richardson if (n_bits == 0) { 15199a2dd95SBruce Richardson return 0; 15299a2dd95SBruce Richardson } 15399a2dd95SBruce Richardson 15499a2dd95SBruce Richardson return __rte_bitmap_get_memory_footprint(n_bits, NULL, NULL, NULL, NULL); 15599a2dd95SBruce Richardson } 15699a2dd95SBruce Richardson 15799a2dd95SBruce Richardson /** 15899a2dd95SBruce Richardson * Bitmap initialization 15999a2dd95SBruce Richardson * 16099a2dd95SBruce Richardson * @param n_bits 16199a2dd95SBruce Richardson * Number of pre-allocated bits in array2. 16299a2dd95SBruce Richardson * @param mem 16399a2dd95SBruce Richardson * Base address of array1 and array2. 16499a2dd95SBruce Richardson * @param mem_size 16599a2dd95SBruce Richardson * Minimum expected size of bitmap. 16699a2dd95SBruce Richardson * @return 16799a2dd95SBruce Richardson * Handle to bitmap instance. 16899a2dd95SBruce Richardson */ 16999a2dd95SBruce Richardson static inline struct rte_bitmap * 17099a2dd95SBruce Richardson rte_bitmap_init(uint32_t n_bits, uint8_t *mem, uint32_t mem_size) 17199a2dd95SBruce Richardson { 17299a2dd95SBruce Richardson struct rte_bitmap *bmp; 17399a2dd95SBruce Richardson uint32_t array1_byte_offset, array1_slabs, array2_byte_offset, array2_slabs; 17499a2dd95SBruce Richardson uint32_t size; 17599a2dd95SBruce Richardson 17699a2dd95SBruce Richardson /* Check input arguments */ 17799a2dd95SBruce Richardson if (n_bits == 0) { 17899a2dd95SBruce Richardson return NULL; 17999a2dd95SBruce Richardson } 18099a2dd95SBruce Richardson 18199a2dd95SBruce Richardson if ((mem == NULL) || (((uintptr_t) mem) & RTE_CACHE_LINE_MASK)) { 18299a2dd95SBruce Richardson return NULL; 18399a2dd95SBruce Richardson } 18499a2dd95SBruce Richardson 18599a2dd95SBruce Richardson size = __rte_bitmap_get_memory_footprint(n_bits, 18699a2dd95SBruce Richardson &array1_byte_offset, &array1_slabs, 18799a2dd95SBruce Richardson &array2_byte_offset, &array2_slabs); 1881ffd3bc1SIvan Ilchenko if (size > mem_size) 18999a2dd95SBruce Richardson return NULL; 19099a2dd95SBruce Richardson 19199a2dd95SBruce Richardson /* Setup bitmap */ 19299a2dd95SBruce Richardson memset(mem, 0, size); 19399a2dd95SBruce Richardson bmp = (struct rte_bitmap *) mem; 19499a2dd95SBruce Richardson 19599a2dd95SBruce Richardson bmp->array1 = (uint64_t *) &mem[array1_byte_offset]; 19699a2dd95SBruce Richardson bmp->array1_size = array1_slabs; 19799a2dd95SBruce Richardson bmp->array2 = (uint64_t *) &mem[array2_byte_offset]; 19899a2dd95SBruce Richardson bmp->array2_size = array2_slabs; 19999a2dd95SBruce Richardson 20099a2dd95SBruce Richardson __rte_bitmap_scan_init(bmp); 20199a2dd95SBruce Richardson 20299a2dd95SBruce Richardson return bmp; 20399a2dd95SBruce Richardson } 20499a2dd95SBruce Richardson 20599a2dd95SBruce Richardson /** 20699a2dd95SBruce Richardson * Bitmap clear slab overhead bits. 20799a2dd95SBruce Richardson * 20899a2dd95SBruce Richardson * @param slabs 20999a2dd95SBruce Richardson * Slab array. 21099a2dd95SBruce Richardson * @param slab_size 21199a2dd95SBruce Richardson * Number of 64-bit slabs in the slabs array. 21299a2dd95SBruce Richardson * @param pos 21399a2dd95SBruce Richardson * The start bit position in the slabs to be cleared. 21499a2dd95SBruce Richardson */ 21599a2dd95SBruce Richardson static inline void 21699a2dd95SBruce Richardson __rte_bitmap_clear_slab_overhead_bits(uint64_t *slabs, uint32_t slab_size, 21799a2dd95SBruce Richardson uint32_t pos) 21899a2dd95SBruce Richardson { 21999a2dd95SBruce Richardson uint32_t i; 22099a2dd95SBruce Richardson uint32_t index = pos / RTE_BITMAP_SLAB_BIT_SIZE; 22199a2dd95SBruce Richardson uint32_t offset = pos & RTE_BITMAP_SLAB_BIT_MASK; 22299a2dd95SBruce Richardson 22399a2dd95SBruce Richardson if (offset) { 22499a2dd95SBruce Richardson for (i = offset; i < RTE_BITMAP_SLAB_BIT_SIZE; i++) 22599a2dd95SBruce Richardson slabs[index] &= ~(1llu << i); 22699a2dd95SBruce Richardson index++; 22799a2dd95SBruce Richardson } 22899a2dd95SBruce Richardson if (index < slab_size) 22999a2dd95SBruce Richardson memset(&slabs[index], 0, sizeof(slabs[0]) * 23099a2dd95SBruce Richardson (slab_size - index)); 23199a2dd95SBruce Richardson } 23299a2dd95SBruce Richardson 23399a2dd95SBruce Richardson /** 23499a2dd95SBruce Richardson * Bitmap initialization with all bits set 23599a2dd95SBruce Richardson * 23699a2dd95SBruce Richardson * @param n_bits 23799a2dd95SBruce Richardson * Number of pre-allocated bits in array2. 23899a2dd95SBruce Richardson * @param mem 23999a2dd95SBruce Richardson * Base address of array1 and array2. 24099a2dd95SBruce Richardson * @param mem_size 24199a2dd95SBruce Richardson * Minimum expected size of bitmap. 24299a2dd95SBruce Richardson * @return 24399a2dd95SBruce Richardson * Handle to bitmap instance. 24499a2dd95SBruce Richardson */ 24599a2dd95SBruce Richardson static inline struct rte_bitmap * 24699a2dd95SBruce Richardson rte_bitmap_init_with_all_set(uint32_t n_bits, uint8_t *mem, uint32_t mem_size) 24799a2dd95SBruce Richardson { 24899a2dd95SBruce Richardson struct rte_bitmap *bmp; 24999a2dd95SBruce Richardson uint32_t array1_byte_offset, array1_slabs; 25099a2dd95SBruce Richardson uint32_t array2_byte_offset, array2_slabs; 25199a2dd95SBruce Richardson uint32_t size; 25299a2dd95SBruce Richardson 25399a2dd95SBruce Richardson /* Check input arguments */ 25499a2dd95SBruce Richardson if (!n_bits || !mem || (((uintptr_t) mem) & RTE_CACHE_LINE_MASK)) 25599a2dd95SBruce Richardson return NULL; 25699a2dd95SBruce Richardson 25799a2dd95SBruce Richardson size = __rte_bitmap_get_memory_footprint(n_bits, 25899a2dd95SBruce Richardson &array1_byte_offset, &array1_slabs, 25999a2dd95SBruce Richardson &array2_byte_offset, &array2_slabs); 26099a2dd95SBruce Richardson if (size < mem_size) 26199a2dd95SBruce Richardson return NULL; 26299a2dd95SBruce Richardson 26399a2dd95SBruce Richardson /* Setup bitmap */ 26499a2dd95SBruce Richardson bmp = (struct rte_bitmap *) mem; 26599a2dd95SBruce Richardson bmp->array1 = (uint64_t *) &mem[array1_byte_offset]; 26699a2dd95SBruce Richardson bmp->array1_size = array1_slabs; 26799a2dd95SBruce Richardson bmp->array2 = (uint64_t *) &mem[array2_byte_offset]; 26899a2dd95SBruce Richardson bmp->array2_size = array2_slabs; 26999a2dd95SBruce Richardson 27099a2dd95SBruce Richardson __rte_bitmap_scan_init(bmp); 27199a2dd95SBruce Richardson 27299a2dd95SBruce Richardson memset(bmp->array1, 0xff, bmp->array1_size * sizeof(bmp->array1[0])); 27399a2dd95SBruce Richardson memset(bmp->array2, 0xff, bmp->array2_size * sizeof(bmp->array2[0])); 27499a2dd95SBruce Richardson /* Clear overhead bits. */ 27599a2dd95SBruce Richardson __rte_bitmap_clear_slab_overhead_bits(bmp->array1, bmp->array1_size, 27699a2dd95SBruce Richardson bmp->array2_size >> RTE_BITMAP_CL_SLAB_SIZE_LOG2); 27799a2dd95SBruce Richardson __rte_bitmap_clear_slab_overhead_bits(bmp->array2, bmp->array2_size, 27899a2dd95SBruce Richardson n_bits); 27999a2dd95SBruce Richardson return bmp; 28099a2dd95SBruce Richardson } 28199a2dd95SBruce Richardson 28299a2dd95SBruce Richardson /** 28399a2dd95SBruce Richardson * Bitmap free 28499a2dd95SBruce Richardson * 28599a2dd95SBruce Richardson * @param bmp 28699a2dd95SBruce Richardson * Handle to bitmap instance 28799a2dd95SBruce Richardson * @return 28899a2dd95SBruce Richardson * 0 upon success, error code otherwise 28999a2dd95SBruce Richardson */ 29099a2dd95SBruce Richardson static inline int 29199a2dd95SBruce Richardson rte_bitmap_free(struct rte_bitmap *bmp) 29299a2dd95SBruce Richardson { 29399a2dd95SBruce Richardson /* Check input arguments */ 29499a2dd95SBruce Richardson if (bmp == NULL) { 29599a2dd95SBruce Richardson return -1; 29699a2dd95SBruce Richardson } 29799a2dd95SBruce Richardson 29899a2dd95SBruce Richardson return 0; 29999a2dd95SBruce Richardson } 30099a2dd95SBruce Richardson 30199a2dd95SBruce Richardson /** 30299a2dd95SBruce Richardson * Bitmap reset 30399a2dd95SBruce Richardson * 30499a2dd95SBruce Richardson * @param bmp 30599a2dd95SBruce Richardson * Handle to bitmap instance 30699a2dd95SBruce Richardson */ 30799a2dd95SBruce Richardson static inline void 30899a2dd95SBruce Richardson rte_bitmap_reset(struct rte_bitmap *bmp) 30999a2dd95SBruce Richardson { 31099a2dd95SBruce Richardson memset(bmp->array1, 0, bmp->array1_size * sizeof(uint64_t)); 31199a2dd95SBruce Richardson memset(bmp->array2, 0, bmp->array2_size * sizeof(uint64_t)); 31299a2dd95SBruce Richardson __rte_bitmap_scan_init(bmp); 31399a2dd95SBruce Richardson } 31499a2dd95SBruce Richardson 31599a2dd95SBruce Richardson /** 31699a2dd95SBruce Richardson * Bitmap location prefetch into CPU L1 cache 31799a2dd95SBruce Richardson * 31899a2dd95SBruce Richardson * @param bmp 31999a2dd95SBruce Richardson * Handle to bitmap instance 32099a2dd95SBruce Richardson * @param pos 32199a2dd95SBruce Richardson * Bit position 32299a2dd95SBruce Richardson */ 32399a2dd95SBruce Richardson static inline void 32499a2dd95SBruce Richardson rte_bitmap_prefetch0(struct rte_bitmap *bmp, uint32_t pos) 32599a2dd95SBruce Richardson { 32699a2dd95SBruce Richardson uint64_t *slab2; 32799a2dd95SBruce Richardson uint32_t index2; 32899a2dd95SBruce Richardson 32999a2dd95SBruce Richardson index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2; 33099a2dd95SBruce Richardson slab2 = bmp->array2 + index2; 33199a2dd95SBruce Richardson rte_prefetch0((void *) slab2); 33299a2dd95SBruce Richardson } 33399a2dd95SBruce Richardson 33499a2dd95SBruce Richardson /** 33599a2dd95SBruce Richardson * Bitmap bit get 33699a2dd95SBruce Richardson * 33799a2dd95SBruce Richardson * @param bmp 33899a2dd95SBruce Richardson * Handle to bitmap instance 33999a2dd95SBruce Richardson * @param pos 34099a2dd95SBruce Richardson * Bit position 34199a2dd95SBruce Richardson * @return 34299a2dd95SBruce Richardson * 0 when bit is cleared, non-zero when bit is set 34399a2dd95SBruce Richardson */ 34499a2dd95SBruce Richardson static inline uint64_t 34599a2dd95SBruce Richardson rte_bitmap_get(struct rte_bitmap *bmp, uint32_t pos) 34699a2dd95SBruce Richardson { 34799a2dd95SBruce Richardson uint64_t *slab2; 34899a2dd95SBruce Richardson uint32_t index2, offset2; 34999a2dd95SBruce Richardson 35099a2dd95SBruce Richardson index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2; 35199a2dd95SBruce Richardson offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK; 35299a2dd95SBruce Richardson slab2 = bmp->array2 + index2; 35399a2dd95SBruce Richardson return (*slab2) & (1llu << offset2); 35499a2dd95SBruce Richardson } 35599a2dd95SBruce Richardson 35699a2dd95SBruce Richardson /** 35799a2dd95SBruce Richardson * Bitmap bit set 35899a2dd95SBruce Richardson * 35999a2dd95SBruce Richardson * @param bmp 36099a2dd95SBruce Richardson * Handle to bitmap instance 36199a2dd95SBruce Richardson * @param pos 36299a2dd95SBruce Richardson * Bit position 36399a2dd95SBruce Richardson */ 36499a2dd95SBruce Richardson static inline void 36599a2dd95SBruce Richardson rte_bitmap_set(struct rte_bitmap *bmp, uint32_t pos) 36699a2dd95SBruce Richardson { 36799a2dd95SBruce Richardson uint64_t *slab1, *slab2; 36899a2dd95SBruce Richardson uint32_t index1, index2, offset1, offset2; 36999a2dd95SBruce Richardson 37099a2dd95SBruce Richardson /* Set bit in array2 slab and set bit in array1 slab */ 37199a2dd95SBruce Richardson index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2; 37299a2dd95SBruce Richardson offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK; 37399a2dd95SBruce Richardson index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2); 37499a2dd95SBruce Richardson offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK; 37599a2dd95SBruce Richardson slab2 = bmp->array2 + index2; 37699a2dd95SBruce Richardson slab1 = bmp->array1 + index1; 37799a2dd95SBruce Richardson 37899a2dd95SBruce Richardson *slab2 |= 1llu << offset2; 37999a2dd95SBruce Richardson *slab1 |= 1llu << offset1; 38099a2dd95SBruce Richardson } 38199a2dd95SBruce Richardson 38299a2dd95SBruce Richardson /** 38399a2dd95SBruce Richardson * Bitmap slab set 38499a2dd95SBruce Richardson * 38599a2dd95SBruce Richardson * @param bmp 38699a2dd95SBruce Richardson * Handle to bitmap instance 38799a2dd95SBruce Richardson * @param pos 38899a2dd95SBruce Richardson * Bit position identifying the array2 slab 38999a2dd95SBruce Richardson * @param slab 39099a2dd95SBruce Richardson * Value to be assigned to the 64-bit slab in array2 39199a2dd95SBruce Richardson */ 39299a2dd95SBruce Richardson static inline void 39399a2dd95SBruce Richardson rte_bitmap_set_slab(struct rte_bitmap *bmp, uint32_t pos, uint64_t slab) 39499a2dd95SBruce Richardson { 39599a2dd95SBruce Richardson uint64_t *slab1, *slab2; 39699a2dd95SBruce Richardson uint32_t index1, index2, offset1; 39799a2dd95SBruce Richardson 39899a2dd95SBruce Richardson /* Set bits in array2 slab and set bit in array1 slab */ 39999a2dd95SBruce Richardson index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2; 40099a2dd95SBruce Richardson index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2); 40199a2dd95SBruce Richardson offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK; 40299a2dd95SBruce Richardson slab2 = bmp->array2 + index2; 40399a2dd95SBruce Richardson slab1 = bmp->array1 + index1; 40499a2dd95SBruce Richardson 40599a2dd95SBruce Richardson *slab2 |= slab; 40699a2dd95SBruce Richardson *slab1 |= 1llu << offset1; 40799a2dd95SBruce Richardson } 40899a2dd95SBruce Richardson 40999a2dd95SBruce Richardson #if RTE_BITMAP_CL_SLAB_SIZE == 8 41099a2dd95SBruce Richardson static inline uint64_t 41199a2dd95SBruce Richardson __rte_bitmap_line_not_empty(uint64_t *slab2) 41299a2dd95SBruce Richardson { 41399a2dd95SBruce Richardson uint64_t v1, v2, v3, v4; 41499a2dd95SBruce Richardson 41599a2dd95SBruce Richardson v1 = slab2[0] | slab2[1]; 41699a2dd95SBruce Richardson v2 = slab2[2] | slab2[3]; 41799a2dd95SBruce Richardson v3 = slab2[4] | slab2[5]; 41899a2dd95SBruce Richardson v4 = slab2[6] | slab2[7]; 41999a2dd95SBruce Richardson v1 |= v2; 42099a2dd95SBruce Richardson v3 |= v4; 42199a2dd95SBruce Richardson 42299a2dd95SBruce Richardson return v1 | v3; 42399a2dd95SBruce Richardson } 42499a2dd95SBruce Richardson 42599a2dd95SBruce Richardson #elif RTE_BITMAP_CL_SLAB_SIZE == 16 42699a2dd95SBruce Richardson static inline uint64_t 42799a2dd95SBruce Richardson __rte_bitmap_line_not_empty(uint64_t *slab2) 42899a2dd95SBruce Richardson { 42999a2dd95SBruce Richardson uint64_t v1, v2, v3, v4, v5, v6, v7, v8; 43099a2dd95SBruce Richardson 43199a2dd95SBruce Richardson v1 = slab2[0] | slab2[1]; 43299a2dd95SBruce Richardson v2 = slab2[2] | slab2[3]; 43399a2dd95SBruce Richardson v3 = slab2[4] | slab2[5]; 43499a2dd95SBruce Richardson v4 = slab2[6] | slab2[7]; 43599a2dd95SBruce Richardson v5 = slab2[8] | slab2[9]; 43699a2dd95SBruce Richardson v6 = slab2[10] | slab2[11]; 43799a2dd95SBruce Richardson v7 = slab2[12] | slab2[13]; 43899a2dd95SBruce Richardson v8 = slab2[14] | slab2[15]; 43999a2dd95SBruce Richardson v1 |= v2; 44099a2dd95SBruce Richardson v3 |= v4; 44199a2dd95SBruce Richardson v5 |= v6; 44299a2dd95SBruce Richardson v7 |= v8; 44399a2dd95SBruce Richardson 44499a2dd95SBruce Richardson return v1 | v3 | v5 | v7; 44599a2dd95SBruce Richardson } 44699a2dd95SBruce Richardson 44799a2dd95SBruce Richardson #endif /* RTE_BITMAP_CL_SLAB_SIZE */ 44899a2dd95SBruce Richardson 44999a2dd95SBruce Richardson /** 45099a2dd95SBruce Richardson * Bitmap bit clear 45199a2dd95SBruce Richardson * 45299a2dd95SBruce Richardson * @param bmp 45399a2dd95SBruce Richardson * Handle to bitmap instance 45499a2dd95SBruce Richardson * @param pos 45599a2dd95SBruce Richardson * Bit position 45699a2dd95SBruce Richardson */ 45799a2dd95SBruce Richardson static inline void 45899a2dd95SBruce Richardson rte_bitmap_clear(struct rte_bitmap *bmp, uint32_t pos) 45999a2dd95SBruce Richardson { 46099a2dd95SBruce Richardson uint64_t *slab1, *slab2; 46199a2dd95SBruce Richardson uint32_t index1, index2, offset1, offset2; 46299a2dd95SBruce Richardson 46399a2dd95SBruce Richardson /* Clear bit in array2 slab */ 46499a2dd95SBruce Richardson index2 = pos >> RTE_BITMAP_SLAB_BIT_SIZE_LOG2; 46599a2dd95SBruce Richardson offset2 = pos & RTE_BITMAP_SLAB_BIT_MASK; 46699a2dd95SBruce Richardson slab2 = bmp->array2 + index2; 46799a2dd95SBruce Richardson 46899a2dd95SBruce Richardson /* Return if array2 slab is not all-zeros */ 46999a2dd95SBruce Richardson *slab2 &= ~(1llu << offset2); 47099a2dd95SBruce Richardson if (*slab2){ 47199a2dd95SBruce Richardson return; 47299a2dd95SBruce Richardson } 47399a2dd95SBruce Richardson 47499a2dd95SBruce Richardson /* Check the entire cache line of array2 for all-zeros */ 47599a2dd95SBruce Richardson index2 &= ~ RTE_BITMAP_CL_SLAB_MASK; 47699a2dd95SBruce Richardson slab2 = bmp->array2 + index2; 47799a2dd95SBruce Richardson if (__rte_bitmap_line_not_empty(slab2)) { 47899a2dd95SBruce Richardson return; 47999a2dd95SBruce Richardson } 48099a2dd95SBruce Richardson 48199a2dd95SBruce Richardson /* The array2 cache line is all-zeros, so clear bit in array1 slab */ 48299a2dd95SBruce Richardson index1 = pos >> (RTE_BITMAP_SLAB_BIT_SIZE_LOG2 + RTE_BITMAP_CL_BIT_SIZE_LOG2); 48399a2dd95SBruce Richardson offset1 = (pos >> RTE_BITMAP_CL_BIT_SIZE_LOG2) & RTE_BITMAP_SLAB_BIT_MASK; 48499a2dd95SBruce Richardson slab1 = bmp->array1 + index1; 48599a2dd95SBruce Richardson *slab1 &= ~(1llu << offset1); 48699a2dd95SBruce Richardson 48799a2dd95SBruce Richardson return; 48899a2dd95SBruce Richardson } 48999a2dd95SBruce Richardson 49099a2dd95SBruce Richardson static inline int 49199a2dd95SBruce Richardson __rte_bitmap_scan_search(struct rte_bitmap *bmp) 49299a2dd95SBruce Richardson { 49399a2dd95SBruce Richardson uint64_t value1; 49499a2dd95SBruce Richardson uint32_t i; 49599a2dd95SBruce Richardson 49699a2dd95SBruce Richardson /* Check current array1 slab */ 49799a2dd95SBruce Richardson value1 = bmp->array1[bmp->index1]; 49899a2dd95SBruce Richardson value1 &= __rte_bitmap_mask1_get(bmp); 49999a2dd95SBruce Richardson 50099a2dd95SBruce Richardson if (rte_bsf64_safe(value1, &bmp->offset1)) 50199a2dd95SBruce Richardson return 1; 50299a2dd95SBruce Richardson 50399a2dd95SBruce Richardson __rte_bitmap_index1_inc(bmp); 50499a2dd95SBruce Richardson bmp->offset1 = 0; 50599a2dd95SBruce Richardson 50699a2dd95SBruce Richardson /* Look for another array1 slab */ 50799a2dd95SBruce Richardson for (i = 0; i < bmp->array1_size; i ++, __rte_bitmap_index1_inc(bmp)) { 50899a2dd95SBruce Richardson value1 = bmp->array1[bmp->index1]; 50999a2dd95SBruce Richardson 51099a2dd95SBruce Richardson if (rte_bsf64_safe(value1, &bmp->offset1)) 51199a2dd95SBruce Richardson return 1; 51299a2dd95SBruce Richardson } 51399a2dd95SBruce Richardson 51499a2dd95SBruce Richardson return 0; 51599a2dd95SBruce Richardson } 51699a2dd95SBruce Richardson 51799a2dd95SBruce Richardson static inline void 51899a2dd95SBruce Richardson __rte_bitmap_scan_read_init(struct rte_bitmap *bmp) 51999a2dd95SBruce Richardson { 52099a2dd95SBruce Richardson __rte_bitmap_index2_set(bmp); 52199a2dd95SBruce Richardson bmp->go2 = 1; 52299a2dd95SBruce Richardson rte_prefetch1((void *)(bmp->array2 + bmp->index2 + 8)); 52399a2dd95SBruce Richardson } 52499a2dd95SBruce Richardson 52599a2dd95SBruce Richardson static inline int 52699a2dd95SBruce Richardson __rte_bitmap_scan_read(struct rte_bitmap *bmp, uint32_t *pos, uint64_t *slab) 52799a2dd95SBruce Richardson { 52899a2dd95SBruce Richardson uint64_t *slab2; 52999a2dd95SBruce Richardson 53099a2dd95SBruce Richardson slab2 = bmp->array2 + bmp->index2; 53199a2dd95SBruce Richardson for ( ; bmp->go2 ; bmp->index2 ++, slab2 ++, bmp->go2 = bmp->index2 & RTE_BITMAP_CL_SLAB_MASK) { 53299a2dd95SBruce Richardson if (*slab2) { 53399a2dd95SBruce Richardson *pos = bmp->index2 << RTE_BITMAP_SLAB_BIT_SIZE_LOG2; 53499a2dd95SBruce Richardson *slab = *slab2; 53599a2dd95SBruce Richardson 53699a2dd95SBruce Richardson bmp->index2 ++; 53799a2dd95SBruce Richardson slab2 ++; 53899a2dd95SBruce Richardson bmp->go2 = bmp->index2 & RTE_BITMAP_CL_SLAB_MASK; 53999a2dd95SBruce Richardson return 1; 54099a2dd95SBruce Richardson } 54199a2dd95SBruce Richardson } 54299a2dd95SBruce Richardson 54399a2dd95SBruce Richardson return 0; 54499a2dd95SBruce Richardson } 54599a2dd95SBruce Richardson 54699a2dd95SBruce Richardson /** 54799a2dd95SBruce Richardson * Bitmap scan (with automatic wrap-around) 54899a2dd95SBruce Richardson * 54999a2dd95SBruce Richardson * @param bmp 55099a2dd95SBruce Richardson * Handle to bitmap instance 55199a2dd95SBruce Richardson * @param pos 55299a2dd95SBruce Richardson * When function call returns 1, pos contains the position of the next set 55399a2dd95SBruce Richardson * bit, otherwise not modified 55499a2dd95SBruce Richardson * @param slab 55599a2dd95SBruce Richardson * When function call returns 1, slab contains the value of the entire 64-bit 55699a2dd95SBruce Richardson * slab where the bit indicated by pos is located. Slabs are always 64-bit 55799a2dd95SBruce Richardson * aligned, so the position of the first bit of the slab (this bit is not 55899a2dd95SBruce Richardson * necessarily set) is pos / 64. Once a slab has been returned by the bitmap 55999a2dd95SBruce Richardson * scan operation, the internal pointers of the bitmap are updated to point 56099a2dd95SBruce Richardson * after this slab, so the same slab will not be returned again if it 56199a2dd95SBruce Richardson * contains more than one bit which is set. When function call returns 0, 56299a2dd95SBruce Richardson * slab is not modified. 56399a2dd95SBruce Richardson * @return 56499a2dd95SBruce Richardson * 0 if there is no bit set in the bitmap, 1 otherwise 56599a2dd95SBruce Richardson */ 56699a2dd95SBruce Richardson static inline int 56799a2dd95SBruce Richardson rte_bitmap_scan(struct rte_bitmap *bmp, uint32_t *pos, uint64_t *slab) 56899a2dd95SBruce Richardson { 56999a2dd95SBruce Richardson /* Return data from current array2 line if available */ 57099a2dd95SBruce Richardson if (__rte_bitmap_scan_read(bmp, pos, slab)) { 57199a2dd95SBruce Richardson return 1; 57299a2dd95SBruce Richardson } 57399a2dd95SBruce Richardson 57499a2dd95SBruce Richardson /* Look for non-empty array2 line */ 57599a2dd95SBruce Richardson if (__rte_bitmap_scan_search(bmp)) { 57699a2dd95SBruce Richardson __rte_bitmap_scan_read_init(bmp); 57799a2dd95SBruce Richardson __rte_bitmap_scan_read(bmp, pos, slab); 57899a2dd95SBruce Richardson return 1; 57999a2dd95SBruce Richardson } 58099a2dd95SBruce Richardson 58199a2dd95SBruce Richardson /* Empty bitmap */ 58299a2dd95SBruce Richardson return 0; 58399a2dd95SBruce Richardson } 58499a2dd95SBruce Richardson 58599a2dd95SBruce Richardson #ifdef __cplusplus 58699a2dd95SBruce Richardson } 58799a2dd95SBruce Richardson #endif 58899a2dd95SBruce Richardson 58999a2dd95SBruce Richardson #endif /* __INCLUDE_RTE_BITMAP_H__ */ 590