xref: /dpdk/drivers/net/mlx5/mlx5_utils.c (revision 83c2047c5fe82fb25674c3053d4871838e7455cb)
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 
8*83c2047cSSuanming Mou #include <mlx5_malloc.h>
9*83c2047cSSuanming Mou 
1046287eacSBing Zhao #include "mlx5_utils.h"
1146287eacSBing Zhao 
1246287eacSBing Zhao struct mlx5_hlist *
1346287eacSBing Zhao mlx5_hlist_create(const char *name, uint32_t size)
1446287eacSBing Zhao {
1546287eacSBing Zhao 	struct mlx5_hlist *h;
1646287eacSBing Zhao 	uint32_t act_size;
1746287eacSBing Zhao 	uint32_t alloc_size;
1846287eacSBing Zhao 
1946287eacSBing Zhao 	if (!size)
2046287eacSBing Zhao 		return NULL;
2146287eacSBing Zhao 	/* Align to the next power of 2, 32bits integer is enough now. */
2246287eacSBing Zhao 	if (!rte_is_power_of_2(size)) {
2346287eacSBing Zhao 		act_size = rte_align32pow2(size);
2446287eacSBing Zhao 		DRV_LOG(WARNING, "Size 0x%" PRIX32 " is not power of 2, will "
2563783b01SDavid Marchand 			"be aligned to 0x%" PRIX32 ".", size, act_size);
2646287eacSBing Zhao 	} else {
2746287eacSBing Zhao 		act_size = size;
2846287eacSBing Zhao 	}
2946287eacSBing Zhao 	alloc_size = sizeof(struct mlx5_hlist) +
3046287eacSBing Zhao 		     sizeof(struct mlx5_hlist_head) * act_size;
3146287eacSBing Zhao 	/* Using zmalloc, then no need to initialize the heads. */
32*83c2047cSSuanming Mou 	h = mlx5_malloc(MLX5_MEM_ZERO, alloc_size, RTE_CACHE_LINE_SIZE,
33*83c2047cSSuanming Mou 			SOCKET_ID_ANY);
3446287eacSBing Zhao 	if (!h) {
3563783b01SDavid Marchand 		DRV_LOG(ERR, "No memory for hash list %s creation",
3646287eacSBing Zhao 			name ? name : "None");
3746287eacSBing Zhao 		return NULL;
3846287eacSBing Zhao 	}
3946287eacSBing Zhao 	if (name)
4046287eacSBing Zhao 		snprintf(h->name, MLX5_HLIST_NAMESIZE, "%s", name);
4146287eacSBing Zhao 	h->table_sz = act_size;
4246287eacSBing Zhao 	h->mask = act_size - 1;
4363783b01SDavid Marchand 	DRV_LOG(DEBUG, "Hash list with %s size 0x%" PRIX32 " is created.",
4446287eacSBing Zhao 		h->name, act_size);
4546287eacSBing Zhao 	return h;
4646287eacSBing Zhao }
4746287eacSBing Zhao 
4846287eacSBing Zhao struct mlx5_hlist_entry *
4946287eacSBing Zhao mlx5_hlist_lookup(struct mlx5_hlist *h, uint64_t key)
5046287eacSBing Zhao {
5146287eacSBing Zhao 	uint32_t idx;
5246287eacSBing Zhao 	struct mlx5_hlist_head *first;
5346287eacSBing Zhao 	struct mlx5_hlist_entry *node;
5446287eacSBing Zhao 
558e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(h);
5646287eacSBing Zhao 	idx = rte_hash_crc_8byte(key, 0) & h->mask;
5746287eacSBing Zhao 	first = &h->heads[idx];
5846287eacSBing Zhao 	LIST_FOREACH(node, first, next) {
5946287eacSBing Zhao 		if (node->key == key)
6046287eacSBing Zhao 			return node;
6146287eacSBing Zhao 	}
6246287eacSBing Zhao 	return NULL;
6346287eacSBing Zhao }
6446287eacSBing Zhao 
6546287eacSBing Zhao int
6646287eacSBing Zhao mlx5_hlist_insert(struct mlx5_hlist *h, struct mlx5_hlist_entry *entry)
6746287eacSBing Zhao {
6846287eacSBing Zhao 	uint32_t idx;
6946287eacSBing Zhao 	struct mlx5_hlist_head *first;
7046287eacSBing Zhao 	struct mlx5_hlist_entry *node;
7146287eacSBing Zhao 
728e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(h && entry);
7346287eacSBing Zhao 	idx = rte_hash_crc_8byte(entry->key, 0) & h->mask;
7446287eacSBing Zhao 	first = &h->heads[idx];
7546287eacSBing Zhao 	/* No need to reuse the lookup function. */
7646287eacSBing Zhao 	LIST_FOREACH(node, first, next) {
7746287eacSBing Zhao 		if (node->key == entry->key)
7846287eacSBing Zhao 			return -EEXIST;
7946287eacSBing Zhao 	}
8046287eacSBing Zhao 	LIST_INSERT_HEAD(first, entry, next);
8146287eacSBing Zhao 	return 0;
8246287eacSBing Zhao }
8346287eacSBing Zhao 
8446287eacSBing Zhao void
8546287eacSBing Zhao mlx5_hlist_remove(struct mlx5_hlist *h __rte_unused,
8646287eacSBing Zhao 		  struct mlx5_hlist_entry *entry)
8746287eacSBing Zhao {
888e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(entry && entry->next.le_prev);
8946287eacSBing Zhao 	LIST_REMOVE(entry, next);
9046287eacSBing Zhao 	/* Set to NULL to get rid of removing action for more than once. */
9146287eacSBing Zhao 	entry->next.le_prev = NULL;
9246287eacSBing Zhao }
9346287eacSBing Zhao 
9446287eacSBing Zhao void
9546287eacSBing Zhao mlx5_hlist_destroy(struct mlx5_hlist *h,
9646287eacSBing Zhao 		   mlx5_hlist_destroy_callback_fn cb, void *ctx)
9746287eacSBing Zhao {
9846287eacSBing Zhao 	uint32_t idx;
9946287eacSBing Zhao 	struct mlx5_hlist_entry *entry;
10046287eacSBing Zhao 
1018e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(h);
10246287eacSBing Zhao 	for (idx = 0; idx < h->table_sz; ++idx) {
10346287eacSBing Zhao 		/* no LIST_FOREACH_SAFE, using while instead */
10446287eacSBing Zhao 		while (!LIST_EMPTY(&h->heads[idx])) {
10546287eacSBing Zhao 			entry = LIST_FIRST(&h->heads[idx]);
10646287eacSBing Zhao 			LIST_REMOVE(entry, next);
10746287eacSBing Zhao 			/*
10846287eacSBing Zhao 			 * The owner of whole element which contains data entry
10946287eacSBing Zhao 			 * is the user, so it's the user's duty to do the clean
11046287eacSBing Zhao 			 * up and the free work because someone may not put the
11146287eacSBing Zhao 			 * hlist entry at the beginning(suggested to locate at
11246287eacSBing Zhao 			 * the beginning). Or else the default free function
11346287eacSBing Zhao 			 * will be used.
11446287eacSBing Zhao 			 */
11546287eacSBing Zhao 			if (cb)
11646287eacSBing Zhao 				cb(entry, ctx);
11746287eacSBing Zhao 			else
118*83c2047cSSuanming Mou 				mlx5_free(entry);
11946287eacSBing Zhao 		}
12046287eacSBing Zhao 	}
121*83c2047cSSuanming Mou 	mlx5_free(h);
12246287eacSBing Zhao }
123a3cf59f5SSuanming Mou 
124a3cf59f5SSuanming Mou static inline void
125a3cf59f5SSuanming Mou mlx5_ipool_lock(struct mlx5_indexed_pool *pool)
126a3cf59f5SSuanming Mou {
127a3cf59f5SSuanming Mou 	if (pool->cfg.need_lock)
128a3cf59f5SSuanming Mou 		rte_spinlock_lock(&pool->lock);
129a3cf59f5SSuanming Mou }
130a3cf59f5SSuanming Mou 
131a3cf59f5SSuanming Mou static inline void
132a3cf59f5SSuanming Mou mlx5_ipool_unlock(struct mlx5_indexed_pool *pool)
133a3cf59f5SSuanming Mou {
134a3cf59f5SSuanming Mou 	if (pool->cfg.need_lock)
135a3cf59f5SSuanming Mou 		rte_spinlock_unlock(&pool->lock);
136a3cf59f5SSuanming Mou }
137a3cf59f5SSuanming Mou 
13862d7d519SSuanming Mou static inline uint32_t
13962d7d519SSuanming Mou mlx5_trunk_idx_get(struct mlx5_indexed_pool *pool, uint32_t entry_idx)
14062d7d519SSuanming Mou {
14162d7d519SSuanming Mou 	struct mlx5_indexed_pool_config *cfg = &pool->cfg;
14262d7d519SSuanming Mou 	uint32_t trunk_idx = 0;
14362d7d519SSuanming Mou 	uint32_t i;
14462d7d519SSuanming Mou 
14562d7d519SSuanming Mou 	if (!cfg->grow_trunk)
14662d7d519SSuanming Mou 		return entry_idx / cfg->trunk_size;
14762d7d519SSuanming Mou 	if (entry_idx >= pool->grow_tbl[cfg->grow_trunk - 1]) {
14862d7d519SSuanming Mou 		trunk_idx = (entry_idx - pool->grow_tbl[cfg->grow_trunk - 1]) /
14962d7d519SSuanming Mou 			    (cfg->trunk_size << (cfg->grow_shift *
15062d7d519SSuanming Mou 			    cfg->grow_trunk)) + cfg->grow_trunk;
15162d7d519SSuanming Mou 	} else {
15262d7d519SSuanming Mou 		for (i = 0; i < cfg->grow_trunk; i++) {
15362d7d519SSuanming Mou 			if (entry_idx < pool->grow_tbl[i])
15462d7d519SSuanming Mou 				break;
15562d7d519SSuanming Mou 		}
15662d7d519SSuanming Mou 		trunk_idx = i;
15762d7d519SSuanming Mou 	}
15862d7d519SSuanming Mou 	return trunk_idx;
15962d7d519SSuanming Mou }
16062d7d519SSuanming Mou 
16162d7d519SSuanming Mou static inline uint32_t
16262d7d519SSuanming Mou mlx5_trunk_size_get(struct mlx5_indexed_pool *pool, uint32_t trunk_idx)
16362d7d519SSuanming Mou {
16462d7d519SSuanming Mou 	struct mlx5_indexed_pool_config *cfg = &pool->cfg;
16562d7d519SSuanming Mou 
16662d7d519SSuanming Mou 	return cfg->trunk_size << (cfg->grow_shift *
16762d7d519SSuanming Mou 	       (trunk_idx > cfg->grow_trunk ? cfg->grow_trunk : trunk_idx));
16862d7d519SSuanming Mou }
16962d7d519SSuanming Mou 
17062d7d519SSuanming Mou static inline uint32_t
17162d7d519SSuanming Mou mlx5_trunk_idx_offset_get(struct mlx5_indexed_pool *pool, uint32_t trunk_idx)
17262d7d519SSuanming Mou {
17362d7d519SSuanming Mou 	struct mlx5_indexed_pool_config *cfg = &pool->cfg;
17462d7d519SSuanming Mou 	uint32_t offset = 0;
17562d7d519SSuanming Mou 
17662d7d519SSuanming Mou 	if (!trunk_idx)
17762d7d519SSuanming Mou 		return 0;
17862d7d519SSuanming Mou 	if (!cfg->grow_trunk)
17962d7d519SSuanming Mou 		return cfg->trunk_size * trunk_idx;
18062d7d519SSuanming Mou 	if (trunk_idx < cfg->grow_trunk)
18162d7d519SSuanming Mou 		offset = pool->grow_tbl[trunk_idx - 1];
18262d7d519SSuanming Mou 	else
18362d7d519SSuanming Mou 		offset = pool->grow_tbl[cfg->grow_trunk - 1] +
18462d7d519SSuanming Mou 			 (cfg->trunk_size << (cfg->grow_shift *
18562d7d519SSuanming Mou 			 cfg->grow_trunk)) * (trunk_idx - cfg->grow_trunk);
18662d7d519SSuanming Mou 	return offset;
18762d7d519SSuanming Mou }
18862d7d519SSuanming Mou 
189a3cf59f5SSuanming Mou struct mlx5_indexed_pool *
190a3cf59f5SSuanming Mou mlx5_ipool_create(struct mlx5_indexed_pool_config *cfg)
191a3cf59f5SSuanming Mou {
192a3cf59f5SSuanming Mou 	struct mlx5_indexed_pool *pool;
19362d7d519SSuanming Mou 	uint32_t i;
194a3cf59f5SSuanming Mou 
195a3cf59f5SSuanming Mou 	if (!cfg || !cfg->size || (!cfg->malloc ^ !cfg->free) ||
196a3cf59f5SSuanming Mou 	    (cfg->trunk_size && ((cfg->trunk_size & (cfg->trunk_size - 1)) ||
197a3cf59f5SSuanming Mou 	    ((__builtin_ffs(cfg->trunk_size) + TRUNK_IDX_BITS) > 32))))
198a3cf59f5SSuanming Mou 		return NULL;
199*83c2047cSSuanming Mou 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool) + cfg->grow_trunk *
200*83c2047cSSuanming Mou 			   sizeof(pool->grow_tbl[0]), RTE_CACHE_LINE_SIZE,
201*83c2047cSSuanming Mou 			   SOCKET_ID_ANY);
202a3cf59f5SSuanming Mou 	if (!pool)
203a3cf59f5SSuanming Mou 		return NULL;
204a3cf59f5SSuanming Mou 	pool->cfg = *cfg;
205a3cf59f5SSuanming Mou 	if (!pool->cfg.trunk_size)
206a3cf59f5SSuanming Mou 		pool->cfg.trunk_size = MLX5_IPOOL_DEFAULT_TRUNK_SIZE;
207a3cf59f5SSuanming Mou 	if (!cfg->malloc && !cfg->free) {
208*83c2047cSSuanming Mou 		pool->cfg.malloc = mlx5_malloc;
209*83c2047cSSuanming Mou 		pool->cfg.free = mlx5_free;
210a3cf59f5SSuanming Mou 	}
211a3cf59f5SSuanming Mou 	pool->free_list = TRUNK_INVALID;
212a3cf59f5SSuanming Mou 	if (pool->cfg.need_lock)
213a3cf59f5SSuanming Mou 		rte_spinlock_init(&pool->lock);
21462d7d519SSuanming Mou 	/*
21562d7d519SSuanming Mou 	 * Initialize the dynamic grow trunk size lookup table to have a quick
21662d7d519SSuanming Mou 	 * lookup for the trunk entry index offset.
21762d7d519SSuanming Mou 	 */
21862d7d519SSuanming Mou 	for (i = 0; i < cfg->grow_trunk; i++) {
21962d7d519SSuanming Mou 		pool->grow_tbl[i] = cfg->trunk_size << (cfg->grow_shift * i);
22062d7d519SSuanming Mou 		if (i > 0)
22162d7d519SSuanming Mou 			pool->grow_tbl[i] += pool->grow_tbl[i - 1];
22262d7d519SSuanming Mou 	}
223a3cf59f5SSuanming Mou 	return pool;
224a3cf59f5SSuanming Mou }
225a3cf59f5SSuanming Mou 
226a3cf59f5SSuanming Mou static int
227a3cf59f5SSuanming Mou mlx5_ipool_grow(struct mlx5_indexed_pool *pool)
228a3cf59f5SSuanming Mou {
229a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk *trunk;
230a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk **trunk_tmp;
231a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk **p;
232a3cf59f5SSuanming Mou 	size_t trunk_size = 0;
23362d7d519SSuanming Mou 	size_t data_size;
234a3cf59f5SSuanming Mou 	size_t bmp_size;
235a3cf59f5SSuanming Mou 	uint32_t idx;
236a3cf59f5SSuanming Mou 
237a3cf59f5SSuanming Mou 	if (pool->n_trunk_valid == TRUNK_MAX_IDX)
238a3cf59f5SSuanming Mou 		return -ENOMEM;
239a3cf59f5SSuanming Mou 	if (pool->n_trunk_valid == pool->n_trunk) {
240a3cf59f5SSuanming Mou 		/* No free trunk flags, expand trunk list. */
241a3cf59f5SSuanming Mou 		int n_grow = pool->n_trunk_valid ? pool->n_trunk :
242a3cf59f5SSuanming Mou 			     RTE_CACHE_LINE_SIZE / sizeof(void *);
243a3cf59f5SSuanming Mou 
244*83c2047cSSuanming Mou 		p = pool->cfg.malloc(0, (pool->n_trunk_valid + n_grow) *
245a3cf59f5SSuanming Mou 				     sizeof(struct mlx5_indexed_trunk *),
246a3cf59f5SSuanming Mou 				     RTE_CACHE_LINE_SIZE, rte_socket_id());
247a3cf59f5SSuanming Mou 		if (!p)
248a3cf59f5SSuanming Mou 			return -ENOMEM;
249a3cf59f5SSuanming Mou 		if (pool->trunks)
250a3cf59f5SSuanming Mou 			memcpy(p, pool->trunks, pool->n_trunk_valid *
251a3cf59f5SSuanming Mou 			       sizeof(struct mlx5_indexed_trunk *));
252a3cf59f5SSuanming Mou 		memset(RTE_PTR_ADD(p, pool->n_trunk_valid * sizeof(void *)), 0,
253a3cf59f5SSuanming Mou 		       n_grow * sizeof(void *));
254a3cf59f5SSuanming Mou 		trunk_tmp = pool->trunks;
255a3cf59f5SSuanming Mou 		pool->trunks = p;
256a3cf59f5SSuanming Mou 		if (trunk_tmp)
257a3cf59f5SSuanming Mou 			pool->cfg.free(trunk_tmp);
258a3cf59f5SSuanming Mou 		pool->n_trunk += n_grow;
259a3cf59f5SSuanming Mou 	}
2601fd4bb67SSuanming Mou 	if (!pool->cfg.release_mem_en) {
261a3cf59f5SSuanming Mou 		idx = pool->n_trunk_valid;
2621fd4bb67SSuanming Mou 	} else {
2631fd4bb67SSuanming Mou 		/* Find the first available slot in trunk list */
2641fd4bb67SSuanming Mou 		for (idx = 0; idx < pool->n_trunk; idx++)
2651fd4bb67SSuanming Mou 			if (pool->trunks[idx] == NULL)
2661fd4bb67SSuanming Mou 				break;
2671fd4bb67SSuanming Mou 	}
268a3cf59f5SSuanming Mou 	trunk_size += sizeof(*trunk);
26962d7d519SSuanming Mou 	data_size = mlx5_trunk_size_get(pool, idx);
27062d7d519SSuanming Mou 	bmp_size = rte_bitmap_get_memory_footprint(data_size);
271691b3d3eSSuanming Mou 	/* rte_bitmap requires memory cacheline aligned. */
272691b3d3eSSuanming Mou 	trunk_size += RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size);
273691b3d3eSSuanming Mou 	trunk_size += bmp_size;
274*83c2047cSSuanming Mou 	trunk = pool->cfg.malloc(0, trunk_size,
275a3cf59f5SSuanming Mou 				 RTE_CACHE_LINE_SIZE, rte_socket_id());
276a3cf59f5SSuanming Mou 	if (!trunk)
277a3cf59f5SSuanming Mou 		return -ENOMEM;
278a3cf59f5SSuanming Mou 	pool->trunks[idx] = trunk;
279a3cf59f5SSuanming Mou 	trunk->idx = idx;
28062d7d519SSuanming Mou 	trunk->free = data_size;
281a3cf59f5SSuanming Mou 	trunk->prev = TRUNK_INVALID;
282a3cf59f5SSuanming Mou 	trunk->next = TRUNK_INVALID;
283a3cf59f5SSuanming Mou 	MLX5_ASSERT(pool->free_list == TRUNK_INVALID);
284a3cf59f5SSuanming Mou 	pool->free_list = idx;
285a3cf59f5SSuanming Mou 	/* Mark all entries as available. */
286691b3d3eSSuanming Mou 	trunk->bmp = rte_bitmap_init_with_all_set(data_size, &trunk->data
287691b3d3eSSuanming Mou 		     [RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size)],
288691b3d3eSSuanming Mou 		     bmp_size);
289691b3d3eSSuanming Mou 	MLX5_ASSERT(trunk->bmp);
290a3cf59f5SSuanming Mou 	pool->n_trunk_valid++;
291a3cf59f5SSuanming Mou #ifdef POOL_DEBUG
292a3cf59f5SSuanming Mou 	pool->trunk_new++;
293a3cf59f5SSuanming Mou 	pool->trunk_avail++;
294a3cf59f5SSuanming Mou #endif
295a3cf59f5SSuanming Mou 	return 0;
296a3cf59f5SSuanming Mou }
297a3cf59f5SSuanming Mou 
298a3cf59f5SSuanming Mou void *
299a3cf59f5SSuanming Mou mlx5_ipool_malloc(struct mlx5_indexed_pool *pool, uint32_t *idx)
300a3cf59f5SSuanming Mou {
301a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk *trunk;
302a3cf59f5SSuanming Mou 	uint64_t slab = 0;
303a3cf59f5SSuanming Mou 	uint32_t iidx = 0;
304a3cf59f5SSuanming Mou 	void *p;
305a3cf59f5SSuanming Mou 
306a3cf59f5SSuanming Mou 	mlx5_ipool_lock(pool);
307a3cf59f5SSuanming Mou 	if (pool->free_list == TRUNK_INVALID) {
308a3cf59f5SSuanming Mou 		/* If no available trunks, grow new. */
309a3cf59f5SSuanming Mou 		if (mlx5_ipool_grow(pool)) {
310a3cf59f5SSuanming Mou 			mlx5_ipool_unlock(pool);
311a3cf59f5SSuanming Mou 			return NULL;
312a3cf59f5SSuanming Mou 		}
313a3cf59f5SSuanming Mou 	}
314a3cf59f5SSuanming Mou 	MLX5_ASSERT(pool->free_list != TRUNK_INVALID);
315a3cf59f5SSuanming Mou 	trunk = pool->trunks[pool->free_list];
316a3cf59f5SSuanming Mou 	MLX5_ASSERT(trunk->free);
317a3cf59f5SSuanming Mou 	if (!rte_bitmap_scan(trunk->bmp, &iidx, &slab)) {
318a3cf59f5SSuanming Mou 		mlx5_ipool_unlock(pool);
319a3cf59f5SSuanming Mou 		return NULL;
320a3cf59f5SSuanming Mou 	}
321a3cf59f5SSuanming Mou 	MLX5_ASSERT(slab);
322a3cf59f5SSuanming Mou 	iidx += __builtin_ctzll(slab);
323a3cf59f5SSuanming Mou 	MLX5_ASSERT(iidx != UINT32_MAX);
32462d7d519SSuanming Mou 	MLX5_ASSERT(iidx < mlx5_trunk_size_get(pool, trunk->idx));
325a3cf59f5SSuanming Mou 	rte_bitmap_clear(trunk->bmp, iidx);
326a3cf59f5SSuanming Mou 	p = &trunk->data[iidx * pool->cfg.size];
32762d7d519SSuanming Mou 	iidx += mlx5_trunk_idx_offset_get(pool, trunk->idx);
328a3cf59f5SSuanming Mou 	iidx += 1; /* non-zero index. */
329a3cf59f5SSuanming Mou 	trunk->free--;
330a3cf59f5SSuanming Mou #ifdef POOL_DEBUG
331a3cf59f5SSuanming Mou 	pool->n_entry++;
332a3cf59f5SSuanming Mou #endif
333a3cf59f5SSuanming Mou 	if (!trunk->free) {
334a3cf59f5SSuanming Mou 		/* Full trunk will be removed from free list in imalloc. */
335a3cf59f5SSuanming Mou 		MLX5_ASSERT(pool->free_list == trunk->idx);
336a3cf59f5SSuanming Mou 		pool->free_list = trunk->next;
337a3cf59f5SSuanming Mou 		if (trunk->next != TRUNK_INVALID)
338a3cf59f5SSuanming Mou 			pool->trunks[trunk->next]->prev = TRUNK_INVALID;
339a3cf59f5SSuanming Mou 		trunk->prev = TRUNK_INVALID;
340a3cf59f5SSuanming Mou 		trunk->next = TRUNK_INVALID;
341a3cf59f5SSuanming Mou #ifdef POOL_DEBUG
342a3cf59f5SSuanming Mou 		pool->trunk_empty++;
343a3cf59f5SSuanming Mou 		pool->trunk_avail--;
344a3cf59f5SSuanming Mou #endif
345a3cf59f5SSuanming Mou 	}
346a3cf59f5SSuanming Mou 	*idx = iidx;
347a3cf59f5SSuanming Mou 	mlx5_ipool_unlock(pool);
348a3cf59f5SSuanming Mou 	return p;
349a3cf59f5SSuanming Mou }
350a3cf59f5SSuanming Mou 
351a3cf59f5SSuanming Mou void *
352a3cf59f5SSuanming Mou mlx5_ipool_zmalloc(struct mlx5_indexed_pool *pool, uint32_t *idx)
353a3cf59f5SSuanming Mou {
354a3cf59f5SSuanming Mou 	void *entry = mlx5_ipool_malloc(pool, idx);
355a3cf59f5SSuanming Mou 
356a3cf59f5SSuanming Mou 	if (entry)
357a3cf59f5SSuanming Mou 		memset(entry, 0, pool->cfg.size);
358a3cf59f5SSuanming Mou 	return entry;
359a3cf59f5SSuanming Mou }
360a3cf59f5SSuanming Mou 
361a3cf59f5SSuanming Mou void
362a3cf59f5SSuanming Mou mlx5_ipool_free(struct mlx5_indexed_pool *pool, uint32_t idx)
363a3cf59f5SSuanming Mou {
364a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk *trunk;
365a3cf59f5SSuanming Mou 	uint32_t trunk_idx;
36662d7d519SSuanming Mou 	uint32_t entry_idx;
367a3cf59f5SSuanming Mou 
368a3cf59f5SSuanming Mou 	if (!idx)
369a3cf59f5SSuanming Mou 		return;
370a3cf59f5SSuanming Mou 	idx -= 1;
371a3cf59f5SSuanming Mou 	mlx5_ipool_lock(pool);
37262d7d519SSuanming Mou 	trunk_idx = mlx5_trunk_idx_get(pool, idx);
3731fd4bb67SSuanming Mou 	if ((!pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk_valid) ||
3741fd4bb67SSuanming Mou 	    (pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk))
375a3cf59f5SSuanming Mou 		goto out;
376a3cf59f5SSuanming Mou 	trunk = pool->trunks[trunk_idx];
37762d7d519SSuanming Mou 	if (!trunk)
378a3cf59f5SSuanming Mou 		goto out;
37962d7d519SSuanming Mou 	entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk->idx);
38062d7d519SSuanming Mou 	if (trunk_idx != trunk->idx ||
38162d7d519SSuanming Mou 	    rte_bitmap_get(trunk->bmp, entry_idx))
38262d7d519SSuanming Mou 		goto out;
38362d7d519SSuanming Mou 	rte_bitmap_set(trunk->bmp, entry_idx);
384a3cf59f5SSuanming Mou 	trunk->free++;
3851fd4bb67SSuanming Mou 	if (pool->cfg.release_mem_en && trunk->free == mlx5_trunk_size_get
3861fd4bb67SSuanming Mou 	   (pool, trunk->idx)) {
3871fd4bb67SSuanming Mou 		if (pool->free_list == trunk->idx)
3881fd4bb67SSuanming Mou 			pool->free_list = trunk->next;
3891fd4bb67SSuanming Mou 		if (trunk->next != TRUNK_INVALID)
3901fd4bb67SSuanming Mou 			pool->trunks[trunk->next]->prev = trunk->prev;
3911fd4bb67SSuanming Mou 		if (trunk->prev != TRUNK_INVALID)
3921fd4bb67SSuanming Mou 			pool->trunks[trunk->prev]->next = trunk->next;
3931fd4bb67SSuanming Mou 		pool->cfg.free(trunk);
3941fd4bb67SSuanming Mou 		pool->trunks[trunk_idx] = NULL;
3951fd4bb67SSuanming Mou 		pool->n_trunk_valid--;
3961fd4bb67SSuanming Mou #ifdef POOL_DEBUG
3971fd4bb67SSuanming Mou 		pool->trunk_avail--;
3981fd4bb67SSuanming Mou 		pool->trunk_free++;
3991fd4bb67SSuanming Mou #endif
4001fd4bb67SSuanming Mou 		if (pool->n_trunk_valid == 0) {
4011fd4bb67SSuanming Mou 			pool->cfg.free(pool->trunks);
4021fd4bb67SSuanming Mou 			pool->trunks = NULL;
4031fd4bb67SSuanming Mou 			pool->n_trunk = 0;
4041fd4bb67SSuanming Mou 		}
4051fd4bb67SSuanming Mou 	} else if (trunk->free == 1) {
406a3cf59f5SSuanming Mou 		/* Put into free trunk list head. */
407a3cf59f5SSuanming Mou 		MLX5_ASSERT(pool->free_list != trunk->idx);
408a3cf59f5SSuanming Mou 		trunk->next = pool->free_list;
409a3cf59f5SSuanming Mou 		trunk->prev = TRUNK_INVALID;
410a3cf59f5SSuanming Mou 		if (pool->free_list != TRUNK_INVALID)
411a3cf59f5SSuanming Mou 			pool->trunks[pool->free_list]->prev = trunk->idx;
412a3cf59f5SSuanming Mou 		pool->free_list = trunk->idx;
413a3cf59f5SSuanming Mou #ifdef POOL_DEBUG
414a3cf59f5SSuanming Mou 		pool->trunk_empty--;
415a3cf59f5SSuanming Mou 		pool->trunk_avail++;
416a3cf59f5SSuanming Mou #endif
417a3cf59f5SSuanming Mou 	}
418a3cf59f5SSuanming Mou #ifdef POOL_DEBUG
419a3cf59f5SSuanming Mou 	pool->n_entry--;
420a3cf59f5SSuanming Mou #endif
421a3cf59f5SSuanming Mou out:
422a3cf59f5SSuanming Mou 	mlx5_ipool_unlock(pool);
423a3cf59f5SSuanming Mou }
424a3cf59f5SSuanming Mou 
425a3cf59f5SSuanming Mou void *
426a3cf59f5SSuanming Mou mlx5_ipool_get(struct mlx5_indexed_pool *pool, uint32_t idx)
427a3cf59f5SSuanming Mou {
428a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk *trunk;
429a3cf59f5SSuanming Mou 	void *p = NULL;
430a3cf59f5SSuanming Mou 	uint32_t trunk_idx;
43162d7d519SSuanming Mou 	uint32_t entry_idx;
432a3cf59f5SSuanming Mou 
433a3cf59f5SSuanming Mou 	if (!idx)
434a3cf59f5SSuanming Mou 		return NULL;
435a3cf59f5SSuanming Mou 	idx -= 1;
436a3cf59f5SSuanming Mou 	mlx5_ipool_lock(pool);
43762d7d519SSuanming Mou 	trunk_idx = mlx5_trunk_idx_get(pool, idx);
4381fd4bb67SSuanming Mou 	if ((!pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk_valid) ||
4391fd4bb67SSuanming Mou 	    (pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk))
440a3cf59f5SSuanming Mou 		goto out;
441a3cf59f5SSuanming Mou 	trunk = pool->trunks[trunk_idx];
44262d7d519SSuanming Mou 	if (!trunk)
443a3cf59f5SSuanming Mou 		goto out;
44462d7d519SSuanming Mou 	entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk->idx);
44562d7d519SSuanming Mou 	if (trunk_idx != trunk->idx ||
44662d7d519SSuanming Mou 	    rte_bitmap_get(trunk->bmp, entry_idx))
44762d7d519SSuanming Mou 		goto out;
44862d7d519SSuanming Mou 	p = &trunk->data[entry_idx * pool->cfg.size];
449a3cf59f5SSuanming Mou out:
450a3cf59f5SSuanming Mou 	mlx5_ipool_unlock(pool);
451a3cf59f5SSuanming Mou 	return p;
452a3cf59f5SSuanming Mou }
453a3cf59f5SSuanming Mou 
454a3cf59f5SSuanming Mou int
455a3cf59f5SSuanming Mou mlx5_ipool_destroy(struct mlx5_indexed_pool *pool)
456a3cf59f5SSuanming Mou {
457a3cf59f5SSuanming Mou 	struct mlx5_indexed_trunk **trunks;
458a3cf59f5SSuanming Mou 	uint32_t i;
459a3cf59f5SSuanming Mou 
460a3cf59f5SSuanming Mou 	MLX5_ASSERT(pool);
461a3cf59f5SSuanming Mou 	mlx5_ipool_lock(pool);
462a3cf59f5SSuanming Mou 	trunks = pool->trunks;
463a3cf59f5SSuanming Mou 	for (i = 0; i < pool->n_trunk; i++) {
464a3cf59f5SSuanming Mou 		if (trunks[i])
465a3cf59f5SSuanming Mou 			pool->cfg.free(trunks[i]);
466a3cf59f5SSuanming Mou 	}
467a3cf59f5SSuanming Mou 	if (!pool->trunks)
468a3cf59f5SSuanming Mou 		pool->cfg.free(pool->trunks);
469a3cf59f5SSuanming Mou 	mlx5_ipool_unlock(pool);
470*83c2047cSSuanming Mou 	mlx5_free(pool);
471a3cf59f5SSuanming Mou 	return 0;
472a3cf59f5SSuanming Mou }
473a3cf59f5SSuanming Mou 
474a3cf59f5SSuanming Mou void
475a3cf59f5SSuanming Mou mlx5_ipool_dump(struct mlx5_indexed_pool *pool)
476a3cf59f5SSuanming Mou {
477a3cf59f5SSuanming Mou 	printf("Pool %s entry size %u, trunks %u, %d entry per trunk, "
478a3cf59f5SSuanming Mou 	       "total: %d\n",
479a3cf59f5SSuanming Mou 	       pool->cfg.type, pool->cfg.size, pool->n_trunk_valid,
480a3cf59f5SSuanming Mou 	       pool->cfg.trunk_size, pool->n_trunk_valid);
481a3cf59f5SSuanming Mou #ifdef POOL_DEBUG
482a3cf59f5SSuanming Mou 	printf("Pool %s entry %u, trunk alloc %u, empty: %u, "
483a3cf59f5SSuanming Mou 	       "available %u free %u\n",
484a3cf59f5SSuanming Mou 	       pool->cfg.type, pool->n_entry, pool->trunk_new,
485a3cf59f5SSuanming Mou 	       pool->trunk_empty, pool->trunk_avail, pool->trunk_free);
486a3cf59f5SSuanming Mou #endif
487a3cf59f5SSuanming Mou }
488bd81eaebSSuanming Mou 
489bd81eaebSSuanming Mou struct mlx5_l3t_tbl *
490bd81eaebSSuanming Mou mlx5_l3t_create(enum mlx5_l3t_type type)
491bd81eaebSSuanming Mou {
492bd81eaebSSuanming Mou 	struct mlx5_l3t_tbl *tbl;
493bd81eaebSSuanming Mou 	struct mlx5_indexed_pool_config l3t_ip_cfg = {
494bd81eaebSSuanming Mou 		.trunk_size = 16,
495bd81eaebSSuanming Mou 		.grow_trunk = 6,
496bd81eaebSSuanming Mou 		.grow_shift = 1,
497bd81eaebSSuanming Mou 		.need_lock = 0,
498bd81eaebSSuanming Mou 		.release_mem_en = 1,
499*83c2047cSSuanming Mou 		.malloc = mlx5_malloc,
500*83c2047cSSuanming Mou 		.free = mlx5_free,
501bd81eaebSSuanming Mou 	};
502bd81eaebSSuanming Mou 
503bd81eaebSSuanming Mou 	if (type >= MLX5_L3T_TYPE_MAX) {
504bd81eaebSSuanming Mou 		rte_errno = EINVAL;
505bd81eaebSSuanming Mou 		return NULL;
506bd81eaebSSuanming Mou 	}
507*83c2047cSSuanming Mou 	tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_l3t_tbl), 1,
508*83c2047cSSuanming Mou 			  SOCKET_ID_ANY);
509bd81eaebSSuanming Mou 	if (!tbl) {
510bd81eaebSSuanming Mou 		rte_errno = ENOMEM;
511bd81eaebSSuanming Mou 		return NULL;
512bd81eaebSSuanming Mou 	}
513bd81eaebSSuanming Mou 	tbl->type = type;
514bd81eaebSSuanming Mou 	switch (type) {
515bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_WORD:
516bd81eaebSSuanming Mou 		l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_word) +
517bd81eaebSSuanming Mou 				  sizeof(uint16_t) * MLX5_L3T_ET_SIZE;
518bd81eaebSSuanming Mou 		l3t_ip_cfg.type = "mlx5_l3t_e_tbl_w";
519bd81eaebSSuanming Mou 		break;
520bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_DWORD:
521bd81eaebSSuanming Mou 		l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_dword) +
522bd81eaebSSuanming Mou 				  sizeof(uint32_t) * MLX5_L3T_ET_SIZE;
523bd81eaebSSuanming Mou 		l3t_ip_cfg.type = "mlx5_l3t_e_tbl_dw";
524bd81eaebSSuanming Mou 		break;
525bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_QWORD:
526bd81eaebSSuanming Mou 		l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_qword) +
527bd81eaebSSuanming Mou 				  sizeof(uint64_t) * MLX5_L3T_ET_SIZE;
528bd81eaebSSuanming Mou 		l3t_ip_cfg.type = "mlx5_l3t_e_tbl_qw";
529bd81eaebSSuanming Mou 		break;
530bd81eaebSSuanming Mou 	default:
531bd81eaebSSuanming Mou 		l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_ptr) +
532bd81eaebSSuanming Mou 				  sizeof(void *) * MLX5_L3T_ET_SIZE;
533bd81eaebSSuanming Mou 		l3t_ip_cfg.type = "mlx5_l3t_e_tbl_tpr";
534bd81eaebSSuanming Mou 		break;
535bd81eaebSSuanming Mou 	}
536bd81eaebSSuanming Mou 	tbl->eip = mlx5_ipool_create(&l3t_ip_cfg);
537bd81eaebSSuanming Mou 	if (!tbl->eip) {
538bd81eaebSSuanming Mou 		rte_errno = ENOMEM;
539*83c2047cSSuanming Mou 		mlx5_free(tbl);
540bd81eaebSSuanming Mou 		tbl = NULL;
541bd81eaebSSuanming Mou 	}
542bd81eaebSSuanming Mou 	return tbl;
543bd81eaebSSuanming Mou }
544bd81eaebSSuanming Mou 
545bd81eaebSSuanming Mou void
546bd81eaebSSuanming Mou mlx5_l3t_destroy(struct mlx5_l3t_tbl *tbl)
547bd81eaebSSuanming Mou {
548bd81eaebSSuanming Mou 	struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
549bd81eaebSSuanming Mou 	uint32_t i, j;
550bd81eaebSSuanming Mou 
551bd81eaebSSuanming Mou 	if (!tbl)
552bd81eaebSSuanming Mou 		return;
553bd81eaebSSuanming Mou 	g_tbl = tbl->tbl;
554bd81eaebSSuanming Mou 	if (g_tbl) {
555bd81eaebSSuanming Mou 		for (i = 0; i < MLX5_L3T_GT_SIZE; i++) {
556bd81eaebSSuanming Mou 			m_tbl = g_tbl->tbl[i];
557bd81eaebSSuanming Mou 			if (!m_tbl)
558bd81eaebSSuanming Mou 				continue;
559bd81eaebSSuanming Mou 			for (j = 0; j < MLX5_L3T_MT_SIZE; j++) {
560bd81eaebSSuanming Mou 				if (!m_tbl->tbl[j])
561bd81eaebSSuanming Mou 					continue;
562bd81eaebSSuanming Mou 				MLX5_ASSERT(!((struct mlx5_l3t_entry_word *)
563bd81eaebSSuanming Mou 					    m_tbl->tbl[j])->ref_cnt);
564bd81eaebSSuanming Mou 				mlx5_ipool_free(tbl->eip,
565bd81eaebSSuanming Mou 						((struct mlx5_l3t_entry_word *)
566bd81eaebSSuanming Mou 						m_tbl->tbl[j])->idx);
567bd81eaebSSuanming Mou 				m_tbl->tbl[j] = 0;
568bd81eaebSSuanming Mou 				if (!(--m_tbl->ref_cnt))
569bd81eaebSSuanming Mou 					break;
570bd81eaebSSuanming Mou 			}
571bd81eaebSSuanming Mou 			MLX5_ASSERT(!m_tbl->ref_cnt);
572*83c2047cSSuanming Mou 			mlx5_free(g_tbl->tbl[i]);
573bd81eaebSSuanming Mou 			g_tbl->tbl[i] = 0;
574bd81eaebSSuanming Mou 			if (!(--g_tbl->ref_cnt))
575bd81eaebSSuanming Mou 				break;
576bd81eaebSSuanming Mou 		}
577bd81eaebSSuanming Mou 		MLX5_ASSERT(!g_tbl->ref_cnt);
578*83c2047cSSuanming Mou 		mlx5_free(tbl->tbl);
579bd81eaebSSuanming Mou 		tbl->tbl = 0;
580bd81eaebSSuanming Mou 	}
581bd81eaebSSuanming Mou 	mlx5_ipool_destroy(tbl->eip);
582*83c2047cSSuanming Mou 	mlx5_free(tbl);
583bd81eaebSSuanming Mou }
584bd81eaebSSuanming Mou 
585bd81eaebSSuanming Mou uint32_t
586bd81eaebSSuanming Mou mlx5_l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
587bd81eaebSSuanming Mou 		   union mlx5_l3t_data *data)
588bd81eaebSSuanming Mou {
589bd81eaebSSuanming Mou 	struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
590bd81eaebSSuanming Mou 	void *e_tbl;
591bd81eaebSSuanming Mou 	uint32_t entry_idx;
592bd81eaebSSuanming Mou 
593bd81eaebSSuanming Mou 	g_tbl = tbl->tbl;
594bd81eaebSSuanming Mou 	if (!g_tbl)
595bd81eaebSSuanming Mou 		return -1;
596bd81eaebSSuanming Mou 	m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
597bd81eaebSSuanming Mou 	if (!m_tbl)
598bd81eaebSSuanming Mou 		return -1;
599bd81eaebSSuanming Mou 	e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
600bd81eaebSSuanming Mou 	if (!e_tbl)
601bd81eaebSSuanming Mou 		return -1;
602bd81eaebSSuanming Mou 	entry_idx = idx & MLX5_L3T_ET_MASK;
603bd81eaebSSuanming Mou 	switch (tbl->type) {
604bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_WORD:
605bd81eaebSSuanming Mou 		data->word = ((struct mlx5_l3t_entry_word *)e_tbl)->entry
606bd81eaebSSuanming Mou 			     [entry_idx];
607bd81eaebSSuanming Mou 		break;
608bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_DWORD:
609bd81eaebSSuanming Mou 		data->dword = ((struct mlx5_l3t_entry_dword *)e_tbl)->entry
610bd81eaebSSuanming Mou 			     [entry_idx];
611bd81eaebSSuanming Mou 		break;
612bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_QWORD:
613bd81eaebSSuanming Mou 		data->qword = ((struct mlx5_l3t_entry_qword *)e_tbl)->entry
614bd81eaebSSuanming Mou 			      [entry_idx];
615bd81eaebSSuanming Mou 		break;
616bd81eaebSSuanming Mou 	default:
617bd81eaebSSuanming Mou 		data->ptr = ((struct mlx5_l3t_entry_ptr *)e_tbl)->entry
618bd81eaebSSuanming Mou 			    [entry_idx];
619bd81eaebSSuanming Mou 		break;
620bd81eaebSSuanming Mou 	}
621bd81eaebSSuanming Mou 	return 0;
622bd81eaebSSuanming Mou }
623bd81eaebSSuanming Mou 
624bd81eaebSSuanming Mou void
625bd81eaebSSuanming Mou mlx5_l3t_clear_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx)
626bd81eaebSSuanming Mou {
627bd81eaebSSuanming Mou 	struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
628bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_word *w_e_tbl;
629bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_dword *dw_e_tbl;
630bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_qword *qw_e_tbl;
631bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_ptr *ptr_e_tbl;
632bd81eaebSSuanming Mou 	void *e_tbl;
633bd81eaebSSuanming Mou 	uint32_t entry_idx;
634bd81eaebSSuanming Mou 	uint64_t ref_cnt;
635bd81eaebSSuanming Mou 
636bd81eaebSSuanming Mou 	g_tbl = tbl->tbl;
637bd81eaebSSuanming Mou 	if (!g_tbl)
638bd81eaebSSuanming Mou 		return;
639bd81eaebSSuanming Mou 	m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
640bd81eaebSSuanming Mou 	if (!m_tbl)
641bd81eaebSSuanming Mou 		return;
642bd81eaebSSuanming Mou 	e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
643bd81eaebSSuanming Mou 	if (!e_tbl)
644bd81eaebSSuanming Mou 		return;
645bd81eaebSSuanming Mou 	entry_idx = idx & MLX5_L3T_ET_MASK;
646bd81eaebSSuanming Mou 	switch (tbl->type) {
647bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_WORD:
648bd81eaebSSuanming Mou 		w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
649bd81eaebSSuanming Mou 		w_e_tbl->entry[entry_idx] = 0;
650bd81eaebSSuanming Mou 		ref_cnt = --w_e_tbl->ref_cnt;
651bd81eaebSSuanming Mou 		break;
652bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_DWORD:
653bd81eaebSSuanming Mou 		dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
654bd81eaebSSuanming Mou 		dw_e_tbl->entry[entry_idx] = 0;
655bd81eaebSSuanming Mou 		ref_cnt = --dw_e_tbl->ref_cnt;
656bd81eaebSSuanming Mou 		break;
657bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_QWORD:
658bd81eaebSSuanming Mou 		qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
659bd81eaebSSuanming Mou 		qw_e_tbl->entry[entry_idx] = 0;
660bd81eaebSSuanming Mou 		ref_cnt = --qw_e_tbl->ref_cnt;
661bd81eaebSSuanming Mou 		break;
662bd81eaebSSuanming Mou 	default:
663bd81eaebSSuanming Mou 		ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
664bd81eaebSSuanming Mou 		ptr_e_tbl->entry[entry_idx] = NULL;
665bd81eaebSSuanming Mou 		ref_cnt = --ptr_e_tbl->ref_cnt;
666bd81eaebSSuanming Mou 		break;
667bd81eaebSSuanming Mou 	}
668bd81eaebSSuanming Mou 	if (!ref_cnt) {
669bd81eaebSSuanming Mou 		mlx5_ipool_free(tbl->eip,
670bd81eaebSSuanming Mou 				((struct mlx5_l3t_entry_word *)e_tbl)->idx);
671bd81eaebSSuanming Mou 		m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK] =
672bd81eaebSSuanming Mou 									NULL;
673bd81eaebSSuanming Mou 		if (!(--m_tbl->ref_cnt)) {
674*83c2047cSSuanming Mou 			mlx5_free(m_tbl);
675bd81eaebSSuanming Mou 			g_tbl->tbl
676bd81eaebSSuanming Mou 			[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK] = NULL;
677bd81eaebSSuanming Mou 			if (!(--g_tbl->ref_cnt)) {
678*83c2047cSSuanming Mou 				mlx5_free(g_tbl);
679bd81eaebSSuanming Mou 				tbl->tbl = 0;
680bd81eaebSSuanming Mou 			}
681bd81eaebSSuanming Mou 		}
682bd81eaebSSuanming Mou 	}
683bd81eaebSSuanming Mou }
684bd81eaebSSuanming Mou 
685bd81eaebSSuanming Mou uint32_t
686bd81eaebSSuanming Mou mlx5_l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
687bd81eaebSSuanming Mou 		   union mlx5_l3t_data *data)
688bd81eaebSSuanming Mou {
689bd81eaebSSuanming Mou 	struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
690bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_word *w_e_tbl;
691bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_dword *dw_e_tbl;
692bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_qword *qw_e_tbl;
693bd81eaebSSuanming Mou 	struct mlx5_l3t_entry_ptr *ptr_e_tbl;
694bd81eaebSSuanming Mou 	void *e_tbl;
695bd81eaebSSuanming Mou 	uint32_t entry_idx, tbl_idx = 0;
696bd81eaebSSuanming Mou 
697bd81eaebSSuanming Mou 	/* Check the global table, create it if empty. */
698bd81eaebSSuanming Mou 	g_tbl = tbl->tbl;
699bd81eaebSSuanming Mou 	if (!g_tbl) {
700*83c2047cSSuanming Mou 		g_tbl = mlx5_malloc(MLX5_MEM_ZERO,
701*83c2047cSSuanming Mou 				    sizeof(struct mlx5_l3t_level_tbl) +
702*83c2047cSSuanming Mou 				    sizeof(void *) * MLX5_L3T_GT_SIZE, 1,
703*83c2047cSSuanming Mou 				    SOCKET_ID_ANY);
704bd81eaebSSuanming Mou 		if (!g_tbl) {
705bd81eaebSSuanming Mou 			rte_errno = ENOMEM;
706bd81eaebSSuanming Mou 			return -1;
707bd81eaebSSuanming Mou 		}
708bd81eaebSSuanming Mou 		tbl->tbl = g_tbl;
709bd81eaebSSuanming Mou 	}
710bd81eaebSSuanming Mou 	/*
711bd81eaebSSuanming Mou 	 * Check the middle table, create it if empty. Ref_cnt will be
712bd81eaebSSuanming Mou 	 * increased if new sub table created.
713bd81eaebSSuanming Mou 	 */
714bd81eaebSSuanming Mou 	m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
715bd81eaebSSuanming Mou 	if (!m_tbl) {
716*83c2047cSSuanming Mou 		m_tbl = mlx5_malloc(MLX5_MEM_ZERO,
717*83c2047cSSuanming Mou 				    sizeof(struct mlx5_l3t_level_tbl) +
718*83c2047cSSuanming Mou 				    sizeof(void *) * MLX5_L3T_MT_SIZE, 1,
719*83c2047cSSuanming Mou 				    SOCKET_ID_ANY);
720bd81eaebSSuanming Mou 		if (!m_tbl) {
721bd81eaebSSuanming Mou 			rte_errno = ENOMEM;
722bd81eaebSSuanming Mou 			return -1;
723bd81eaebSSuanming Mou 		}
724bd81eaebSSuanming Mou 		g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK] =
725bd81eaebSSuanming Mou 									m_tbl;
726bd81eaebSSuanming Mou 		g_tbl->ref_cnt++;
727bd81eaebSSuanming Mou 	}
728bd81eaebSSuanming Mou 	/*
729bd81eaebSSuanming Mou 	 * Check the entry table, create it if empty. Ref_cnt will be
730bd81eaebSSuanming Mou 	 * increased if new sub entry table created.
731bd81eaebSSuanming Mou 	 */
732bd81eaebSSuanming Mou 	e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
733bd81eaebSSuanming Mou 	if (!e_tbl) {
734bd81eaebSSuanming Mou 		e_tbl = mlx5_ipool_zmalloc(tbl->eip, &tbl_idx);
735bd81eaebSSuanming Mou 		if (!e_tbl) {
736bd81eaebSSuanming Mou 			rte_errno = ENOMEM;
737bd81eaebSSuanming Mou 			return -1;
738bd81eaebSSuanming Mou 		}
739bd81eaebSSuanming Mou 		((struct mlx5_l3t_entry_word *)e_tbl)->idx = tbl_idx;
740bd81eaebSSuanming Mou 		m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK] =
741bd81eaebSSuanming Mou 									e_tbl;
742bd81eaebSSuanming Mou 		m_tbl->ref_cnt++;
743bd81eaebSSuanming Mou 	}
744bd81eaebSSuanming Mou 	entry_idx = idx & MLX5_L3T_ET_MASK;
745bd81eaebSSuanming Mou 	switch (tbl->type) {
746bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_WORD:
747bd81eaebSSuanming Mou 		w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
748bd81eaebSSuanming Mou 		w_e_tbl->entry[entry_idx] = data->word;
749bd81eaebSSuanming Mou 		w_e_tbl->ref_cnt++;
750bd81eaebSSuanming Mou 		break;
751bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_DWORD:
752bd81eaebSSuanming Mou 		dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
753bd81eaebSSuanming Mou 		dw_e_tbl->entry[entry_idx] = data->dword;
754bd81eaebSSuanming Mou 		dw_e_tbl->ref_cnt++;
755bd81eaebSSuanming Mou 		break;
756bd81eaebSSuanming Mou 	case MLX5_L3T_TYPE_QWORD:
757bd81eaebSSuanming Mou 		qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
758bd81eaebSSuanming Mou 		qw_e_tbl->entry[entry_idx] = data->qword;
759bd81eaebSSuanming Mou 		qw_e_tbl->ref_cnt++;
760bd81eaebSSuanming Mou 		break;
761bd81eaebSSuanming Mou 	default:
762bd81eaebSSuanming Mou 		ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
763bd81eaebSSuanming Mou 		ptr_e_tbl->entry[entry_idx] = data->ptr;
764bd81eaebSSuanming Mou 		ptr_e_tbl->ref_cnt++;
765bd81eaebSSuanming Mou 		break;
766bd81eaebSSuanming Mou 	}
767bd81eaebSSuanming Mou 	return 0;
768bd81eaebSSuanming Mou }
769