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