146287eacSBing Zhao /* SPDX-License-Identifier: BSD-3-Clause 246287eacSBing Zhao * Copyright 2019 Mellanox Technologies, Ltd 346287eacSBing Zhao */ 446287eacSBing Zhao 546287eacSBing Zhao #include <rte_malloc.h> 646287eacSBing Zhao #include <rte_hash_crc.h> 746287eacSBing Zhao 846287eacSBing Zhao #include "mlx5_utils.h" 946287eacSBing Zhao 1046287eacSBing Zhao struct mlx5_hlist * 1146287eacSBing Zhao mlx5_hlist_create(const char *name, uint32_t size) 1246287eacSBing Zhao { 1346287eacSBing Zhao struct mlx5_hlist *h; 1446287eacSBing Zhao uint32_t act_size; 1546287eacSBing Zhao uint32_t alloc_size; 1646287eacSBing Zhao 1746287eacSBing Zhao if (!size) 1846287eacSBing Zhao return NULL; 1946287eacSBing Zhao /* Align to the next power of 2, 32bits integer is enough now. */ 2046287eacSBing Zhao if (!rte_is_power_of_2(size)) { 2146287eacSBing Zhao act_size = rte_align32pow2(size); 2246287eacSBing Zhao DRV_LOG(WARNING, "Size 0x%" PRIX32 " is not power of 2, will " 2346287eacSBing Zhao "be aligned to 0x%" PRIX32 ".\n", size, act_size); 2446287eacSBing Zhao } else { 2546287eacSBing Zhao act_size = size; 2646287eacSBing Zhao } 2746287eacSBing Zhao alloc_size = sizeof(struct mlx5_hlist) + 2846287eacSBing Zhao sizeof(struct mlx5_hlist_head) * act_size; 2946287eacSBing Zhao /* Using zmalloc, then no need to initialize the heads. */ 3046287eacSBing Zhao h = rte_zmalloc(name, alloc_size, RTE_CACHE_LINE_SIZE); 3146287eacSBing Zhao if (!h) { 3246287eacSBing Zhao DRV_LOG(ERR, "No memory for hash list %s creation\n", 3346287eacSBing Zhao name ? name : "None"); 3446287eacSBing Zhao return NULL; 3546287eacSBing Zhao } 3646287eacSBing Zhao if (name) 3746287eacSBing Zhao snprintf(h->name, MLX5_HLIST_NAMESIZE, "%s", name); 3846287eacSBing Zhao h->table_sz = act_size; 3946287eacSBing Zhao h->mask = act_size - 1; 4046287eacSBing Zhao DRV_LOG(DEBUG, "Hash list with %s size 0x%" PRIX32 " is created.\n", 4146287eacSBing Zhao h->name, act_size); 4246287eacSBing Zhao return h; 4346287eacSBing Zhao } 4446287eacSBing Zhao 4546287eacSBing Zhao struct mlx5_hlist_entry * 4646287eacSBing Zhao mlx5_hlist_lookup(struct mlx5_hlist *h, uint64_t key) 4746287eacSBing Zhao { 4846287eacSBing Zhao uint32_t idx; 4946287eacSBing Zhao struct mlx5_hlist_head *first; 5046287eacSBing Zhao struct mlx5_hlist_entry *node; 5146287eacSBing Zhao 528e46d4e1SAlexander Kozyrev MLX5_ASSERT(h); 5346287eacSBing Zhao idx = rte_hash_crc_8byte(key, 0) & h->mask; 5446287eacSBing Zhao first = &h->heads[idx]; 5546287eacSBing Zhao LIST_FOREACH(node, first, next) { 5646287eacSBing Zhao if (node->key == key) 5746287eacSBing Zhao return node; 5846287eacSBing Zhao } 5946287eacSBing Zhao return NULL; 6046287eacSBing Zhao } 6146287eacSBing Zhao 6246287eacSBing Zhao int 6346287eacSBing Zhao mlx5_hlist_insert(struct mlx5_hlist *h, struct mlx5_hlist_entry *entry) 6446287eacSBing Zhao { 6546287eacSBing Zhao uint32_t idx; 6646287eacSBing Zhao struct mlx5_hlist_head *first; 6746287eacSBing Zhao struct mlx5_hlist_entry *node; 6846287eacSBing Zhao 698e46d4e1SAlexander Kozyrev MLX5_ASSERT(h && entry); 7046287eacSBing Zhao idx = rte_hash_crc_8byte(entry->key, 0) & h->mask; 7146287eacSBing Zhao first = &h->heads[idx]; 7246287eacSBing Zhao /* No need to reuse the lookup function. */ 7346287eacSBing Zhao LIST_FOREACH(node, first, next) { 7446287eacSBing Zhao if (node->key == entry->key) 7546287eacSBing Zhao return -EEXIST; 7646287eacSBing Zhao } 7746287eacSBing Zhao LIST_INSERT_HEAD(first, entry, next); 7846287eacSBing Zhao return 0; 7946287eacSBing Zhao } 8046287eacSBing Zhao 8146287eacSBing Zhao void 8246287eacSBing Zhao mlx5_hlist_remove(struct mlx5_hlist *h __rte_unused, 8346287eacSBing Zhao struct mlx5_hlist_entry *entry) 8446287eacSBing Zhao { 858e46d4e1SAlexander Kozyrev MLX5_ASSERT(entry && entry->next.le_prev); 8646287eacSBing Zhao LIST_REMOVE(entry, next); 8746287eacSBing Zhao /* Set to NULL to get rid of removing action for more than once. */ 8846287eacSBing Zhao entry->next.le_prev = NULL; 8946287eacSBing Zhao } 9046287eacSBing Zhao 9146287eacSBing Zhao void 9246287eacSBing Zhao mlx5_hlist_destroy(struct mlx5_hlist *h, 9346287eacSBing Zhao mlx5_hlist_destroy_callback_fn cb, void *ctx) 9446287eacSBing Zhao { 9546287eacSBing Zhao uint32_t idx; 9646287eacSBing Zhao struct mlx5_hlist_entry *entry; 9746287eacSBing Zhao 988e46d4e1SAlexander Kozyrev MLX5_ASSERT(h); 9946287eacSBing Zhao for (idx = 0; idx < h->table_sz; ++idx) { 10046287eacSBing Zhao /* no LIST_FOREACH_SAFE, using while instead */ 10146287eacSBing Zhao while (!LIST_EMPTY(&h->heads[idx])) { 10246287eacSBing Zhao entry = LIST_FIRST(&h->heads[idx]); 10346287eacSBing Zhao LIST_REMOVE(entry, next); 10446287eacSBing Zhao /* 10546287eacSBing Zhao * The owner of whole element which contains data entry 10646287eacSBing Zhao * is the user, so it's the user's duty to do the clean 10746287eacSBing Zhao * up and the free work because someone may not put the 10846287eacSBing Zhao * hlist entry at the beginning(suggested to locate at 10946287eacSBing Zhao * the beginning). Or else the default free function 11046287eacSBing Zhao * will be used. 11146287eacSBing Zhao */ 11246287eacSBing Zhao if (cb) 11346287eacSBing Zhao cb(entry, ctx); 11446287eacSBing Zhao else 11546287eacSBing Zhao rte_free(entry); 11646287eacSBing Zhao } 11746287eacSBing Zhao } 11846287eacSBing Zhao rte_free(h); 11946287eacSBing Zhao } 120a3cf59f5SSuanming Mou 121a3cf59f5SSuanming Mou static inline void 122a3cf59f5SSuanming Mou mlx5_ipool_lock(struct mlx5_indexed_pool *pool) 123a3cf59f5SSuanming Mou { 124a3cf59f5SSuanming Mou if (pool->cfg.need_lock) 125a3cf59f5SSuanming Mou rte_spinlock_lock(&pool->lock); 126a3cf59f5SSuanming Mou } 127a3cf59f5SSuanming Mou 128a3cf59f5SSuanming Mou static inline void 129a3cf59f5SSuanming Mou mlx5_ipool_unlock(struct mlx5_indexed_pool *pool) 130a3cf59f5SSuanming Mou { 131a3cf59f5SSuanming Mou if (pool->cfg.need_lock) 132a3cf59f5SSuanming Mou rte_spinlock_unlock(&pool->lock); 133a3cf59f5SSuanming Mou } 134a3cf59f5SSuanming Mou 13562d7d519SSuanming Mou static inline uint32_t 13662d7d519SSuanming Mou mlx5_trunk_idx_get(struct mlx5_indexed_pool *pool, uint32_t entry_idx) 13762d7d519SSuanming Mou { 13862d7d519SSuanming Mou struct mlx5_indexed_pool_config *cfg = &pool->cfg; 13962d7d519SSuanming Mou uint32_t trunk_idx = 0; 14062d7d519SSuanming Mou uint32_t i; 14162d7d519SSuanming Mou 14262d7d519SSuanming Mou if (!cfg->grow_trunk) 14362d7d519SSuanming Mou return entry_idx / cfg->trunk_size; 14462d7d519SSuanming Mou if (entry_idx >= pool->grow_tbl[cfg->grow_trunk - 1]) { 14562d7d519SSuanming Mou trunk_idx = (entry_idx - pool->grow_tbl[cfg->grow_trunk - 1]) / 14662d7d519SSuanming Mou (cfg->trunk_size << (cfg->grow_shift * 14762d7d519SSuanming Mou cfg->grow_trunk)) + cfg->grow_trunk; 14862d7d519SSuanming Mou } else { 14962d7d519SSuanming Mou for (i = 0; i < cfg->grow_trunk; i++) { 15062d7d519SSuanming Mou if (entry_idx < pool->grow_tbl[i]) 15162d7d519SSuanming Mou break; 15262d7d519SSuanming Mou } 15362d7d519SSuanming Mou trunk_idx = i; 15462d7d519SSuanming Mou } 15562d7d519SSuanming Mou return trunk_idx; 15662d7d519SSuanming Mou } 15762d7d519SSuanming Mou 15862d7d519SSuanming Mou static inline uint32_t 15962d7d519SSuanming Mou mlx5_trunk_size_get(struct mlx5_indexed_pool *pool, uint32_t trunk_idx) 16062d7d519SSuanming Mou { 16162d7d519SSuanming Mou struct mlx5_indexed_pool_config *cfg = &pool->cfg; 16262d7d519SSuanming Mou 16362d7d519SSuanming Mou return cfg->trunk_size << (cfg->grow_shift * 16462d7d519SSuanming Mou (trunk_idx > cfg->grow_trunk ? cfg->grow_trunk : trunk_idx)); 16562d7d519SSuanming Mou } 16662d7d519SSuanming Mou 16762d7d519SSuanming Mou static inline uint32_t 16862d7d519SSuanming Mou mlx5_trunk_idx_offset_get(struct mlx5_indexed_pool *pool, uint32_t trunk_idx) 16962d7d519SSuanming Mou { 17062d7d519SSuanming Mou struct mlx5_indexed_pool_config *cfg = &pool->cfg; 17162d7d519SSuanming Mou uint32_t offset = 0; 17262d7d519SSuanming Mou 17362d7d519SSuanming Mou if (!trunk_idx) 17462d7d519SSuanming Mou return 0; 17562d7d519SSuanming Mou if (!cfg->grow_trunk) 17662d7d519SSuanming Mou return cfg->trunk_size * trunk_idx; 17762d7d519SSuanming Mou if (trunk_idx < cfg->grow_trunk) 17862d7d519SSuanming Mou offset = pool->grow_tbl[trunk_idx - 1]; 17962d7d519SSuanming Mou else 18062d7d519SSuanming Mou offset = pool->grow_tbl[cfg->grow_trunk - 1] + 18162d7d519SSuanming Mou (cfg->trunk_size << (cfg->grow_shift * 18262d7d519SSuanming Mou cfg->grow_trunk)) * (trunk_idx - cfg->grow_trunk); 18362d7d519SSuanming Mou return offset; 18462d7d519SSuanming Mou } 18562d7d519SSuanming Mou 186a3cf59f5SSuanming Mou struct mlx5_indexed_pool * 187a3cf59f5SSuanming Mou mlx5_ipool_create(struct mlx5_indexed_pool_config *cfg) 188a3cf59f5SSuanming Mou { 189a3cf59f5SSuanming Mou struct mlx5_indexed_pool *pool; 19062d7d519SSuanming Mou uint32_t i; 191a3cf59f5SSuanming Mou 192a3cf59f5SSuanming Mou if (!cfg || !cfg->size || (!cfg->malloc ^ !cfg->free) || 193a3cf59f5SSuanming Mou (cfg->trunk_size && ((cfg->trunk_size & (cfg->trunk_size - 1)) || 194a3cf59f5SSuanming Mou ((__builtin_ffs(cfg->trunk_size) + TRUNK_IDX_BITS) > 32)))) 195a3cf59f5SSuanming Mou return NULL; 19662d7d519SSuanming Mou pool = rte_zmalloc("mlx5_ipool", sizeof(*pool) + cfg->grow_trunk * 19762d7d519SSuanming Mou sizeof(pool->grow_tbl[0]), RTE_CACHE_LINE_SIZE); 198a3cf59f5SSuanming Mou if (!pool) 199a3cf59f5SSuanming Mou return NULL; 200a3cf59f5SSuanming Mou pool->cfg = *cfg; 201a3cf59f5SSuanming Mou if (!pool->cfg.trunk_size) 202a3cf59f5SSuanming Mou pool->cfg.trunk_size = MLX5_IPOOL_DEFAULT_TRUNK_SIZE; 203a3cf59f5SSuanming Mou if (!cfg->malloc && !cfg->free) { 204a3cf59f5SSuanming Mou pool->cfg.malloc = rte_malloc_socket; 205a3cf59f5SSuanming Mou pool->cfg.free = rte_free; 206a3cf59f5SSuanming Mou } 207a3cf59f5SSuanming Mou pool->free_list = TRUNK_INVALID; 208a3cf59f5SSuanming Mou if (pool->cfg.need_lock) 209a3cf59f5SSuanming Mou rte_spinlock_init(&pool->lock); 21062d7d519SSuanming Mou /* 21162d7d519SSuanming Mou * Initialize the dynamic grow trunk size lookup table to have a quick 21262d7d519SSuanming Mou * lookup for the trunk entry index offset. 21362d7d519SSuanming Mou */ 21462d7d519SSuanming Mou for (i = 0; i < cfg->grow_trunk; i++) { 21562d7d519SSuanming Mou pool->grow_tbl[i] = cfg->trunk_size << (cfg->grow_shift * i); 21662d7d519SSuanming Mou if (i > 0) 21762d7d519SSuanming Mou pool->grow_tbl[i] += pool->grow_tbl[i - 1]; 21862d7d519SSuanming Mou } 219a3cf59f5SSuanming Mou return pool; 220a3cf59f5SSuanming Mou } 221a3cf59f5SSuanming Mou 222a3cf59f5SSuanming Mou static int 223a3cf59f5SSuanming Mou mlx5_ipool_grow(struct mlx5_indexed_pool *pool) 224a3cf59f5SSuanming Mou { 225a3cf59f5SSuanming Mou struct mlx5_indexed_trunk *trunk; 226a3cf59f5SSuanming Mou struct mlx5_indexed_trunk **trunk_tmp; 227a3cf59f5SSuanming Mou struct mlx5_indexed_trunk **p; 228a3cf59f5SSuanming Mou size_t trunk_size = 0; 22962d7d519SSuanming Mou size_t data_size; 230a3cf59f5SSuanming Mou size_t bmp_size; 231a3cf59f5SSuanming Mou uint32_t idx; 232a3cf59f5SSuanming Mou 233a3cf59f5SSuanming Mou if (pool->n_trunk_valid == TRUNK_MAX_IDX) 234a3cf59f5SSuanming Mou return -ENOMEM; 235a3cf59f5SSuanming Mou if (pool->n_trunk_valid == pool->n_trunk) { 236a3cf59f5SSuanming Mou /* No free trunk flags, expand trunk list. */ 237a3cf59f5SSuanming Mou int n_grow = pool->n_trunk_valid ? pool->n_trunk : 238a3cf59f5SSuanming Mou RTE_CACHE_LINE_SIZE / sizeof(void *); 239a3cf59f5SSuanming Mou 240a3cf59f5SSuanming Mou p = pool->cfg.malloc(pool->cfg.type, 241a3cf59f5SSuanming Mou (pool->n_trunk_valid + n_grow) * 242a3cf59f5SSuanming Mou sizeof(struct mlx5_indexed_trunk *), 243a3cf59f5SSuanming Mou RTE_CACHE_LINE_SIZE, rte_socket_id()); 244a3cf59f5SSuanming Mou if (!p) 245a3cf59f5SSuanming Mou return -ENOMEM; 246a3cf59f5SSuanming Mou if (pool->trunks) 247a3cf59f5SSuanming Mou memcpy(p, pool->trunks, pool->n_trunk_valid * 248a3cf59f5SSuanming Mou sizeof(struct mlx5_indexed_trunk *)); 249a3cf59f5SSuanming Mou memset(RTE_PTR_ADD(p, pool->n_trunk_valid * sizeof(void *)), 0, 250a3cf59f5SSuanming Mou n_grow * sizeof(void *)); 251a3cf59f5SSuanming Mou trunk_tmp = pool->trunks; 252a3cf59f5SSuanming Mou pool->trunks = p; 253a3cf59f5SSuanming Mou if (trunk_tmp) 254a3cf59f5SSuanming Mou pool->cfg.free(trunk_tmp); 255a3cf59f5SSuanming Mou pool->n_trunk += n_grow; 256a3cf59f5SSuanming Mou } 2571fd4bb67SSuanming Mou if (!pool->cfg.release_mem_en) { 258a3cf59f5SSuanming Mou idx = pool->n_trunk_valid; 2591fd4bb67SSuanming Mou } else { 2601fd4bb67SSuanming Mou /* Find the first available slot in trunk list */ 2611fd4bb67SSuanming Mou for (idx = 0; idx < pool->n_trunk; idx++) 2621fd4bb67SSuanming Mou if (pool->trunks[idx] == NULL) 2631fd4bb67SSuanming Mou break; 2641fd4bb67SSuanming Mou } 265a3cf59f5SSuanming Mou trunk_size += sizeof(*trunk); 26662d7d519SSuanming Mou data_size = mlx5_trunk_size_get(pool, idx); 26762d7d519SSuanming Mou bmp_size = rte_bitmap_get_memory_footprint(data_size); 268*691b3d3eSSuanming Mou /* rte_bitmap requires memory cacheline aligned. */ 269*691b3d3eSSuanming Mou trunk_size += RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size); 270*691b3d3eSSuanming Mou trunk_size += bmp_size; 271a3cf59f5SSuanming Mou trunk = pool->cfg.malloc(pool->cfg.type, trunk_size, 272a3cf59f5SSuanming Mou RTE_CACHE_LINE_SIZE, rte_socket_id()); 273a3cf59f5SSuanming Mou if (!trunk) 274a3cf59f5SSuanming Mou return -ENOMEM; 275a3cf59f5SSuanming Mou pool->trunks[idx] = trunk; 276a3cf59f5SSuanming Mou trunk->idx = idx; 27762d7d519SSuanming Mou trunk->free = data_size; 278a3cf59f5SSuanming Mou trunk->prev = TRUNK_INVALID; 279a3cf59f5SSuanming Mou trunk->next = TRUNK_INVALID; 280a3cf59f5SSuanming Mou MLX5_ASSERT(pool->free_list == TRUNK_INVALID); 281a3cf59f5SSuanming Mou pool->free_list = idx; 282a3cf59f5SSuanming Mou /* Mark all entries as available. */ 283*691b3d3eSSuanming Mou trunk->bmp = rte_bitmap_init_with_all_set(data_size, &trunk->data 284*691b3d3eSSuanming Mou [RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size)], 285*691b3d3eSSuanming Mou bmp_size); 286*691b3d3eSSuanming Mou MLX5_ASSERT(trunk->bmp); 287a3cf59f5SSuanming Mou pool->n_trunk_valid++; 288a3cf59f5SSuanming Mou #ifdef POOL_DEBUG 289a3cf59f5SSuanming Mou pool->trunk_new++; 290a3cf59f5SSuanming Mou pool->trunk_avail++; 291a3cf59f5SSuanming Mou #endif 292a3cf59f5SSuanming Mou return 0; 293a3cf59f5SSuanming Mou } 294a3cf59f5SSuanming Mou 295a3cf59f5SSuanming Mou void * 296a3cf59f5SSuanming Mou mlx5_ipool_malloc(struct mlx5_indexed_pool *pool, uint32_t *idx) 297a3cf59f5SSuanming Mou { 298a3cf59f5SSuanming Mou struct mlx5_indexed_trunk *trunk; 299a3cf59f5SSuanming Mou uint64_t slab = 0; 300a3cf59f5SSuanming Mou uint32_t iidx = 0; 301a3cf59f5SSuanming Mou void *p; 302a3cf59f5SSuanming Mou 303a3cf59f5SSuanming Mou mlx5_ipool_lock(pool); 304a3cf59f5SSuanming Mou if (pool->free_list == TRUNK_INVALID) { 305a3cf59f5SSuanming Mou /* If no available trunks, grow new. */ 306a3cf59f5SSuanming Mou if (mlx5_ipool_grow(pool)) { 307a3cf59f5SSuanming Mou mlx5_ipool_unlock(pool); 308a3cf59f5SSuanming Mou return NULL; 309a3cf59f5SSuanming Mou } 310a3cf59f5SSuanming Mou } 311a3cf59f5SSuanming Mou MLX5_ASSERT(pool->free_list != TRUNK_INVALID); 312a3cf59f5SSuanming Mou trunk = pool->trunks[pool->free_list]; 313a3cf59f5SSuanming Mou MLX5_ASSERT(trunk->free); 314a3cf59f5SSuanming Mou if (!rte_bitmap_scan(trunk->bmp, &iidx, &slab)) { 315a3cf59f5SSuanming Mou mlx5_ipool_unlock(pool); 316a3cf59f5SSuanming Mou return NULL; 317a3cf59f5SSuanming Mou } 318a3cf59f5SSuanming Mou MLX5_ASSERT(slab); 319a3cf59f5SSuanming Mou iidx += __builtin_ctzll(slab); 320a3cf59f5SSuanming Mou MLX5_ASSERT(iidx != UINT32_MAX); 32162d7d519SSuanming Mou MLX5_ASSERT(iidx < mlx5_trunk_size_get(pool, trunk->idx)); 322a3cf59f5SSuanming Mou rte_bitmap_clear(trunk->bmp, iidx); 323a3cf59f5SSuanming Mou p = &trunk->data[iidx * pool->cfg.size]; 32462d7d519SSuanming Mou iidx += mlx5_trunk_idx_offset_get(pool, trunk->idx); 325a3cf59f5SSuanming Mou iidx += 1; /* non-zero index. */ 326a3cf59f5SSuanming Mou trunk->free--; 327a3cf59f5SSuanming Mou #ifdef POOL_DEBUG 328a3cf59f5SSuanming Mou pool->n_entry++; 329a3cf59f5SSuanming Mou #endif 330a3cf59f5SSuanming Mou if (!trunk->free) { 331a3cf59f5SSuanming Mou /* Full trunk will be removed from free list in imalloc. */ 332a3cf59f5SSuanming Mou MLX5_ASSERT(pool->free_list == trunk->idx); 333a3cf59f5SSuanming Mou pool->free_list = trunk->next; 334a3cf59f5SSuanming Mou if (trunk->next != TRUNK_INVALID) 335a3cf59f5SSuanming Mou pool->trunks[trunk->next]->prev = TRUNK_INVALID; 336a3cf59f5SSuanming Mou trunk->prev = TRUNK_INVALID; 337a3cf59f5SSuanming Mou trunk->next = TRUNK_INVALID; 338a3cf59f5SSuanming Mou #ifdef POOL_DEBUG 339a3cf59f5SSuanming Mou pool->trunk_empty++; 340a3cf59f5SSuanming Mou pool->trunk_avail--; 341a3cf59f5SSuanming Mou #endif 342a3cf59f5SSuanming Mou } 343a3cf59f5SSuanming Mou *idx = iidx; 344a3cf59f5SSuanming Mou mlx5_ipool_unlock(pool); 345a3cf59f5SSuanming Mou return p; 346a3cf59f5SSuanming Mou } 347a3cf59f5SSuanming Mou 348a3cf59f5SSuanming Mou void * 349a3cf59f5SSuanming Mou mlx5_ipool_zmalloc(struct mlx5_indexed_pool *pool, uint32_t *idx) 350a3cf59f5SSuanming Mou { 351a3cf59f5SSuanming Mou void *entry = mlx5_ipool_malloc(pool, idx); 352a3cf59f5SSuanming Mou 353a3cf59f5SSuanming Mou if (entry) 354a3cf59f5SSuanming Mou memset(entry, 0, pool->cfg.size); 355a3cf59f5SSuanming Mou return entry; 356a3cf59f5SSuanming Mou } 357a3cf59f5SSuanming Mou 358a3cf59f5SSuanming Mou void 359a3cf59f5SSuanming Mou mlx5_ipool_free(struct mlx5_indexed_pool *pool, uint32_t idx) 360a3cf59f5SSuanming Mou { 361a3cf59f5SSuanming Mou struct mlx5_indexed_trunk *trunk; 362a3cf59f5SSuanming Mou uint32_t trunk_idx; 36362d7d519SSuanming Mou uint32_t entry_idx; 364a3cf59f5SSuanming Mou 365a3cf59f5SSuanming Mou if (!idx) 366a3cf59f5SSuanming Mou return; 367a3cf59f5SSuanming Mou idx -= 1; 368a3cf59f5SSuanming Mou mlx5_ipool_lock(pool); 36962d7d519SSuanming Mou trunk_idx = mlx5_trunk_idx_get(pool, idx); 3701fd4bb67SSuanming Mou if ((!pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk_valid) || 3711fd4bb67SSuanming Mou (pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk)) 372a3cf59f5SSuanming Mou goto out; 373a3cf59f5SSuanming Mou trunk = pool->trunks[trunk_idx]; 37462d7d519SSuanming Mou if (!trunk) 375a3cf59f5SSuanming Mou goto out; 37662d7d519SSuanming Mou entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk->idx); 37762d7d519SSuanming Mou if (trunk_idx != trunk->idx || 37862d7d519SSuanming Mou rte_bitmap_get(trunk->bmp, entry_idx)) 37962d7d519SSuanming Mou goto out; 38062d7d519SSuanming Mou rte_bitmap_set(trunk->bmp, entry_idx); 381a3cf59f5SSuanming Mou trunk->free++; 3821fd4bb67SSuanming Mou if (pool->cfg.release_mem_en && trunk->free == mlx5_trunk_size_get 3831fd4bb67SSuanming Mou (pool, trunk->idx)) { 3841fd4bb67SSuanming Mou if (pool->free_list == trunk->idx) 3851fd4bb67SSuanming Mou pool->free_list = trunk->next; 3861fd4bb67SSuanming Mou if (trunk->next != TRUNK_INVALID) 3871fd4bb67SSuanming Mou pool->trunks[trunk->next]->prev = trunk->prev; 3881fd4bb67SSuanming Mou if (trunk->prev != TRUNK_INVALID) 3891fd4bb67SSuanming Mou pool->trunks[trunk->prev]->next = trunk->next; 3901fd4bb67SSuanming Mou pool->cfg.free(trunk); 3911fd4bb67SSuanming Mou pool->trunks[trunk_idx] = NULL; 3921fd4bb67SSuanming Mou pool->n_trunk_valid--; 3931fd4bb67SSuanming Mou #ifdef POOL_DEBUG 3941fd4bb67SSuanming Mou pool->trunk_avail--; 3951fd4bb67SSuanming Mou pool->trunk_free++; 3961fd4bb67SSuanming Mou #endif 3971fd4bb67SSuanming Mou if (pool->n_trunk_valid == 0) { 3981fd4bb67SSuanming Mou pool->cfg.free(pool->trunks); 3991fd4bb67SSuanming Mou pool->trunks = NULL; 4001fd4bb67SSuanming Mou pool->n_trunk = 0; 4011fd4bb67SSuanming Mou } 4021fd4bb67SSuanming Mou } else if (trunk->free == 1) { 403a3cf59f5SSuanming Mou /* Put into free trunk list head. */ 404a3cf59f5SSuanming Mou MLX5_ASSERT(pool->free_list != trunk->idx); 405a3cf59f5SSuanming Mou trunk->next = pool->free_list; 406a3cf59f5SSuanming Mou trunk->prev = TRUNK_INVALID; 407a3cf59f5SSuanming Mou if (pool->free_list != TRUNK_INVALID) 408a3cf59f5SSuanming Mou pool->trunks[pool->free_list]->prev = trunk->idx; 409a3cf59f5SSuanming Mou pool->free_list = trunk->idx; 410a3cf59f5SSuanming Mou #ifdef POOL_DEBUG 411a3cf59f5SSuanming Mou pool->trunk_empty--; 412a3cf59f5SSuanming Mou pool->trunk_avail++; 413a3cf59f5SSuanming Mou #endif 414a3cf59f5SSuanming Mou } 415a3cf59f5SSuanming Mou #ifdef POOL_DEBUG 416a3cf59f5SSuanming Mou pool->n_entry--; 417a3cf59f5SSuanming Mou #endif 418a3cf59f5SSuanming Mou out: 419a3cf59f5SSuanming Mou mlx5_ipool_unlock(pool); 420a3cf59f5SSuanming Mou } 421a3cf59f5SSuanming Mou 422a3cf59f5SSuanming Mou void * 423a3cf59f5SSuanming Mou mlx5_ipool_get(struct mlx5_indexed_pool *pool, uint32_t idx) 424a3cf59f5SSuanming Mou { 425a3cf59f5SSuanming Mou struct mlx5_indexed_trunk *trunk; 426a3cf59f5SSuanming Mou void *p = NULL; 427a3cf59f5SSuanming Mou uint32_t trunk_idx; 42862d7d519SSuanming Mou uint32_t entry_idx; 429a3cf59f5SSuanming Mou 430a3cf59f5SSuanming Mou if (!idx) 431a3cf59f5SSuanming Mou return NULL; 432a3cf59f5SSuanming Mou idx -= 1; 433a3cf59f5SSuanming Mou mlx5_ipool_lock(pool); 43462d7d519SSuanming Mou trunk_idx = mlx5_trunk_idx_get(pool, idx); 4351fd4bb67SSuanming Mou if ((!pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk_valid) || 4361fd4bb67SSuanming Mou (pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk)) 437a3cf59f5SSuanming Mou goto out; 438a3cf59f5SSuanming Mou trunk = pool->trunks[trunk_idx]; 43962d7d519SSuanming Mou if (!trunk) 440a3cf59f5SSuanming Mou goto out; 44162d7d519SSuanming Mou entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk->idx); 44262d7d519SSuanming Mou if (trunk_idx != trunk->idx || 44362d7d519SSuanming Mou rte_bitmap_get(trunk->bmp, entry_idx)) 44462d7d519SSuanming Mou goto out; 44562d7d519SSuanming Mou p = &trunk->data[entry_idx * pool->cfg.size]; 446a3cf59f5SSuanming Mou out: 447a3cf59f5SSuanming Mou mlx5_ipool_unlock(pool); 448a3cf59f5SSuanming Mou return p; 449a3cf59f5SSuanming Mou } 450a3cf59f5SSuanming Mou 451a3cf59f5SSuanming Mou int 452a3cf59f5SSuanming Mou mlx5_ipool_destroy(struct mlx5_indexed_pool *pool) 453a3cf59f5SSuanming Mou { 454a3cf59f5SSuanming Mou struct mlx5_indexed_trunk **trunks; 455a3cf59f5SSuanming Mou uint32_t i; 456a3cf59f5SSuanming Mou 457a3cf59f5SSuanming Mou MLX5_ASSERT(pool); 458a3cf59f5SSuanming Mou mlx5_ipool_lock(pool); 459a3cf59f5SSuanming Mou trunks = pool->trunks; 460a3cf59f5SSuanming Mou for (i = 0; i < pool->n_trunk; i++) { 461a3cf59f5SSuanming Mou if (trunks[i]) 462a3cf59f5SSuanming Mou pool->cfg.free(trunks[i]); 463a3cf59f5SSuanming Mou } 464a3cf59f5SSuanming Mou if (!pool->trunks) 465a3cf59f5SSuanming Mou pool->cfg.free(pool->trunks); 466a3cf59f5SSuanming Mou mlx5_ipool_unlock(pool); 467a3cf59f5SSuanming Mou rte_free(pool); 468a3cf59f5SSuanming Mou return 0; 469a3cf59f5SSuanming Mou } 470a3cf59f5SSuanming Mou 471a3cf59f5SSuanming Mou void 472a3cf59f5SSuanming Mou mlx5_ipool_dump(struct mlx5_indexed_pool *pool) 473a3cf59f5SSuanming Mou { 474a3cf59f5SSuanming Mou printf("Pool %s entry size %u, trunks %u, %d entry per trunk, " 475a3cf59f5SSuanming Mou "total: %d\n", 476a3cf59f5SSuanming Mou pool->cfg.type, pool->cfg.size, pool->n_trunk_valid, 477a3cf59f5SSuanming Mou pool->cfg.trunk_size, pool->n_trunk_valid); 478a3cf59f5SSuanming Mou #ifdef POOL_DEBUG 479a3cf59f5SSuanming Mou printf("Pool %s entry %u, trunk alloc %u, empty: %u, " 480a3cf59f5SSuanming Mou "available %u free %u\n", 481a3cf59f5SSuanming Mou pool->cfg.type, pool->n_entry, pool->trunk_new, 482a3cf59f5SSuanming Mou pool->trunk_empty, pool->trunk_avail, pool->trunk_free); 483a3cf59f5SSuanming Mou #endif 484a3cf59f5SSuanming Mou } 485