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) | 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 : : mlx5_ipool_unlock(pool);
888 : 0 : mlx5_free(pool);
889 : 0 : return 0;
890 : : }
891 : :
892 : : void
893 : 0 : mlx5_ipool_flush_cache(struct mlx5_indexed_pool *pool)
894 : : {
895 : : uint32_t i, j;
896 : : struct mlx5_indexed_cache *gc;
897 : : struct rte_bitmap *ibmp;
898 : : uint32_t bmp_num, mem_size;
899 : :
900 [ # # ]: 0 : if (!pool->cfg.per_core_cache)
901 : : return;
902 : 0 : gc = pool->gc;
903 [ # # ]: 0 : if (!gc)
904 : : return;
905 : : /* Reset bmp. */
906 : 0 : bmp_num = mlx5_trunk_idx_offset_get(pool, gc->n_trunk_valid);
907 : 0 : mem_size = rte_bitmap_get_memory_footprint(bmp_num);
908 [ # # # # ]: 0 : pool->bmp_mem = pool_malloc(pool, MLX5_MEM_ZERO, mem_size,
909 : : RTE_CACHE_LINE_SIZE, rte_socket_id());
910 [ # # ]: 0 : if (!pool->bmp_mem) {
911 : 0 : DRV_LOG(ERR, "Ipool bitmap mem allocate failed.\n");
912 : 0 : return;
913 : : }
914 : 0 : ibmp = rte_bitmap_init_with_all_set(bmp_num, pool->bmp_mem, mem_size);
915 [ # # ]: 0 : if (!ibmp) {
916 : 0 : pool->cfg.free(pool->bmp_mem);
917 : 0 : pool->bmp_mem = NULL;
918 : 0 : DRV_LOG(ERR, "Ipool bitmap create failed.\n");
919 : 0 : return;
920 : : }
921 : 0 : pool->ibmp = ibmp;
922 : : /* Clear global cache. */
923 [ # # ]: 0 : for (i = 0; i < gc->len; i++)
924 : 0 : rte_bitmap_clear(ibmp, gc->idx[i] - 1);
925 : 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: flush gcache, gcache size = %d",
926 : : rte_lcore_id(), pool->cfg.type, gc->len);
927 : : /* Clear core cache. */
928 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE + 1; i++) {
929 : 0 : struct mlx5_ipool_per_lcore *ilc = pool->cache[i];
930 : :
931 [ # # ]: 0 : if (!ilc)
932 : 0 : continue;
933 [ # # ]: 0 : for (j = 0; j < ilc->len; j++)
934 : 0 : rte_bitmap_clear(ibmp, ilc->idx[j] - 1);
935 : 0 : DRV_LOG_IPOOL(INFO, "lcore id %d: pool %s: flush lcache %d",
936 : : rte_lcore_id(), pool->cfg.type, i);
937 : : }
938 : : }
939 : :
940 : : static void *
941 : 0 : mlx5_ipool_get_next_cache(struct mlx5_indexed_pool *pool, uint32_t *pos)
942 : : {
943 : : struct rte_bitmap *ibmp;
944 : 0 : uint64_t slab = 0;
945 : 0 : uint32_t iidx = *pos;
946 : :
947 : 0 : ibmp = pool->ibmp;
948 [ # # # # ]: 0 : if (!ibmp || !rte_bitmap_scan(ibmp, &iidx, &slab)) {
949 [ # # ]: 0 : if (pool->bmp_mem) {
950 : 0 : pool->cfg.free(pool->bmp_mem);
951 : 0 : pool->bmp_mem = NULL;
952 : 0 : pool->ibmp = NULL;
953 : : }
954 : 0 : return NULL;
955 : : }
956 : 0 : iidx += rte_ctz64(slab);
957 : 0 : rte_bitmap_clear(ibmp, iidx);
958 : 0 : iidx++;
959 : 0 : *pos = iidx;
960 : 0 : return mlx5_ipool_get_cache(pool, iidx);
961 : : }
962 : :
963 : : void *
964 : 0 : mlx5_ipool_get_next(struct mlx5_indexed_pool *pool, uint32_t *pos)
965 : : {
966 : 0 : uint32_t idx = *pos;
967 : : void *entry;
968 : :
969 [ # # ]: 0 : if (pool->cfg.per_core_cache)
970 : 0 : return mlx5_ipool_get_next_cache(pool, pos);
971 [ # # ]: 0 : while (idx <= mlx5_trunk_idx_offset_get(pool, pool->n_trunk)) {
972 : 0 : entry = mlx5_ipool_get(pool, idx);
973 [ # # ]: 0 : if (entry) {
974 : 0 : *pos = idx;
975 : 0 : return entry;
976 : : }
977 : 0 : idx++;
978 : : }
979 : : return NULL;
980 : : }
981 : :
982 : : int
983 : 0 : mlx5_ipool_resize(struct mlx5_indexed_pool *pool, uint32_t num_entries,
984 : : struct rte_flow_error *error)
985 : : {
986 [ # # ]: 0 : if (num_entries == pool->cfg.max_idx)
987 : : return 0;
988 [ # # ]: 0 : else if (num_entries < pool->cfg.max_idx)
989 : 0 : return rte_flow_error_set(error, EINVAL,
990 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
991 : : NULL, "cannot decrease pool size");
992 [ # # ]: 0 : if (num_entries % pool->cfg.trunk_size)
993 : 0 : return rte_flow_error_set(error, EINVAL,
994 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
995 : : NULL, "number of entries in pool must be trunk size multiplication");
996 [ # # ]: 0 : if (num_entries >= mlx5_trunk_idx_offset_get(pool, TRUNK_MAX_IDX + 1))
997 : 0 : return rte_flow_error_set(error, EINVAL,
998 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
999 : : NULL, "requested number of entries exceeds pool limit");
1000 : : mlx5_ipool_lock(pool);
1001 [ # # ]: 0 : pool->cfg.max_idx = num_entries;
1002 : : mlx5_ipool_unlock(pool);
1003 : :
1004 : 0 : DRV_LOG_IPOOL(INFO,
1005 : : "lcore id %d: pool %s:, resize pool, new entries limit %d",
1006 : : rte_lcore_id(), pool->cfg.type, pool->cfg.max_idx);
1007 : 0 : return 0;
1008 : : }
1009 : :
1010 : : void
1011 : 0 : mlx5_ipool_dump(struct mlx5_indexed_pool *pool)
1012 : : {
1013 : 0 : printf("Pool %s entry size %u, trunks %u, %d entry per trunk, "
1014 : : "total: %d\n",
1015 : : pool->cfg.type, pool->cfg.size, pool->n_trunk_valid,
1016 : 0 : pool->cfg.trunk_size, pool->n_trunk_valid);
1017 : : #ifdef POOL_DEBUG
1018 : : printf("Pool %s entry %u, trunk alloc %u, empty: %u, "
1019 : : "available %u free %u\n",
1020 : : pool->cfg.type, pool->n_entry, pool->trunk_new,
1021 : : pool->trunk_empty, pool->trunk_avail, pool->trunk_free);
1022 : : #endif
1023 : 0 : }
1024 : :
1025 : : struct mlx5_l3t_tbl *
1026 : 0 : mlx5_l3t_create(enum mlx5_l3t_type type)
1027 : : {
1028 : : struct mlx5_l3t_tbl *tbl;
1029 : 0 : struct mlx5_indexed_pool_config l3t_ip_cfg = {
1030 : : .trunk_size = 16,
1031 : : .grow_trunk = 6,
1032 : : .grow_shift = 1,
1033 : : .need_lock = 0,
1034 : : .release_mem_en = 1,
1035 : : .malloc = mlx5_malloc,
1036 : : .free = mlx5_free,
1037 : : };
1038 : :
1039 [ # # ]: 0 : if (type >= MLX5_L3T_TYPE_MAX) {
1040 : 0 : rte_errno = EINVAL;
1041 : 0 : return NULL;
1042 : : }
1043 : 0 : tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_l3t_tbl), 1,
1044 : : SOCKET_ID_ANY);
1045 [ # # ]: 0 : if (!tbl) {
1046 : 0 : rte_errno = ENOMEM;
1047 : 0 : return NULL;
1048 : : }
1049 : 0 : tbl->type = type;
1050 [ # # # # ]: 0 : switch (type) {
1051 : 0 : case MLX5_L3T_TYPE_WORD:
1052 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_word);
1053 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_w";
1054 : 0 : break;
1055 : 0 : case MLX5_L3T_TYPE_DWORD:
1056 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_dword);
1057 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_dw";
1058 : 0 : break;
1059 : 0 : case MLX5_L3T_TYPE_QWORD:
1060 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_qword);
1061 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_qw";
1062 : 0 : break;
1063 : 0 : default:
1064 : 0 : l3t_ip_cfg.size = sizeof(struct mlx5_l3t_entry_ptr);
1065 : 0 : l3t_ip_cfg.type = "mlx5_l3t_e_tbl_tpr";
1066 : 0 : break;
1067 : : }
1068 : : rte_spinlock_init(&tbl->sl);
1069 : 0 : tbl->eip = mlx5_ipool_create(&l3t_ip_cfg);
1070 [ # # ]: 0 : if (!tbl->eip) {
1071 : 0 : rte_errno = ENOMEM;
1072 : 0 : mlx5_free(tbl);
1073 : : tbl = NULL;
1074 : : }
1075 : : return tbl;
1076 : : }
1077 : :
1078 : : void
1079 : 0 : mlx5_l3t_destroy(struct mlx5_l3t_tbl *tbl)
1080 : : {
1081 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1082 : : uint32_t i, j;
1083 : :
1084 [ # # ]: 0 : if (!tbl)
1085 : : return;
1086 : 0 : g_tbl = tbl->tbl;
1087 [ # # ]: 0 : if (g_tbl) {
1088 [ # # ]: 0 : for (i = 0; i < MLX5_L3T_GT_SIZE; i++) {
1089 : 0 : m_tbl = g_tbl->tbl[i];
1090 [ # # ]: 0 : if (!m_tbl)
1091 : 0 : continue;
1092 [ # # ]: 0 : for (j = 0; j < MLX5_L3T_MT_SIZE; j++) {
1093 [ # # ]: 0 : if (!m_tbl->tbl[j])
1094 : 0 : continue;
1095 : : MLX5_ASSERT(!((struct mlx5_l3t_entry_word *)
1096 : : m_tbl->tbl[j])->ref_cnt);
1097 : 0 : mlx5_ipool_free(tbl->eip,
1098 : : ((struct mlx5_l3t_entry_word *)
1099 : : m_tbl->tbl[j])->idx);
1100 : 0 : m_tbl->tbl[j] = 0;
1101 [ # # ]: 0 : if (!(--m_tbl->ref_cnt))
1102 : : break;
1103 : : }
1104 : : MLX5_ASSERT(!m_tbl->ref_cnt);
1105 : 0 : mlx5_free(g_tbl->tbl[i]);
1106 : 0 : g_tbl->tbl[i] = 0;
1107 [ # # ]: 0 : if (!(--g_tbl->ref_cnt))
1108 : : break;
1109 : : }
1110 : : MLX5_ASSERT(!g_tbl->ref_cnt);
1111 : 0 : mlx5_free(tbl->tbl);
1112 : 0 : tbl->tbl = 0;
1113 : : }
1114 : 0 : mlx5_ipool_destroy(tbl->eip);
1115 : 0 : mlx5_free(tbl);
1116 : : }
1117 : :
1118 : : static int32_t
1119 : 0 : __l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1120 : : union mlx5_l3t_data *data)
1121 : : {
1122 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1123 : : struct mlx5_l3t_entry_word *w_e_tbl;
1124 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
1125 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
1126 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
1127 : : void *e_tbl;
1128 : : uint32_t entry_idx;
1129 : :
1130 : 0 : g_tbl = tbl->tbl;
1131 [ # # ]: 0 : if (!g_tbl)
1132 : : return -1;
1133 : 0 : m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
1134 [ # # ]: 0 : if (!m_tbl)
1135 : : return -1;
1136 : 0 : e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
1137 [ # # ]: 0 : if (!e_tbl)
1138 : : return -1;
1139 : 0 : entry_idx = idx & MLX5_L3T_ET_MASK;
1140 [ # # # # ]: 0 : switch (tbl->type) {
1141 : 0 : case MLX5_L3T_TYPE_WORD:
1142 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
1143 : 0 : data->word = w_e_tbl->entry[entry_idx].data;
1144 [ # # ]: 0 : if (w_e_tbl->entry[entry_idx].data)
1145 : 0 : w_e_tbl->entry[entry_idx].ref_cnt++;
1146 : : break;
1147 : 0 : case MLX5_L3T_TYPE_DWORD:
1148 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
1149 : 0 : data->dword = dw_e_tbl->entry[entry_idx].data;
1150 [ # # ]: 0 : if (dw_e_tbl->entry[entry_idx].data)
1151 : 0 : dw_e_tbl->entry[entry_idx].ref_cnt++;
1152 : : break;
1153 : 0 : case MLX5_L3T_TYPE_QWORD:
1154 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
1155 : 0 : data->qword = qw_e_tbl->entry[entry_idx].data;
1156 [ # # ]: 0 : if (qw_e_tbl->entry[entry_idx].data)
1157 : 0 : qw_e_tbl->entry[entry_idx].ref_cnt++;
1158 : : break;
1159 : 0 : default:
1160 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
1161 : 0 : data->ptr = ptr_e_tbl->entry[entry_idx].data;
1162 [ # # ]: 0 : if (ptr_e_tbl->entry[entry_idx].data)
1163 : 0 : ptr_e_tbl->entry[entry_idx].ref_cnt++;
1164 : : break;
1165 : : }
1166 : : return 0;
1167 : : }
1168 : :
1169 : : int32_t
1170 : 0 : mlx5_l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1171 : : union mlx5_l3t_data *data)
1172 : : {
1173 : : int ret;
1174 : :
1175 : 0 : rte_spinlock_lock(&tbl->sl);
1176 : 0 : ret = __l3t_get_entry(tbl, idx, data);
1177 : : rte_spinlock_unlock(&tbl->sl);
1178 : 0 : return ret;
1179 : : }
1180 : :
1181 : : int32_t
1182 : 0 : mlx5_l3t_clear_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx)
1183 : : {
1184 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1185 : : struct mlx5_l3t_entry_word *w_e_tbl;
1186 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
1187 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
1188 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
1189 : : void *e_tbl;
1190 : : uint32_t entry_idx;
1191 : : uint64_t ref_cnt;
1192 : : int32_t ret = -1;
1193 : :
1194 : 0 : rte_spinlock_lock(&tbl->sl);
1195 : 0 : g_tbl = tbl->tbl;
1196 [ # # ]: 0 : if (!g_tbl)
1197 : 0 : goto out;
1198 : 0 : m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
1199 [ # # ]: 0 : if (!m_tbl)
1200 : 0 : goto out;
1201 : 0 : e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
1202 [ # # ]: 0 : if (!e_tbl)
1203 : 0 : goto out;
1204 : 0 : entry_idx = idx & MLX5_L3T_ET_MASK;
1205 [ # # # # ]: 0 : switch (tbl->type) {
1206 : 0 : case MLX5_L3T_TYPE_WORD:
1207 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
1208 : : MLX5_ASSERT(w_e_tbl->entry[entry_idx].ref_cnt);
1209 : 0 : ret = --w_e_tbl->entry[entry_idx].ref_cnt;
1210 [ # # ]: 0 : if (ret)
1211 : 0 : goto out;
1212 : 0 : w_e_tbl->entry[entry_idx].data = 0;
1213 : 0 : ref_cnt = --w_e_tbl->ref_cnt;
1214 : 0 : break;
1215 : 0 : case MLX5_L3T_TYPE_DWORD:
1216 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
1217 : : MLX5_ASSERT(dw_e_tbl->entry[entry_idx].ref_cnt);
1218 : 0 : ret = --dw_e_tbl->entry[entry_idx].ref_cnt;
1219 [ # # ]: 0 : if (ret)
1220 : 0 : goto out;
1221 : 0 : dw_e_tbl->entry[entry_idx].data = 0;
1222 : 0 : ref_cnt = --dw_e_tbl->ref_cnt;
1223 : 0 : break;
1224 : 0 : case MLX5_L3T_TYPE_QWORD:
1225 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
1226 : : MLX5_ASSERT(qw_e_tbl->entry[entry_idx].ref_cnt);
1227 : 0 : ret = --qw_e_tbl->entry[entry_idx].ref_cnt;
1228 [ # # ]: 0 : if (ret)
1229 : 0 : goto out;
1230 : 0 : qw_e_tbl->entry[entry_idx].data = 0;
1231 : 0 : ref_cnt = --qw_e_tbl->ref_cnt;
1232 : 0 : break;
1233 : 0 : default:
1234 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
1235 : : MLX5_ASSERT(ptr_e_tbl->entry[entry_idx].ref_cnt);
1236 : 0 : ret = --ptr_e_tbl->entry[entry_idx].ref_cnt;
1237 [ # # ]: 0 : if (ret)
1238 : 0 : goto out;
1239 : 0 : ptr_e_tbl->entry[entry_idx].data = NULL;
1240 : 0 : ref_cnt = --ptr_e_tbl->ref_cnt;
1241 : 0 : break;
1242 : : }
1243 [ # # ]: 0 : if (!ref_cnt) {
1244 : 0 : mlx5_ipool_free(tbl->eip,
1245 : : ((struct mlx5_l3t_entry_word *)e_tbl)->idx);
1246 : 0 : m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK] =
1247 : : NULL;
1248 [ # # ]: 0 : if (!(--m_tbl->ref_cnt)) {
1249 : 0 : mlx5_free(m_tbl);
1250 : : g_tbl->tbl
1251 : 0 : [(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK] = NULL;
1252 [ # # ]: 0 : if (!(--g_tbl->ref_cnt)) {
1253 : 0 : mlx5_free(g_tbl);
1254 : 0 : tbl->tbl = 0;
1255 : : }
1256 : : }
1257 : : }
1258 : 0 : out:
1259 : : rte_spinlock_unlock(&tbl->sl);
1260 : 0 : return ret;
1261 : : }
1262 : :
1263 : : static int32_t
1264 : 0 : __l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1265 : : union mlx5_l3t_data *data)
1266 : : {
1267 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
1268 : : struct mlx5_l3t_entry_word *w_e_tbl;
1269 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
1270 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
1271 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
1272 : : void *e_tbl;
1273 : 0 : uint32_t entry_idx, tbl_idx = 0;
1274 : :
1275 : : /* Check the global table, create it if empty. */
1276 : 0 : g_tbl = tbl->tbl;
1277 [ # # ]: 0 : if (!g_tbl) {
1278 : 0 : g_tbl = mlx5_malloc(MLX5_MEM_ZERO,
1279 : : sizeof(struct mlx5_l3t_level_tbl) +
1280 : : sizeof(void *) * MLX5_L3T_GT_SIZE, 1,
1281 : : SOCKET_ID_ANY);
1282 [ # # ]: 0 : if (!g_tbl) {
1283 : 0 : rte_errno = ENOMEM;
1284 : 0 : return -1;
1285 : : }
1286 : 0 : tbl->tbl = g_tbl;
1287 : : }
1288 : : /*
1289 : : * Check the middle table, create it if empty. Ref_cnt will be
1290 : : * increased if new sub table created.
1291 : : */
1292 : 0 : m_tbl = g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK];
1293 [ # # ]: 0 : if (!m_tbl) {
1294 : 0 : m_tbl = mlx5_malloc(MLX5_MEM_ZERO,
1295 : : sizeof(struct mlx5_l3t_level_tbl) +
1296 : : sizeof(void *) * MLX5_L3T_MT_SIZE, 1,
1297 : : SOCKET_ID_ANY);
1298 [ # # ]: 0 : if (!m_tbl) {
1299 : 0 : rte_errno = ENOMEM;
1300 : 0 : return -1;
1301 : : }
1302 : 0 : g_tbl->tbl[(idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK] =
1303 : : m_tbl;
1304 : 0 : g_tbl->ref_cnt++;
1305 : : }
1306 : : /*
1307 : : * Check the entry table, create it if empty. Ref_cnt will be
1308 : : * increased if new sub entry table created.
1309 : : */
1310 : 0 : e_tbl = m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK];
1311 [ # # ]: 0 : if (!e_tbl) {
1312 : 0 : e_tbl = mlx5_ipool_zmalloc(tbl->eip, &tbl_idx);
1313 [ # # ]: 0 : if (!e_tbl) {
1314 : 0 : rte_errno = ENOMEM;
1315 : 0 : return -1;
1316 : : }
1317 : 0 : ((struct mlx5_l3t_entry_word *)e_tbl)->idx = tbl_idx;
1318 : 0 : m_tbl->tbl[(idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK] =
1319 : : e_tbl;
1320 : 0 : m_tbl->ref_cnt++;
1321 : : }
1322 : 0 : entry_idx = idx & MLX5_L3T_ET_MASK;
1323 [ # # # # ]: 0 : switch (tbl->type) {
1324 : 0 : case MLX5_L3T_TYPE_WORD:
1325 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
1326 [ # # ]: 0 : if (w_e_tbl->entry[entry_idx].data) {
1327 : 0 : data->word = w_e_tbl->entry[entry_idx].data;
1328 : 0 : w_e_tbl->entry[entry_idx].ref_cnt++;
1329 : 0 : rte_errno = EEXIST;
1330 : 0 : return -1;
1331 : : }
1332 : 0 : w_e_tbl->entry[entry_idx].data = data->word;
1333 : 0 : w_e_tbl->entry[entry_idx].ref_cnt = 1;
1334 : 0 : w_e_tbl->ref_cnt++;
1335 : 0 : break;
1336 : 0 : case MLX5_L3T_TYPE_DWORD:
1337 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
1338 [ # # ]: 0 : if (dw_e_tbl->entry[entry_idx].data) {
1339 : 0 : data->dword = dw_e_tbl->entry[entry_idx].data;
1340 : 0 : dw_e_tbl->entry[entry_idx].ref_cnt++;
1341 : 0 : rte_errno = EEXIST;
1342 : 0 : return -1;
1343 : : }
1344 : 0 : dw_e_tbl->entry[entry_idx].data = data->dword;
1345 : 0 : dw_e_tbl->entry[entry_idx].ref_cnt = 1;
1346 : 0 : dw_e_tbl->ref_cnt++;
1347 : 0 : break;
1348 : 0 : case MLX5_L3T_TYPE_QWORD:
1349 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
1350 [ # # ]: 0 : if (qw_e_tbl->entry[entry_idx].data) {
1351 : 0 : data->qword = qw_e_tbl->entry[entry_idx].data;
1352 : 0 : qw_e_tbl->entry[entry_idx].ref_cnt++;
1353 : 0 : rte_errno = EEXIST;
1354 : 0 : return -1;
1355 : : }
1356 : 0 : qw_e_tbl->entry[entry_idx].data = data->qword;
1357 : 0 : qw_e_tbl->entry[entry_idx].ref_cnt = 1;
1358 : 0 : qw_e_tbl->ref_cnt++;
1359 : 0 : break;
1360 : 0 : default:
1361 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
1362 [ # # ]: 0 : if (ptr_e_tbl->entry[entry_idx].data) {
1363 : 0 : data->ptr = ptr_e_tbl->entry[entry_idx].data;
1364 : 0 : ptr_e_tbl->entry[entry_idx].ref_cnt++;
1365 : 0 : rte_errno = EEXIST;
1366 : 0 : return -1;
1367 : : }
1368 : 0 : ptr_e_tbl->entry[entry_idx].data = data->ptr;
1369 : 0 : ptr_e_tbl->entry[entry_idx].ref_cnt = 1;
1370 : 0 : ptr_e_tbl->ref_cnt++;
1371 : 0 : break;
1372 : : }
1373 : : return 0;
1374 : : }
1375 : :
1376 : : int32_t
1377 : 0 : mlx5_l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
1378 : : union mlx5_l3t_data *data)
1379 : : {
1380 : : int ret;
1381 : :
1382 : 0 : rte_spinlock_lock(&tbl->sl);
1383 : 0 : ret = __l3t_set_entry(tbl, idx, data);
1384 : : rte_spinlock_unlock(&tbl->sl);
1385 : 0 : return ret;
1386 : : }
|