LCOV - code coverage report
Current view: top level - drivers/net/mlx5 - mlx5_utils.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 1 643 0.2 %
Date: 2025-06-01 17:49:23 Functions: 1 30 3.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 452 0.2 %

           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                 :            : }

Generated by: LCOV version 1.14