Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2019 Mellanox Technologies, Ltd
3 : : */
4 : :
5 : : #include <rte_malloc.h>
6 : :
7 : : #include <mlx5_malloc.h>
8 : :
9 : : #include "mlx5_utils.h"
10 : :
11 : : /********************* Indexed pool **********************/
12 : :
13 : : #if defined(RTE_TOOLCHAIN_GCC) || defined(RTE_TOOLCHAIN_CLANG)
14 : : #define pool_malloc(pool, flags, size, align, socket) (__extension__ ({ \
15 : : struct mlx5_indexed_pool *p = (struct mlx5_indexed_pool *)(pool); \
16 : : uint32_t f = (uint32_t)(flags); \
17 : : size_t s = (size_t)(size); \
18 : : uint32_t a = (uint32_t)(align); \
19 : : int so = (int)(socket); \
20 : : void *mem = p->cfg.malloc(f, s, a, so); \
21 : : if (mem == NULL && so != SOCKET_ID_ANY) { \
22 : : mem = p->cfg.malloc(f, s, a, SOCKET_ID_ANY); \
23 : : if (mem) { \
24 : : DRV_LOG(WARNING, \
25 : : "Allocated %p (size %zu socket %d) through NUMA tolerant fallback", \
26 : : mem, s, so); \
27 : : } \
28 : : } \
29 : : mem; \
30 : : }))
31 : : #else
32 : : #define pool_malloc(pool, flags, size, align, socket) \
33 : : ((pool)->cfg.malloc((uint32_t)(flags) | MLX5_NUMA_TOLERANT, (size), (align), (socket)))
34 : : #endif
35 : :
36 : : int mlx5_logtype_ipool;
37 : :
38 : : /* Initialize driver log type. */
39 [ - + ]: 253 : RTE_LOG_REGISTER_SUFFIX(mlx5_logtype_ipool, ipool, NOTICE)
40 : :
41 : : static inline void
42 : : mlx5_ipool_lock(struct mlx5_indexed_pool *pool)
43 : : {
44 [ # # # # : 0 : if (pool->cfg.need_lock)
# # ]
45 : 0 : rte_spinlock_lock(&pool->rsz_lock);
46 : : }
47 : :
48 : : static inline void
49 : : mlx5_ipool_unlock(struct mlx5_indexed_pool *pool)
50 : : {
51 [ # # # # : 0 : if (pool->cfg.need_lock)
# # # # #
# ]
52 : 0 : rte_spinlock_unlock(&pool->rsz_lock);
53 : : }
54 : :
55 : : static inline uint32_t
56 : 0 : mlx5_trunk_idx_get(struct mlx5_indexed_pool *pool, uint32_t entry_idx)
57 : : {
58 : : struct mlx5_indexed_pool_config *cfg = &pool->cfg;
59 : : uint32_t trunk_idx = 0;
60 : : uint32_t i;
61 : :
62 [ # # ]: 0 : if (!cfg->grow_trunk)
63 : 0 : return entry_idx / cfg->trunk_size;
64 [ # # ]: 0 : if (entry_idx >= pool->grow_tbl[cfg->grow_trunk - 1]) {
65 : 0 : trunk_idx = (entry_idx - pool->grow_tbl[cfg->grow_trunk - 1]) /
66 : 0 : (cfg->trunk_size << (cfg->grow_shift *
67 : 0 : cfg->grow_trunk)) + cfg->grow_trunk;
68 : : } else {
69 [ # # ]: 0 : for (i = 0; i < cfg->grow_trunk; i++) {
70 [ # # ]: 0 : if (entry_idx < pool->grow_tbl[i])
71 : : break;
72 : : }
73 : : trunk_idx = i;
74 : : }
75 : : return trunk_idx;
76 : : }
77 : :
78 : : static inline uint32_t
79 : : mlx5_trunk_size_get(struct mlx5_indexed_pool *pool, uint32_t trunk_idx)
80 : : {
81 : : struct mlx5_indexed_pool_config *cfg = &pool->cfg;
82 : :
83 : 0 : return cfg->trunk_size << (cfg->grow_shift *
84 : 0 : (trunk_idx > cfg->grow_trunk ? cfg->grow_trunk : trunk_idx));
85 : : }
86 : :
87 : : static inline uint32_t
88 : 0 : mlx5_trunk_idx_offset_get(struct mlx5_indexed_pool *pool, uint32_t trunk_idx)
89 : : {
90 : : struct mlx5_indexed_pool_config *cfg = &pool->cfg;
91 : : uint32_t offset = 0;
92 : :
93 [ # # ]: 0 : if (!trunk_idx)
94 : : return 0;
95 [ # # # # : 0 : if (!cfg->grow_trunk)
# # ]
96 : 0 : return cfg->trunk_size * trunk_idx;
97 [ # # ]: 0 : if (trunk_idx < cfg->grow_trunk)
98 : 0 : offset = pool->grow_tbl[trunk_idx - 1];
99 : : else
100 : 0 : offset = pool->grow_tbl[cfg->grow_trunk - 1] +
101 : 0 : (cfg->trunk_size << (cfg->grow_shift *
102 : 0 : cfg->grow_trunk)) * (trunk_idx - cfg->grow_trunk);
103 : : return offset;
104 : : }
105 : :
106 : : struct mlx5_indexed_pool *
107 : 0 : mlx5_ipool_create(struct mlx5_indexed_pool_config *cfg)
108 : : {
109 : : struct mlx5_indexed_pool *pool;
110 : : uint32_t i;
111 : :
112 [ # # # # ]: 0 : if (!cfg || (!cfg->malloc ^ !cfg->free) ||
113 [ # # # # ]: 0 : (cfg->per_core_cache && cfg->release_mem_en) ||
114 [ # # # # ]: 0 : (cfg->trunk_size && ((cfg->trunk_size & (cfg->trunk_size - 1)) ||
115 [ # # ]: 0 : ((rte_ffs32(cfg->trunk_size) + TRUNK_IDX_BITS) > 32))))
116 : : return NULL;
117 : 0 : pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool) + cfg->grow_trunk *
118 : : sizeof(pool->grow_tbl[0]), RTE_CACHE_LINE_SIZE,
119 : : SOCKET_ID_ANY);
120 [ # # ]: 0 : if (!pool)
121 : : return NULL;
122 : 0 : pool->cfg = *cfg;
123 [ # # ]: 0 : if (!pool->cfg.trunk_size)
124 : 0 : pool->cfg.trunk_size = MLX5_IPOOL_DEFAULT_TRUNK_SIZE;
125 [ # # # # ]: 0 : if (!cfg->malloc && !cfg->free) {
126 : 0 : pool->cfg.malloc = mlx5_malloc;
127 : 0 : pool->cfg.free = mlx5_free;
128 : : }
129 [ # # ]: 0 : if (pool->cfg.need_lock)
130 : : rte_spinlock_init(&pool->rsz_lock);
131 : : /*
132 : : * Initialize the dynamic grow trunk size lookup table to have a quick
133 : : * lookup for the trunk entry index offset.
134 : : */
135 [ # # ]: 0 : for (i = 0; i < cfg->grow_trunk; i++) {
136 : 0 : pool->grow_tbl[i] = cfg->trunk_size << (cfg->grow_shift * i);
137 [ # # ]: 0 : if (i > 0)
138 : 0 : pool->grow_tbl[i] += pool->grow_tbl[i - 1];
139 : : }
140 [ # # ]: 0 : if (!pool->cfg.max_idx)
141 : 0 : pool->cfg.max_idx =
142 : : mlx5_trunk_idx_offset_get(pool, TRUNK_MAX_IDX + 1);
143 [ # # ]: 0 : if (!cfg->per_core_cache)
144 : 0 : pool->free_list = TRUNK_INVALID;
145 : : rte_spinlock_init(&pool->lcore_lock);
146 : :
147 : : #ifdef POOL_DEBUG
148 : : rte_spinlock_init(&pool->cache_validator.lock);
149 : : #endif
150 [ # # ]: 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: per core cache mode %s",
151 : : rte_lcore_id(), pool->cfg.type, pool->cfg.per_core_cache != 0 ? "on" : "off");
152 : 0 : return pool;
153 : : }
154 : :
155 : : static int
156 : 0 : mlx5_ipool_grow(struct mlx5_indexed_pool *pool)
157 : : {
158 : : struct mlx5_indexed_trunk *trunk;
159 : : struct mlx5_indexed_trunk **trunk_tmp;
160 : : struct mlx5_indexed_trunk **p;
161 : : size_t trunk_size = 0;
162 : : size_t data_size;
163 : : size_t bmp_size;
164 : : uint32_t idx, cur_max_idx, i;
165 : :
166 : 0 : cur_max_idx = mlx5_trunk_idx_offset_get(pool, pool->n_trunk_valid);
167 [ # # ]: 0 : if (pool->n_trunk_valid == TRUNK_MAX_IDX ||
168 [ # # ]: 0 : cur_max_idx >= pool->cfg.max_idx)
169 : : return -ENOMEM;
170 [ # # ]: 0 : if (pool->n_trunk_valid == pool->n_trunk) {
171 : : /* No free trunk flags, expand trunk list. */
172 [ # # ]: 0 : int n_grow = pool->n_trunk_valid ? pool->n_trunk :
173 : : RTE_CACHE_LINE_SIZE / sizeof(void *);
174 : :
175 [ # # # # ]: 0 : p = pool_malloc(pool, MLX5_MEM_ZERO, (pool->n_trunk_valid + n_grow) *
176 : : sizeof(struct mlx5_indexed_trunk *),
177 : : RTE_CACHE_LINE_SIZE, rte_socket_id());
178 [ # # ]: 0 : if (!p)
179 : : return -ENOMEM;
180 [ # # ]: 0 : if (pool->trunks)
181 : 0 : memcpy(p, pool->trunks, pool->n_trunk_valid *
182 : : sizeof(struct mlx5_indexed_trunk *));
183 [ # # ]: 0 : memset(RTE_PTR_ADD(p, pool->n_trunk_valid * sizeof(void *)), 0,
184 : : n_grow * sizeof(void *));
185 : 0 : trunk_tmp = pool->trunks;
186 : 0 : pool->trunks = p;
187 [ # # ]: 0 : if (trunk_tmp)
188 : 0 : pool->cfg.free(trunk_tmp);
189 : 0 : pool->n_trunk += n_grow;
190 : : }
191 [ # # ]: 0 : if (!pool->cfg.release_mem_en) {
192 : 0 : idx = pool->n_trunk_valid;
193 : : } else {
194 : : /* Find the first available slot in trunk list */
195 [ # # ]: 0 : for (idx = 0; idx < pool->n_trunk; idx++)
196 [ # # ]: 0 : if (pool->trunks[idx] == NULL)
197 : : break;
198 : : }
199 : : trunk_size += sizeof(*trunk);
200 : 0 : data_size = mlx5_trunk_size_get(pool, idx);
201 : 0 : bmp_size = rte_bitmap_get_memory_footprint(data_size);
202 : : /* rte_bitmap requires memory cacheline aligned. */
203 : 0 : trunk_size += RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size);
204 : 0 : trunk_size += bmp_size;
205 [ # # # # ]: 0 : trunk = pool_malloc(pool, MLX5_MEM_ZERO, trunk_size,
206 : : RTE_CACHE_LINE_SIZE, rte_socket_id());
207 [ # # ]: 0 : if (!trunk)
208 : : return -ENOMEM;
209 : 0 : pool->trunks[idx] = trunk;
210 : 0 : trunk->idx = idx;
211 : 0 : trunk->free = data_size;
212 : 0 : trunk->prev = TRUNK_INVALID;
213 : 0 : trunk->next = TRUNK_INVALID;
214 : : MLX5_ASSERT(pool->free_list == TRUNK_INVALID);
215 : 0 : pool->free_list = idx;
216 : : /* Mark all entries as available. */
217 : 0 : trunk->bmp = rte_bitmap_init_with_all_set(data_size, &trunk->data
218 : 0 : [RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size)],
219 : : bmp_size);
220 : : /* Clear the overhead bits in the trunk if it happens. */
221 [ # # ]: 0 : if (cur_max_idx + data_size > pool->cfg.max_idx) {
222 [ # # ]: 0 : for (i = pool->cfg.max_idx - cur_max_idx; i < data_size; i++)
223 : 0 : rte_bitmap_clear(trunk->bmp, i);
224 : : }
225 : : MLX5_ASSERT(trunk->bmp);
226 : 0 : pool->n_trunk_valid++;
227 : : #ifdef POOL_DEBUG
228 : : pool->trunk_new++;
229 : : pool->trunk_avail++;
230 : : #endif
231 : 0 : return 0;
232 : : }
233 : :
234 : : static inline struct mlx5_indexed_cache *
235 : 0 : mlx5_ipool_update_global_cache(struct mlx5_indexed_pool *pool, int cidx)
236 : : {
237 : : struct mlx5_indexed_cache *gc, *lc, *olc = NULL;
238 : :
239 : 0 : lc = pool->cache[cidx]->lc;
240 : 0 : gc = rte_atomic_load_explicit(&pool->gc, rte_memory_order_relaxed);
241 [ # # ]: 0 : if (gc && lc != gc) {
242 : : mlx5_ipool_lock(pool);
243 [ # # # # ]: 0 : if (lc && !(--lc->ref_cnt))
244 : : olc = lc;
245 : 0 : lc = pool->gc;
246 : 0 : lc->ref_cnt++;
247 [ # # ]: 0 : pool->cache[cidx]->lc = lc;
248 : : mlx5_ipool_unlock(pool);
249 [ # # ]: 0 : if (olc)
250 : 0 : pool->cfg.free(olc);
251 : 0 : DRV_LOG_IPOOL(DEBUG, "lcore id %d: pool %s: updated lcache %d "
252 : : "ref %d, new %p, old %p", rte_lcore_id(), pool->cfg.type,
253 : : cidx, lc->ref_cnt, (void *)lc, (void *)olc);
254 : : }
255 : 0 : return lc;
256 : : }
257 : :
258 : : #ifdef POOL_DEBUG
259 : : static void
260 : : mlx5_ipool_grow_bmp(struct mlx5_indexed_pool *pool, uint32_t new_size)
261 : : {
262 : : struct rte_bitmap *old_bmp = NULL;
263 : : void *old_bmp_mem = NULL;
264 : : uint32_t old_size = 0;
265 : : uint32_t i, bmp_mem_size;
266 : :
267 : : if (pool->cache_validator.bmp_mem && pool->cache_validator.bmp) {
268 : : old_bmp = pool->cache_validator.bmp;
269 : : old_size = pool->cache_validator.bmp_size;
270 : : old_bmp_mem = pool->cache_validator.bmp_mem;
271 : : }
272 : :
273 : : if (unlikely(new_size <= old_size))
274 : : return;
275 : :
276 : : pool->cache_validator.bmp_size = new_size;
277 : : bmp_mem_size = rte_bitmap_get_memory_footprint(new_size);
278 : :
279 : : pool->cache_validator.bmp_mem = pool_malloc(pool, MLX5_MEM_ZERO,
280 : : bmp_mem_size,
281 : : RTE_CACHE_LINE_SIZE,
282 : : rte_socket_id());
283 : : if (unlikely(!pool->cache_validator.bmp_mem)) {
284 : : DRV_LOG_IPOOL(ERR, "Unable to allocate memory for a new bitmap");
285 : : return;
286 : : }
287 : :
288 : : pool->cache_validator.bmp = rte_bitmap_init_with_all_set(pool->cache_validator.bmp_size,
289 : : pool->cache_validator.bmp_mem,
290 : : bmp_mem_size);
291 : : if (unlikely(!pool->cache_validator.bmp)) {
292 : : DRV_LOG(ERR, "Unable to allocate memory for a new bitmap");
293 : : pool->cfg.free(pool->cache_validator.bmp_mem);
294 : : return;
295 : : }
296 : :
297 : : if (old_bmp && old_bmp_mem) {
298 : : for (i = 0; i < old_size; i++) {
299 : : if (rte_bitmap_get(old_bmp, i) == 0)
300 : : rte_bitmap_clear(pool->cache_validator.bmp, i);
301 : : }
302 : : rte_bitmap_free(old_bmp);
303 : : pool->cfg.free(old_bmp_mem);
304 : : }
305 : : }
306 : : #endif
307 : :
308 : : static uint32_t
309 : 0 : mlx5_ipool_allocate_from_global(struct mlx5_indexed_pool *pool, int cidx)
310 : : {
311 : : struct mlx5_indexed_trunk *trunk;
312 : : struct mlx5_indexed_cache *p, *lc, *olc = NULL;
313 : : size_t trunk_size = 0;
314 : : size_t data_size;
315 : : uint32_t cur_max_idx, trunk_idx, trunk_n;
316 : : uint32_t fetch_size, ts_idx, i;
317 : : int n_grow;
318 : :
319 : 0 : check_again:
320 : : p = NULL;
321 : : fetch_size = 0;
322 : : /*
323 : : * Fetch new index from global if possible. First round local
324 : : * cache will be NULL.
325 : : */
326 [ # # ]: 0 : lc = pool->cache[cidx]->lc;
327 : : mlx5_ipool_lock(pool);
328 : : /* Try to update local cache first. */
329 [ # # ]: 0 : if (likely(pool->gc)) {
330 [ # # ]: 0 : if (lc != pool->gc) {
331 [ # # # # ]: 0 : if (lc && !(--lc->ref_cnt))
332 : : olc = lc;
333 : : lc = pool->gc;
334 : 0 : lc->ref_cnt++;
335 : 0 : pool->cache[cidx]->lc = lc;
336 : : }
337 [ # # ]: 0 : if (lc->len) {
338 : : /* Use the updated local cache to fetch index. */
339 : 0 : fetch_size = pool->cfg.per_core_cache >> 2;
340 : : if (lc->len < fetch_size)
341 : : fetch_size = lc->len;
342 : 0 : lc->len -= fetch_size;
343 : 0 : memcpy(pool->cache[cidx]->idx, &lc->idx[lc->len],
344 : : sizeof(uint32_t) * fetch_size);
345 : : }
346 : : }
347 : : mlx5_ipool_unlock(pool);
348 [ # # ]: 0 : if (unlikely(olc)) {
349 : 0 : pool->cfg.free(olc);
350 : : olc = NULL;
351 : : }
352 [ # # ]: 0 : if (fetch_size) {
353 : 0 : pool->cache[cidx]->len = fetch_size - 1;
354 : 0 : return pool->cache[cidx]->idx[pool->cache[cidx]->len];
355 : : }
356 : 0 : trunk_idx = lc ? rte_atomic_load_explicit(&lc->n_trunk_valid,
357 [ # # ]: 0 : rte_memory_order_acquire) : 0;
358 [ # # ]: 0 : trunk_n = lc ? lc->n_trunk : 0;
359 : 0 : cur_max_idx = mlx5_trunk_idx_offset_get(pool, trunk_idx);
360 : : /* Check if index reach maximum. */
361 [ # # ]: 0 : if (trunk_idx == TRUNK_MAX_IDX ||
362 [ # # ]: 0 : cur_max_idx >= pool->cfg.max_idx)
363 : : return 0;
364 : : /* No enough space in trunk array, resize the trunks array. */
365 [ # # ]: 0 : if (trunk_idx == trunk_n) {
366 [ # # ]: 0 : n_grow = trunk_idx ? trunk_idx :
367 : : RTE_CACHE_LINE_SIZE / sizeof(void *);
368 : 0 : cur_max_idx = mlx5_trunk_idx_offset_get(pool, trunk_n + n_grow);
369 : : /* Resize the trunk array. */
370 [ # # # # ]: 0 : p = pool_malloc(pool, MLX5_MEM_ZERO, ((trunk_idx + n_grow) *
371 : : sizeof(struct mlx5_indexed_trunk *)) +
372 : : (cur_max_idx * sizeof(uint32_t)) + sizeof(*p),
373 : : RTE_CACHE_LINE_SIZE, rte_socket_id());
374 [ # # ]: 0 : if (!p)
375 : : return 0;
376 : 0 : p->trunks = (struct mlx5_indexed_trunk **)&p->idx[cur_max_idx];
377 [ # # ]: 0 : if (lc)
378 : 0 : memcpy(p->trunks, lc->trunks, trunk_idx *
379 : : sizeof(struct mlx5_indexed_trunk *));
380 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
381 : : memset(RTE_PTR_ADD(p->trunks, trunk_idx * sizeof(void *)), 0,
382 : : n_grow * sizeof(void *));
383 : : #endif
384 : 0 : p->n_trunk_valid = trunk_idx;
385 : 0 : p->n_trunk = trunk_n + n_grow;
386 : 0 : p->len = 0;
387 : : }
388 : : /* Prepare the new trunk. */
389 : : trunk_size = sizeof(*trunk);
390 : 0 : data_size = mlx5_trunk_size_get(pool, trunk_idx);
391 : 0 : trunk_size += RTE_CACHE_LINE_ROUNDUP(data_size * pool->cfg.size);
392 [ # # # # ]: 0 : trunk = pool_malloc(pool, MLX5_MEM_ZERO, trunk_size,
393 : : RTE_CACHE_LINE_SIZE, rte_socket_id());
394 [ # # ]: 0 : if (unlikely(!trunk)) {
395 : 0 : pool->cfg.free(p);
396 : 0 : return 0;
397 : : }
398 : 0 : trunk->idx = trunk_idx;
399 [ # # ]: 0 : trunk->free = data_size;
400 : : mlx5_ipool_lock(pool);
401 : : /*
402 : : * Double check if trunks has been updated or have available index.
403 : : * During the new trunk allocate, index may still be flushed to the
404 : : * global cache. So also need to check the pool->gc->len.
405 : : */
406 [ # # # # ]: 0 : if (pool->gc && (lc != pool->gc ||
407 [ # # ]: 0 : lc->n_trunk_valid != trunk_idx ||
408 [ # # ]: 0 : pool->gc->len)) {
409 : : mlx5_ipool_unlock(pool);
410 [ # # ]: 0 : if (p)
411 : 0 : pool->cfg.free(p);
412 : 0 : pool->cfg.free(trunk);
413 : 0 : goto check_again;
414 : : }
415 : : /* Resize the trunk array and update local cache first. */
416 [ # # ]: 0 : if (p) {
417 [ # # # # ]: 0 : if (lc && !(--lc->ref_cnt))
418 : : olc = lc;
419 : : lc = p;
420 : 0 : lc->ref_cnt = 1;
421 : 0 : pool->cache[cidx]->lc = lc;
422 : 0 : rte_atomic_store_explicit(&pool->gc, p, rte_memory_order_relaxed);
423 : : }
424 : : /* Add trunk to trunks array. */
425 : 0 : lc->trunks[trunk_idx] = trunk;
426 : 0 : rte_atomic_fetch_add_explicit(&lc->n_trunk_valid, 1, rte_memory_order_relaxed);
427 : : /* Enqueue half of the index to global. */
428 : 0 : ts_idx = mlx5_trunk_idx_offset_get(pool, trunk_idx) + 1;
429 : 0 : fetch_size = trunk->free >> 1;
430 [ # # ]: 0 : if (fetch_size > pool->cfg.per_core_cache)
431 : 0 : fetch_size = trunk->free - pool->cfg.per_core_cache;
432 [ # # ]: 0 : for (i = 0; i < fetch_size; i++)
433 : 0 : lc->idx[i] = ts_idx + i;
434 [ # # ]: 0 : lc->len = fetch_size;
435 : : mlx5_ipool_unlock(pool);
436 : : /* Copy left half - 1 to local cache index array. */
437 : 0 : pool->cache[cidx]->len = trunk->free - fetch_size - 1;
438 : 0 : ts_idx += fetch_size;
439 [ # # ]: 0 : for (i = 0; i < pool->cache[cidx]->len; i++)
440 : 0 : pool->cache[cidx]->idx[i] = ts_idx + i;
441 [ # # ]: 0 : if (olc)
442 : 0 : pool->cfg.free(olc);
443 : 0 : return ts_idx + i;
444 : : }
445 : :
446 : : static void *
447 : 0 : _mlx5_ipool_get_cache(struct mlx5_indexed_pool *pool, int cidx, uint32_t idx)
448 : : {
449 : : struct mlx5_indexed_trunk *trunk;
450 : : struct mlx5_indexed_cache *lc;
451 : : uint32_t trunk_idx;
452 : : uint32_t entry_idx;
453 : :
454 : : MLX5_ASSERT(idx);
455 [ # # ]: 0 : if (unlikely(!pool->cache[cidx])) {
456 : 0 : pool->cache[cidx] = pool_malloc(pool, MLX5_MEM_ZERO,
457 : : sizeof(struct mlx5_ipool_per_lcore) +
458 : : (pool->cfg.per_core_cache * sizeof(uint32_t)),
459 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
460 [ # # ]: 0 : if (!pool->cache[cidx]) {
461 : 0 : DRV_LOG(ERR, "Ipool cache%d allocate failed\n", cidx);
462 : 0 : return NULL;
463 : : }
464 : : }
465 : 0 : lc = mlx5_ipool_update_global_cache(pool, cidx);
466 : 0 : idx -= 1;
467 : 0 : trunk_idx = mlx5_trunk_idx_get(pool, idx);
468 : 0 : trunk = lc->trunks[trunk_idx];
469 [ # # ]: 0 : if (!trunk)
470 : : return NULL;
471 : 0 : entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk_idx);
472 : 0 : return &trunk->data[entry_idx * pool->cfg.size];
473 : : }
474 : :
475 : : static void *
476 : 0 : mlx5_ipool_get_cache(struct mlx5_indexed_pool *pool, uint32_t idx)
477 : : {
478 : : void *entry;
479 : : int cidx;
480 : :
481 : 0 : cidx = rte_lcore_index(rte_lcore_id());
482 [ # # ]: 0 : if (unlikely(cidx == -1)) {
483 : : cidx = RTE_MAX_LCORE;
484 : 0 : rte_spinlock_lock(&pool->lcore_lock);
485 : : }
486 : 0 : entry = _mlx5_ipool_get_cache(pool, cidx, idx);
487 [ # # ]: 0 : if (unlikely(cidx == RTE_MAX_LCORE))
488 : 0 : rte_spinlock_unlock(&pool->lcore_lock);
489 : 0 : return entry;
490 : : }
491 : :
492 : : #ifdef POOL_DEBUG
493 : : static void
494 : : mlx5_ipool_validate_malloc_cache(struct mlx5_indexed_pool *pool, uint32_t idx)
495 : : {
496 : : rte_spinlock_lock(&pool->cache_validator.lock);
497 : : uint32_t entry_idx = idx - 1;
498 : : uint32_t allocated_size = pool->gc->n_trunk_valid *
499 : : mlx5_trunk_size_get(pool, pool->n_trunk_valid);
500 : :
501 : : if (!pool->cache_validator.bmp)
502 : : mlx5_ipool_grow_bmp(pool, allocated_size);
503 : :
504 : : if (pool->cache_validator.bmp_size < allocated_size)
505 : : mlx5_ipool_grow_bmp(pool, allocated_size);
506 : :
507 : : if (rte_bitmap_get(pool->cache_validator.bmp, entry_idx) == 0) {
508 : : DRV_LOG_IPOOL(ERR, "lcore id %d: pool %s: detected double malloc idx: %d",
509 : : rte_lcore_id(), pool->cfg.type, idx);
510 : : MLX5_ASSERT(0);
511 : : }
512 : : rte_bitmap_clear(pool->cache_validator.bmp, entry_idx);
513 : : rte_spinlock_unlock(&pool->cache_validator.lock);
514 : : }
515 : :
516 : : static void
517 : : mlx5_ipool_validate_free_cache(struct mlx5_indexed_pool *pool, uint32_t idx)
518 : : {
519 : : rte_spinlock_lock(&pool->cache_validator.lock);
520 : : uint32_t entry_idx = idx - 1;
521 : :
522 : : if (!pool->gc || !pool->cache_validator.bmp) {
523 : : rte_spinlock_unlock(&pool->cache_validator.lock);
524 : : return;
525 : : }
526 : :
527 : : if (rte_bitmap_get(pool->cache_validator.bmp, entry_idx) != 0) {
528 : : DRV_LOG_IPOOL(ERR, "lcore id %d: pool %s: detected double free of index %d",
529 : : rte_lcore_id(), pool->cfg.type, idx);
530 : : MLX5_ASSERT(0);
531 : : }
532 : : rte_bitmap_set(pool->cache_validator.bmp, entry_idx);
533 : : rte_spinlock_unlock(&pool->cache_validator.lock);
534 : : }
535 : : #endif
536 : :
537 : : static void *
538 : 0 : _mlx5_ipool_malloc_cache(struct mlx5_indexed_pool *pool, int cidx,
539 : : uint32_t *idx)
540 : : {
541 [ # # ]: 0 : if (unlikely(!pool->cache[cidx])) {
542 : 0 : pool->cache[cidx] = pool_malloc(pool, MLX5_MEM_ZERO,
543 : : sizeof(struct mlx5_ipool_per_lcore) +
544 : : (pool->cfg.per_core_cache * sizeof(uint32_t)),
545 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
546 [ # # ]: 0 : if (!pool->cache[cidx]) {
547 : 0 : DRV_LOG(ERR, "Ipool cache%d allocate failed\n", cidx);
548 : 0 : return NULL;
549 : : }
550 [ # # ]: 0 : } else if (pool->cache[cidx]->len) {
551 : 0 : pool->cache[cidx]->len--;
552 : 0 : *idx = pool->cache[cidx]->idx[pool->cache[cidx]->len];
553 : 0 : return _mlx5_ipool_get_cache(pool, cidx, *idx);
554 : : }
555 : : /* Not enough idx in global cache. Keep fetching from global. */
556 : 0 : *idx = mlx5_ipool_allocate_from_global(pool, cidx);
557 [ # # ]: 0 : if (unlikely(!(*idx)))
558 : : return NULL;
559 : 0 : return _mlx5_ipool_get_cache(pool, cidx, *idx);
560 : : }
561 : :
562 : : static void *
563 : 0 : mlx5_ipool_malloc_cache(struct mlx5_indexed_pool *pool, uint32_t *idx)
564 : : {
565 : : void *entry;
566 : : int cidx;
567 : :
568 : 0 : cidx = rte_lcore_index(rte_lcore_id());
569 [ # # ]: 0 : if (unlikely(cidx == -1)) {
570 : : cidx = RTE_MAX_LCORE;
571 : 0 : rte_spinlock_lock(&pool->lcore_lock);
572 : : }
573 : 0 : entry = _mlx5_ipool_malloc_cache(pool, cidx, idx);
574 [ # # ]: 0 : if (unlikely(cidx == RTE_MAX_LCORE))
575 : 0 : rte_spinlock_unlock(&pool->lcore_lock);
576 : : #ifdef POOL_DEBUG
577 : : ++pool->n_entry;
578 : : mlx5_ipool_validate_malloc_cache(pool, *idx);
579 : : DRV_LOG_IPOOL(DEBUG, "lcore id %d: pool %s: allocated entry %d lcore %d, "
580 : : "current cache size %d, total allocated entries %d.", rte_lcore_id(),
581 : : pool->cfg.type, *idx, cidx, pool->cache[cidx]->len, pool->n_entry);
582 : : #endif
583 : 0 : return entry;
584 : : }
585 : :
586 : : static void
587 : 0 : _mlx5_ipool_free_cache(struct mlx5_indexed_pool *pool, int cidx, uint32_t idx)
588 : : {
589 : : struct mlx5_ipool_per_lcore *ilc;
590 : : struct mlx5_indexed_cache *gc, *olc = NULL;
591 : : uint32_t reclaim_num = 0;
592 : :
593 : : MLX5_ASSERT(idx);
594 : :
595 : : #ifdef POOL_DEBUG
596 : : mlx5_ipool_validate_free_cache(pool, idx);
597 : : #endif
598 : :
599 : : /*
600 : : * When index was allocated on core A but freed on core B. In this
601 : : * case check if local cache on core B was allocated before.
602 : : */
603 [ # # ]: 0 : if (unlikely(!pool->cache[cidx])) {
604 : 0 : pool->cache[cidx] = pool_malloc(pool, MLX5_MEM_ZERO,
605 : : sizeof(struct mlx5_ipool_per_lcore) +
606 : : (pool->cfg.per_core_cache * sizeof(uint32_t)),
607 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
608 [ # # ]: 0 : if (!pool->cache[cidx]) {
609 : 0 : DRV_LOG(ERR, "Ipool cache%d allocate failed\n", cidx);
610 : 0 : return;
611 : : }
612 : : }
613 : : /* Try to enqueue to local index cache. */
614 [ # # ]: 0 : if (pool->cache[cidx]->len < pool->cfg.per_core_cache) {
615 : 0 : pool->cache[cidx]->idx[pool->cache[cidx]->len] = idx;
616 : 0 : pool->cache[cidx]->len++;
617 : 0 : DRV_LOG_IPOOL(DEBUG, "lcore id %d: pool %s: freed entry %d "
618 : : "back to lcache %d, lcache size %d.", rte_lcore_id(),
619 : : pool->cfg.type, idx, cidx, pool->cache[cidx]->len);
620 : 0 : return;
621 : : }
622 : : ilc = pool->cache[cidx];
623 : 0 : reclaim_num = pool->cfg.per_core_cache >> 2;
624 [ # # ]: 0 : ilc->len -= reclaim_num;
625 : : /* Local index cache full, try with global index cache. */
626 : : mlx5_ipool_lock(pool);
627 : 0 : gc = pool->gc;
628 [ # # ]: 0 : if (ilc->lc != gc) {
629 [ # # # # ]: 0 : if (ilc->lc && !(--ilc->lc->ref_cnt))
630 : : olc = ilc->lc;
631 : 0 : gc->ref_cnt++;
632 : 0 : ilc->lc = gc;
633 : : }
634 [ # # ]: 0 : memcpy(&gc->idx[gc->len], &ilc->idx[ilc->len],
635 : : reclaim_num * sizeof(uint32_t));
636 [ # # ]: 0 : gc->len += reclaim_num;
637 : : mlx5_ipool_unlock(pool);
638 [ # # ]: 0 : if (olc)
639 : 0 : pool->cfg.free(olc);
640 : 0 : pool->cache[cidx]->idx[pool->cache[cidx]->len] = idx;
641 : 0 : pool->cache[cidx]->len++;
642 : :
643 : 0 : DRV_LOG_IPOOL(DEBUG, "lcore id %d: pool %s: cache reclaim, lcache %d, "
644 : : "reclaimed: %d, gcache size %d.", rte_lcore_id(), pool->cfg.type,
645 : : cidx, reclaim_num, pool->cache[cidx]->len);
646 : : }
647 : :
648 : : static void
649 : 0 : mlx5_ipool_free_cache(struct mlx5_indexed_pool *pool, uint32_t idx)
650 : : {
651 : : int cidx;
652 : :
653 : 0 : cidx = rte_lcore_index(rte_lcore_id());
654 [ # # ]: 0 : if (unlikely(cidx == -1)) {
655 : : cidx = RTE_MAX_LCORE;
656 : 0 : rte_spinlock_lock(&pool->lcore_lock);
657 : : }
658 : 0 : _mlx5_ipool_free_cache(pool, cidx, idx);
659 [ # # ]: 0 : if (unlikely(cidx == RTE_MAX_LCORE))
660 : 0 : rte_spinlock_unlock(&pool->lcore_lock);
661 : :
662 : : #ifdef POOL_DEBUG
663 : : pool->n_entry--;
664 : : #endif
665 : 0 : }
666 : :
667 : : void *
668 : 0 : mlx5_ipool_malloc(struct mlx5_indexed_pool *pool, uint32_t *idx)
669 : : {
670 : : struct mlx5_indexed_trunk *trunk;
671 : 0 : uint64_t slab = 0;
672 : 0 : uint32_t iidx = 0;
673 : : void *p;
674 : :
675 [ # # ]: 0 : if (pool->cfg.per_core_cache)
676 : 0 : return mlx5_ipool_malloc_cache(pool, idx);
677 : : mlx5_ipool_lock(pool);
678 [ # # ]: 0 : if (pool->free_list == TRUNK_INVALID) {
679 : : /* If no available trunks, grow new. */
680 [ # # ]: 0 : if (mlx5_ipool_grow(pool)) {
681 : : mlx5_ipool_unlock(pool);
682 : 0 : return NULL;
683 : : }
684 : 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: add trunk: new size = %d",
685 : : rte_lcore_id(), pool->cfg.type, pool->n_trunk_valid);
686 : : }
687 : : MLX5_ASSERT(pool->free_list != TRUNK_INVALID);
688 : 0 : trunk = pool->trunks[pool->free_list];
689 : : MLX5_ASSERT(trunk->free);
690 [ # # ]: 0 : if (!rte_bitmap_scan(trunk->bmp, &iidx, &slab)) {
691 : : mlx5_ipool_unlock(pool);
692 : 0 : return NULL;
693 : : }
694 : : MLX5_ASSERT(slab);
695 : 0 : iidx += rte_ctz64(slab);
696 : : MLX5_ASSERT(iidx != UINT32_MAX);
697 : : MLX5_ASSERT(iidx < mlx5_trunk_size_get(pool, trunk->idx));
698 : 0 : rte_bitmap_clear(trunk->bmp, iidx);
699 : 0 : p = &trunk->data[iidx * pool->cfg.size];
700 : : /*
701 : : * The ipool index should grow continually from small to big,
702 : : * some features as metering only accept limited bits of index.
703 : : * Random index with MSB set may be rejected.
704 : : */
705 : 0 : iidx += mlx5_trunk_idx_offset_get(pool, trunk->idx);
706 : 0 : iidx += 1; /* non-zero index. */
707 : 0 : trunk->free--;
708 : : #ifdef POOL_DEBUG
709 : : ++pool->n_entry;
710 : : #endif
711 [ # # ]: 0 : if (!trunk->free) {
712 : : /* Full trunk will be removed from free list in imalloc. */
713 : : MLX5_ASSERT(pool->free_list == trunk->idx);
714 : 0 : pool->free_list = trunk->next;
715 [ # # ]: 0 : if (trunk->next != TRUNK_INVALID)
716 : 0 : pool->trunks[trunk->next]->prev = TRUNK_INVALID;
717 : 0 : trunk->prev = TRUNK_INVALID;
718 : 0 : trunk->next = TRUNK_INVALID;
719 : : #ifdef POOL_DEBUG
720 : : pool->trunk_empty++;
721 : : pool->trunk_avail--;
722 : : #endif
723 : : }
724 [ # # ]: 0 : *idx = iidx;
725 : : mlx5_ipool_unlock(pool);
726 : : #ifdef POOL_DEBUG
727 : : DRV_LOG_IPOOL(DEBUG, "lcore id %d: pool %s: allocated entry %d trunk_id %d, "
728 : : "number of trunks %d, total allocated entries %d", rte_lcore_id(),
729 : : pool->cfg.type, *idx, pool->free_list, pool->n_trunk_valid, pool->n_entry);
730 : : #endif
731 : : return p;
732 : : }
733 : :
734 : : void *
735 : 0 : mlx5_ipool_zmalloc(struct mlx5_indexed_pool *pool, uint32_t *idx)
736 : : {
737 : 0 : void *entry = mlx5_ipool_malloc(pool, idx);
738 : :
739 [ # # # # ]: 0 : if (entry && pool->cfg.size)
740 : 0 : memset(entry, 0, pool->cfg.size);
741 : 0 : return entry;
742 : : }
743 : :
744 : : void
745 : 0 : mlx5_ipool_free(struct mlx5_indexed_pool *pool, uint32_t idx)
746 : : {
747 : : struct mlx5_indexed_trunk *trunk;
748 : : uint32_t trunk_idx;
749 : : uint32_t entry_idx;
750 : :
751 [ # # ]: 0 : if (!idx)
752 : : return;
753 [ # # ]: 0 : if (pool->cfg.per_core_cache) {
754 : 0 : mlx5_ipool_free_cache(pool, idx);
755 : 0 : return;
756 : : }
757 [ # # ]: 0 : idx -= 1;
758 : : mlx5_ipool_lock(pool);
759 : 0 : trunk_idx = mlx5_trunk_idx_get(pool, idx);
760 [ # # # # : 0 : if ((!pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk_valid) ||
# # ]
761 [ # # ]: 0 : (pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk))
762 : 0 : goto out;
763 : 0 : trunk = pool->trunks[trunk_idx];
764 [ # # ]: 0 : if (!trunk)
765 : 0 : goto out;
766 : 0 : entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk->idx);
767 [ # # # # ]: 0 : if (trunk_idx != trunk->idx ||
768 [ # # ]: 0 : rte_bitmap_get(trunk->bmp, entry_idx))
769 : 0 : goto out;
770 : 0 : rte_bitmap_set(trunk->bmp, entry_idx);
771 : 0 : trunk->free++;
772 [ # # # # ]: 0 : if (pool->cfg.release_mem_en && trunk->free == mlx5_trunk_size_get
773 : : (pool, trunk->idx)) {
774 [ # # ]: 0 : if (pool->free_list == trunk->idx)
775 : 0 : pool->free_list = trunk->next;
776 [ # # ]: 0 : if (trunk->next != TRUNK_INVALID)
777 : 0 : pool->trunks[trunk->next]->prev = trunk->prev;
778 [ # # ]: 0 : if (trunk->prev != TRUNK_INVALID)
779 : 0 : pool->trunks[trunk->prev]->next = trunk->next;
780 : 0 : pool->cfg.free(trunk);
781 : 0 : pool->trunks[trunk_idx] = NULL;
782 : 0 : pool->n_trunk_valid--;
783 : : #ifdef POOL_DEBUG
784 : : pool->trunk_avail--;
785 : : pool->trunk_free++;
786 : : #endif
787 [ # # ]: 0 : if (pool->n_trunk_valid == 0) {
788 : 0 : pool->cfg.free(pool->trunks);
789 : 0 : pool->trunks = NULL;
790 : 0 : pool->n_trunk = 0;
791 : : }
792 [ # # ]: 0 : } else if (trunk->free == 1) {
793 : : /* Put into free trunk list head. */
794 : : MLX5_ASSERT(pool->free_list != trunk->idx);
795 : 0 : trunk->next = pool->free_list;
796 : 0 : trunk->prev = TRUNK_INVALID;
797 [ # # ]: 0 : if (pool->free_list != TRUNK_INVALID)
798 : 0 : pool->trunks[pool->free_list]->prev = trunk->idx;
799 : 0 : pool->free_list = trunk->idx;
800 : : #ifdef POOL_DEBUG
801 : : pool->trunk_empty--;
802 : : pool->trunk_avail++;
803 : : #endif
804 : : }
805 : : #ifdef POOL_DEBUG
806 : : pool->n_entry--;
807 : : #endif
808 : 0 : DRV_LOG_IPOOL(DEBUG, "lcore id %d: pool %s: freed entry %d trunk_id %d",
809 : : rte_lcore_id(), pool->cfg.type, entry_idx + 1, trunk_idx);
810 [ # # ]: 0 : out:
811 : : mlx5_ipool_unlock(pool);
812 : : }
813 : :
814 : : void *
815 : 0 : mlx5_ipool_get(struct mlx5_indexed_pool *pool, uint32_t idx)
816 : : {
817 : : struct mlx5_indexed_trunk *trunk;
818 : : void *p = NULL;
819 : : uint32_t trunk_idx;
820 : : uint32_t entry_idx;
821 : :
822 [ # # ]: 0 : if (!idx)
823 : : return NULL;
824 [ # # ]: 0 : if (pool->cfg.per_core_cache)
825 : 0 : return mlx5_ipool_get_cache(pool, idx);
826 [ # # ]: 0 : idx -= 1;
827 : : mlx5_ipool_lock(pool);
828 : 0 : trunk_idx = mlx5_trunk_idx_get(pool, idx);
829 [ # # # # : 0 : if ((!pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk_valid) ||
# # ]
830 [ # # ]: 0 : (pool->cfg.release_mem_en && trunk_idx >= pool->n_trunk))
831 : 0 : goto out;
832 : 0 : trunk = pool->trunks[trunk_idx];
833 [ # # ]: 0 : if (!trunk)
834 : 0 : goto out;
835 : 0 : entry_idx = idx - mlx5_trunk_idx_offset_get(pool, trunk->idx);
836 [ # # # # ]: 0 : if (trunk_idx != trunk->idx ||
837 [ # # ]: 0 : rte_bitmap_get(trunk->bmp, entry_idx))
838 : 0 : goto out;
839 : 0 : p = &trunk->data[entry_idx * pool->cfg.size];
840 [ # # ]: 0 : out:
841 : : mlx5_ipool_unlock(pool);
842 : : return p;
843 : : }
844 : :
845 : : int
846 : 0 : mlx5_ipool_destroy(struct mlx5_indexed_pool *pool)
847 : : {
848 : : struct mlx5_indexed_trunk **trunks = NULL;
849 [ # # ]: 0 : struct mlx5_indexed_cache *gc = pool->gc;
850 : : uint32_t i, n_trunk_valid = 0;
851 : :
852 : : MLX5_ASSERT(pool);
853 : : mlx5_ipool_lock(pool);
854 : 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: destroy", rte_lcore_id(), pool->cfg.type);
855 : :
856 [ # # ]: 0 : if (pool->cfg.per_core_cache) {
857 [ # # ]: 0 : for (i = 0; i <= RTE_MAX_LCORE; i++) {
858 : : /*
859 : : * Free only old global cache. Pool gc will be
860 : : * freed at last.
861 : : */
862 [ # # ]: 0 : if (pool->cache[i]) {
863 [ # # ]: 0 : if (pool->cache[i]->lc &&
864 [ # # ]: 0 : pool->cache[i]->lc != pool->gc &&
865 [ # # ]: 0 : (!(--pool->cache[i]->lc->ref_cnt)))
866 : 0 : pool->cfg.free(pool->cache[i]->lc);
867 : 0 : pool->cfg.free(pool->cache[i]);
868 : : }
869 : : }
870 [ # # ]: 0 : if (gc) {
871 : 0 : trunks = gc->trunks;
872 : 0 : n_trunk_valid = gc->n_trunk_valid;
873 : : }
874 : : } else {
875 : : gc = NULL;
876 : 0 : trunks = pool->trunks;
877 : 0 : n_trunk_valid = pool->n_trunk_valid;
878 : : }
879 [ # # ]: 0 : for (i = 0; i < n_trunk_valid; i++) {
880 [ # # ]: 0 : if (trunks[i])
881 : 0 : pool->cfg.free(trunks[i]);
882 : : }
883 [ # # ]: 0 : if (!gc && trunks)
884 : 0 : pool->cfg.free(trunks);
885 [ # # ]: 0 : if (gc)
886 : 0 : pool->cfg.free(gc);
887 : : #ifdef POOL_DEBUG
888 : : if (pool->cache_validator.bmp_mem)
889 : : pool->cfg.free(pool->cache_validator.bmp_mem);
890 : : #endif
891 : : mlx5_ipool_unlock(pool);
892 : 0 : mlx5_free(pool);
893 : 0 : return 0;
894 : : }
895 : :
896 : : void
897 : 0 : mlx5_ipool_flush_cache(struct mlx5_indexed_pool *pool)
898 : : {
899 : : uint32_t i, j;
900 : : struct mlx5_indexed_cache *gc;
901 : : struct rte_bitmap *ibmp;
902 : : uint32_t bmp_num, mem_size;
903 : :
904 [ # # ]: 0 : if (!pool->cfg.per_core_cache)
905 : : return;
906 : 0 : gc = pool->gc;
907 [ # # ]: 0 : if (!gc)
908 : : return;
909 : : /* Reset bmp. */
910 : 0 : bmp_num = mlx5_trunk_idx_offset_get(pool, gc->n_trunk_valid);
911 : 0 : mem_size = rte_bitmap_get_memory_footprint(bmp_num);
912 [ # # # # ]: 0 : pool->bmp_mem = pool_malloc(pool, MLX5_MEM_ZERO, mem_size,
913 : : RTE_CACHE_LINE_SIZE, rte_socket_id());
914 [ # # ]: 0 : if (!pool->bmp_mem) {
915 : 0 : DRV_LOG(ERR, "Ipool bitmap mem allocate failed.\n");
916 : 0 : return;
917 : : }
918 : 0 : ibmp = rte_bitmap_init_with_all_set(bmp_num, pool->bmp_mem, mem_size);
919 [ # # ]: 0 : if (!ibmp) {
920 : 0 : pool->cfg.free(pool->bmp_mem);
921 : 0 : pool->bmp_mem = NULL;
922 : 0 : DRV_LOG(ERR, "Ipool bitmap create failed.\n");
923 : 0 : return;
924 : : }
925 : 0 : pool->ibmp = ibmp;
926 : : /* Clear global cache. */
927 [ # # ]: 0 : for (i = 0; i < gc->len; i++)
928 : 0 : rte_bitmap_clear(ibmp, gc->idx[i] - 1);
929 : 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: flush gcache, gcache size = %d",
930 : : rte_lcore_id(), pool->cfg.type, gc->len);
931 : : /* Clear core cache. */
932 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE + 1; i++) {
933 : 0 : struct mlx5_ipool_per_lcore *ilc = pool->cache[i];
934 : :
935 [ # # ]: 0 : if (!ilc)
936 : 0 : continue;
937 [ # # ]: 0 : for (j = 0; j < ilc->len; j++)
938 : 0 : rte_bitmap_clear(ibmp, ilc->idx[j] - 1);
939 : 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: flush lcache %d",
940 : : rte_lcore_id(), pool->cfg.type, i);
941 : : }
942 : : }
943 : :
944 : : static void *
945 : 0 : mlx5_ipool_get_next_cache(struct mlx5_indexed_pool *pool, uint32_t *pos)
946 : : {
947 : : struct rte_bitmap *ibmp;
948 : 0 : uint64_t slab = 0;
949 : 0 : uint32_t iidx = *pos;
950 : :
951 : 0 : ibmp = pool->ibmp;
952 [ # # # # ]: 0 : if (!ibmp || !rte_bitmap_scan(ibmp, &iidx, &slab)) {
953 [ # # ]: 0 : if (pool->bmp_mem) {
954 : 0 : pool->cfg.free(pool->bmp_mem);
955 : 0 : pool->bmp_mem = NULL;
956 : 0 : pool->ibmp = NULL;
957 : : }
958 : 0 : return NULL;
959 : : }
960 : 0 : iidx += rte_ctz64(slab);
961 : 0 : rte_bitmap_clear(ibmp, iidx);
962 : 0 : iidx++;
963 : 0 : *pos = iidx;
964 : 0 : return mlx5_ipool_get_cache(pool, iidx);
965 : : }
966 : :
967 : : void *
968 : 0 : mlx5_ipool_get_next(struct mlx5_indexed_pool *pool, uint32_t *pos)
969 : : {
970 : 0 : uint32_t idx = *pos;
971 : : void *entry;
972 : :
973 [ # # ]: 0 : if (pool->cfg.per_core_cache)
974 : 0 : return mlx5_ipool_get_next_cache(pool, pos);
975 [ # # ]: 0 : while (idx <= mlx5_trunk_idx_offset_get(pool, pool->n_trunk)) {
976 : 0 : entry = mlx5_ipool_get(pool, idx);
977 [ # # ]: 0 : if (entry) {
978 : 0 : *pos = idx;
979 : 0 : return entry;
980 : : }
981 : 0 : idx++;
982 : : }
983 : : return NULL;
984 : : }
985 : :
986 : : int
987 : 0 : mlx5_ipool_resize(struct mlx5_indexed_pool *pool, uint32_t num_entries,
988 : : struct rte_flow_error *error)
989 : : {
990 [ # # ]: 0 : if (num_entries == pool->cfg.max_idx)
991 : : return 0;
992 [ # # ]: 0 : else if (num_entries < pool->cfg.max_idx)
993 : 0 : return rte_flow_error_set(error, EINVAL,
994 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
995 : : NULL, "cannot decrease pool size");
996 [ # # ]: 0 : if (num_entries % pool->cfg.trunk_size)
997 : 0 : return rte_flow_error_set(error, EINVAL,
998 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
999 : : NULL, "number of entries in pool must be trunk size multiplication");
1000 [ # # ]: 0 : if (num_entries >= mlx5_trunk_idx_offset_get(pool, TRUNK_MAX_IDX + 1))
1001 : 0 : return rte_flow_error_set(error, EINVAL,
1002 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1003 : : NULL, "requested number of entries exceeds pool limit");
1004 : : mlx5_ipool_lock(pool);
1005 [ # # ]: 0 : pool->cfg.max_idx = num_entries;
1006 : : mlx5_ipool_unlock(pool);
1007 : :
1008 : 0 : DRV_LOG_IPOOL(INFO,
1009 : : "lcore id %d: pool %s:, resize pool, new entries limit %d",
1010 : : rte_lcore_id(), pool->cfg.type, pool->cfg.max_idx);
1011 : 0 : return 0;
1012 : : }
1013 : :
1014 : : void
1015 : 0 : mlx5_ipool_dump(struct mlx5_indexed_pool *pool)
1016 : : {
1017 : 0 : printf("Pool %s entry size %u, trunks %u, %d entry per trunk, "
1018 : : "total: %d\n",
1019 : : pool->cfg.type, pool->cfg.size, pool->n_trunk_valid,
1020 : 0 : pool->cfg.trunk_size, pool->n_trunk_valid);
1021 : : #ifdef POOL_DEBUG
1022 : : printf("Pool %s entry %u, trunk alloc %u, empty: %u, "
1023 : : "available %u free %u\n",
1024 : : pool->cfg.type, pool->n_entry, pool->trunk_new,
1025 : : pool->trunk_empty, pool->trunk_avail, pool->trunk_free);
1026 : : #endif
1027 : 0 : }
1028 : :
1029 : : struct mlx5_l3t_tbl *
1030 : 0 : mlx5_l3t_create(enum mlx5_l3t_type type)
1031 : : {
1032 : : struct mlx5_l3t_tbl *tbl;
1033 : 0 : struct mlx5_indexed_pool_config l3t_ip_cfg = {
1034 : : .trunk_size = 16,
1035 : : .grow_trunk = 6,
1036 : : .grow_shift = 1,
1037 : : .need_lock = 0,
1038 : : .release_mem_en = 1,
1039 : : .malloc = mlx5_malloc,
1040 : : .free = mlx5_free,
1041 : : };
1042 : :
1043 [ # # ]: 0 : if (type >= MLX5_L3T_TYPE_MAX) {
1044 : 0 : rte_errno = EINVAL;
1045 : 0 : return NULL;
1046 : : }
1047 : 0 : tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_l3t_tbl), 1,
1048 : : SOCKET_ID_ANY);
1049 [ # # ]: 0 : if (!tbl) {
1050 : 0 : rte_errno = ENOMEM;
1051 : 0 : return NULL;
1052 : : }
1053 : 0 : tbl->type = type;
1054 [ # # # # ]: 0 : switch (type) {
1055 : 0 : case MLX5_L3T_TYPE_WORD:
1056 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_word);
1057 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_w";
1058 : 0 : break;
1059 : 0 : case MLX5_L3T_TYPE_DWORD:
1060 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_dword);
1061 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_dw";
1062 : 0 : break;
1063 : 0 : case MLX5_L3T_TYPE_QWORD:
1064 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_qword);
1065 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_qw";
1066 : 0 : break;
1067 : 0 : default:
1068 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_ptr);
1069 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_tpr";
1070 : 0 : break;
1071 : : }
1072 : : rte_spinlock_init(&tbl->sl);
1073 : 0 : tbl->eip = mlx5_ipool_create(&l3t_ip_cfg);
1074 [ # # ]: 0 : if (!tbl->eip) {
1075 : 0 : rte_errno = ENOMEM;
1076 : 0 : mlx5_free(tbl);
1077 : : tbl = NULL;
1078 : : }
1079 : : return tbl;
1080 : : }
1081 : :
1082 : : void
1083 : 0 : mlx5_l3t_destroy(struct mlx5_l3t_tbl *tbl)
1084 : : {
1085 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1086 : : uint32_t i, j;
1087 : :
1088 [ # # ]: 0 : if (!tbl)
1089 : : return;
1090 : 0 : g_tbl = tbl->tbl;
1091 [ # # ]: 0 : if (g_tbl) {
1092 [ # # ]: 0 : for (i = 0; i < MLX5_L3T_GT_SIZE; i++) {
1093 : 0 : m_tbl = g_tbl->tbl[i];
1094 [ # # ]: 0 : if (!m_tbl)
1095 : 0 : continue;
1096 [ # # ]: 0 : for (j = 0; j < MLX5_L3T_MT_SIZE; j++) {
1097 [ # # ]: 0 : if (!m_tbl->tbl[j])
1098 : 0 : continue;
1099 : : MLX5_ASSERT(!((struct mlx5_l3t_entry_word *)
1100 : : m_tbl->tbl[j])->ref_cnt);
1101 : 0 : mlx5_ipool_free(tbl->eip,
1102 : : ((struct mlx5_l3t_entry_word *)
1103 : : m_tbl->tbl[j])->idx);
1104 : 0 : m_tbl->tbl[j] = 0;
1105 [ # # ]: 0 : if (!(--m_tbl->ref_cnt))
1106 : : break;
1107 : : }
1108 : : MLX5_ASSERT(!m_tbl->ref_cnt);
1109 : 0 : mlx5_free(g_tbl->tbl[i]);
1110 : 0 : g_tbl->tbl[i] = 0;
1111 [ # # ]: 0 : if (!(--g_tbl->ref_cnt))
1112 : : break;
1113 : : }
1114 : : MLX5_ASSERT(!g_tbl->ref_cnt);
1115 : 0 : mlx5_free(tbl->tbl);
1116 : 0 : tbl->tbl = 0;
1117 : : }
1118 : 0 : mlx5_ipool_destroy(tbl->eip);
1119 : 0 : mlx5_free(tbl);
1120 : : }
1121 : :
1122 : : static int32_t
1123 : 0 : __l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1124 : : union mlx5_l3t_data *data)
1125 : : {
1126 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1127 : : struct mlx5_l3t_entry_word *w_e_tbl;
1128 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
1129 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
1130 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
1131 : : void *e_tbl;
1132 : : uint32_t entry_idx;
1133 : :
1134 : 0 : g_tbl = tbl->tbl;
1135 [ # # ]: 0 : if (!g_tbl)
1136 : : return -1;
1137 : 0 : m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
1138 [ # # ]: 0 : if (!m_tbl)
1139 : : return -1;
1140 : 0 : e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
1141 [ # # ]: 0 : if (!e_tbl)
1142 : : return -1;
1143 : 0 : entry_idx = idx & MLX5_L3T_ET_MASK;
1144 [ # # # # ]: 0 : switch (tbl->type) {
1145 : 0 : case MLX5_L3T_TYPE_WORD:
1146 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
1147 : 0 : data->word = w_e_tbl->entry[entry_idx].data;
1148 [ # # ]: 0 : if (w_e_tbl->entry[entry_idx].data)
1149 : 0 : w_e_tbl->entry[entry_idx].ref_cnt++;
1150 : : break;
1151 : 0 : case MLX5_L3T_TYPE_DWORD:
1152 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
1153 : 0 : data->dword = dw_e_tbl->entry[entry_idx].data;
1154 [ # # ]: 0 : if (dw_e_tbl->entry[entry_idx].data)
1155 : 0 : dw_e_tbl->entry[entry_idx].ref_cnt++;
1156 : : break;
1157 : 0 : case MLX5_L3T_TYPE_QWORD:
1158 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
1159 : 0 : data->qword = qw_e_tbl->entry[entry_idx].data;
1160 [ # # ]: 0 : if (qw_e_tbl->entry[entry_idx].data)
1161 : 0 : qw_e_tbl->entry[entry_idx].ref_cnt++;
1162 : : break;
1163 : 0 : default:
1164 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
1165 : 0 : data->ptr = ptr_e_tbl->entry[entry_idx].data;
1166 [ # # ]: 0 : if (ptr_e_tbl->entry[entry_idx].data)
1167 : 0 : ptr_e_tbl->entry[entry_idx].ref_cnt++;
1168 : : break;
1169 : : }
1170 : : return 0;
1171 : : }
1172 : :
1173 : : int32_t
1174 : 0 : mlx5_l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1175 : : union mlx5_l3t_data *data)
1176 : : {
1177 : : int ret;
1178 : :
1179 : 0 : rte_spinlock_lock(&tbl->sl);
1180 : 0 : ret = __l3t_get_entry(tbl, idx, data);
1181 : : rte_spinlock_unlock(&tbl->sl);
1182 : 0 : return ret;
1183 : : }
1184 : :
1185 : : int32_t
1186 : 0 : mlx5_l3t_clear_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx)
1187 : : {
1188 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1189 : : struct mlx5_l3t_entry_word *w_e_tbl;
1190 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
1191 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
1192 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
1193 : : void *e_tbl;
1194 : : uint32_t entry_idx;
1195 : : uint64_t ref_cnt;
1196 : : int32_t ret = -1;
1197 : :
1198 : 0 : rte_spinlock_lock(&tbl->sl);
1199 : 0 : g_tbl = tbl->tbl;
1200 [ # # ]: 0 : if (!g_tbl)
1201 : 0 : goto out;
1202 : 0 : m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
1203 [ # # ]: 0 : if (!m_tbl)
1204 : 0 : goto out;
1205 : 0 : e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
1206 [ # # ]: 0 : if (!e_tbl)
1207 : 0 : goto out;
1208 : 0 : entry_idx = idx & MLX5_L3T_ET_MASK;
1209 [ # # # # ]: 0 : switch (tbl->type) {
1210 : 0 : case MLX5_L3T_TYPE_WORD:
1211 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
1212 : : MLX5_ASSERT(w_e_tbl->entry[entry_idx].ref_cnt);
1213 : 0 : ret = --w_e_tbl->entry[entry_idx].ref_cnt;
1214 [ # # ]: 0 : if (ret)
1215 : 0 : goto out;
1216 : 0 : w_e_tbl->entry[entry_idx].data = 0;
1217 : 0 : ref_cnt = --w_e_tbl->ref_cnt;
1218 : 0 : break;
1219 : 0 : case MLX5_L3T_TYPE_DWORD:
1220 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
1221 : : MLX5_ASSERT(dw_e_tbl->entry[entry_idx].ref_cnt);
1222 : 0 : ret = --dw_e_tbl->entry[entry_idx].ref_cnt;
1223 [ # # ]: 0 : if (ret)
1224 : 0 : goto out;
1225 : 0 : dw_e_tbl->entry[entry_idx].data = 0;
1226 : 0 : ref_cnt = --dw_e_tbl->ref_cnt;
1227 : 0 : break;
1228 : 0 : case MLX5_L3T_TYPE_QWORD:
1229 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
1230 : : MLX5_ASSERT(qw_e_tbl->entry[entry_idx].ref_cnt);
1231 : 0 : ret = --qw_e_tbl->entry[entry_idx].ref_cnt;
1232 [ # # ]: 0 : if (ret)
1233 : 0 : goto out;
1234 : 0 : qw_e_tbl->entry[entry_idx].data = 0;
1235 : 0 : ref_cnt = --qw_e_tbl->ref_cnt;
1236 : 0 : break;
1237 : 0 : default:
1238 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
1239 : : MLX5_ASSERT(ptr_e_tbl->entry[entry_idx].ref_cnt);
1240 : 0 : ret = --ptr_e_tbl->entry[entry_idx].ref_cnt;
1241 [ # # ]: 0 : if (ret)
1242 : 0 : goto out;
1243 : 0 : ptr_e_tbl->entry[entry_idx].data = NULL;
1244 : 0 : ref_cnt = --ptr_e_tbl->ref_cnt;
1245 : 0 : break;
1246 : : }
1247 [ # # ]: 0 : if (!ref_cnt) {
1248 : 0 : mlx5_ipool_free(tbl->eip,
1249 : : ((struct mlx5_l3t_entry_word *)e_tbl)->idx);
1250 : 0 : m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK] =
1251 : : NULL;
1252 [ # # ]: 0 : if (!(--m_tbl->ref_cnt)) {
1253 : 0 : mlx5_free(m_tbl);
1254 : : g_tbl->tbl
1255 : 0 : [(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK] = NULL;
1256 [ # # ]: 0 : if (!(--g_tbl->ref_cnt)) {
1257 : 0 : mlx5_free(g_tbl);
1258 : 0 : tbl->tbl = 0;
1259 : : }
1260 : : }
1261 : : }
1262 : 0 : out:
1263 : : rte_spinlock_unlock(&tbl->sl);
1264 : 0 : return ret;
1265 : : }
1266 : :
1267 : : static int32_t
1268 : 0 : __l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1269 : : union mlx5_l3t_data *data)
1270 : : {
1271 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1272 : : struct mlx5_l3t_entry_word *w_e_tbl;
1273 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
1274 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
1275 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
1276 : : void *e_tbl;
1277 : 0 : uint32_t entry_idx, tbl_idx = 0;
1278 : :
1279 : : /* Check the global table, create it if empty. */
1280 : 0 : g_tbl = tbl->tbl;
1281 [ # # ]: 0 : if (!g_tbl) {
1282 : 0 : g_tbl = mlx5_malloc(MLX5_MEM_ZERO,
1283 : : sizeof(struct mlx5_l3t_level_tbl) +
1284 : : sizeof(void *) * MLX5_L3T_GT_SIZE, 1,
1285 : : SOCKET_ID_ANY);
1286 [ # # ]: 0 : if (!g_tbl) {
1287 : 0 : rte_errno = ENOMEM;
1288 : 0 : return -1;
1289 : : }
1290 : 0 : tbl->tbl = g_tbl;
1291 : : }
1292 : : /*
1293 : : * Check the middle table, create it if empty. Ref_cnt will be
1294 : : * increased if new sub table created.
1295 : : */
1296 : 0 : m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
1297 [ # # ]: 0 : if (!m_tbl) {
1298 : 0 : m_tbl = mlx5_malloc(MLX5_MEM_ZERO,
1299 : : sizeof(struct mlx5_l3t_level_tbl) +
1300 : : sizeof(void *) * MLX5_L3T_MT_SIZE, 1,
1301 : : SOCKET_ID_ANY);
1302 [ # # ]: 0 : if (!m_tbl) {
1303 : 0 : rte_errno = ENOMEM;
1304 : 0 : return -1;
1305 : : }
1306 : 0 : g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK] =
1307 : : m_tbl;
1308 : 0 : g_tbl->ref_cnt++;
1309 : : }
1310 : : /*
1311 : : * Check the entry table, create it if empty. Ref_cnt will be
1312 : : * increased if new sub entry table created.
1313 : : */
1314 : 0 : e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
1315 [ # # ]: 0 : if (!e_tbl) {
1316 : 0 : e_tbl = mlx5_ipool_zmalloc(tbl->eip, &tbl_idx);
1317 [ # # ]: 0 : if (!e_tbl) {
1318 : 0 : rte_errno = ENOMEM;
1319 : 0 : return -1;
1320 : : }
1321 : 0 : ((struct mlx5_l3t_entry_word *)e_tbl)->idx = tbl_idx;
1322 : 0 : m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK] =
1323 : : e_tbl;
1324 : 0 : m_tbl->ref_cnt++;
1325 : : }
1326 : 0 : entry_idx = idx & MLX5_L3T_ET_MASK;
1327 [ # # # # ]: 0 : switch (tbl->type) {
1328 : 0 : case MLX5_L3T_TYPE_WORD:
1329 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
1330 [ # # ]: 0 : if (w_e_tbl->entry[entry_idx].data) {
1331 : 0 : data->word = w_e_tbl->entry[entry_idx].data;
1332 : 0 : w_e_tbl->entry[entry_idx].ref_cnt++;
1333 : 0 : rte_errno = EEXIST;
1334 : 0 : return -1;
1335 : : }
1336 : 0 : w_e_tbl->entry[entry_idx].data = data->word;
1337 : 0 : w_e_tbl->entry[entry_idx].ref_cnt = 1;
1338 : 0 : w_e_tbl->ref_cnt++;
1339 : 0 : break;
1340 : 0 : case MLX5_L3T_TYPE_DWORD:
1341 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
1342 [ # # ]: 0 : if (dw_e_tbl->entry[entry_idx].data) {
1343 : 0 : data->dword = dw_e_tbl->entry[entry_idx].data;
1344 : 0 : dw_e_tbl->entry[entry_idx].ref_cnt++;
1345 : 0 : rte_errno = EEXIST;
1346 : 0 : return -1;
1347 : : }
1348 : 0 : dw_e_tbl->entry[entry_idx].data = data->dword;
1349 : 0 : dw_e_tbl->entry[entry_idx].ref_cnt = 1;
1350 : 0 : dw_e_tbl->ref_cnt++;
1351 : 0 : break;
1352 : 0 : case MLX5_L3T_TYPE_QWORD:
1353 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
1354 [ # # ]: 0 : if (qw_e_tbl->entry[entry_idx].data) {
1355 : 0 : data->qword = qw_e_tbl->entry[entry_idx].data;
1356 : 0 : qw_e_tbl->entry[entry_idx].ref_cnt++;
1357 : 0 : rte_errno = EEXIST;
1358 : 0 : return -1;
1359 : : }
1360 : 0 : qw_e_tbl->entry[entry_idx].data = data->qword;
1361 : 0 : qw_e_tbl->entry[entry_idx].ref_cnt = 1;
1362 : 0 : qw_e_tbl->ref_cnt++;
1363 : 0 : break;
1364 : 0 : default:
1365 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
1366 [ # # ]: 0 : if (ptr_e_tbl->entry[entry_idx].data) {
1367 : 0 : data->ptr = ptr_e_tbl->entry[entry_idx].data;
1368 : 0 : ptr_e_tbl->entry[entry_idx].ref_cnt++;
1369 : 0 : rte_errno = EEXIST;
1370 : 0 : return -1;
1371 : : }
1372 : 0 : ptr_e_tbl->entry[entry_idx].data = data->ptr;
1373 : 0 : ptr_e_tbl->entry[entry_idx].ref_cnt = 1;
1374 : 0 : ptr_e_tbl->ref_cnt++;
1375 : 0 : break;
1376 : : }
1377 : : return 0;
1378 : : }
1379 : :
1380 : : int32_t
1381 : 0 : mlx5_l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1382 : : union mlx5_l3t_data *data)
1383 : : {
1384 : : int ret;
1385 : :
1386 : 0 : rte_spinlock_lock(&tbl->sl);
1387 : 0 : ret = __l3t_set_entry(tbl, idx, data);
1388 : : rte_spinlock_unlock(&tbl->sl);
1389 : 0 : return ret;
1390 : : }
|