LCOV - code coverage report
Current view: top level - drivers/common/cnxk - roc_npc_utils.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 462 0.0 %
Date: 2025-03-01 20:23:48 Functions: 0 29 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 304 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(C) 2021 Marvell.
       3                 :            :  */
       4                 :            : #include "roc_api.h"
       5                 :            : #include "roc_priv.h"
       6                 :            : 
       7                 :            : enum npc_mcam_cn20k_key_width {
       8                 :            :         NPC_CN20K_MCAM_KEY_X1 = 0,
       9                 :            :         NPC_CN20K_MCAM_KEY_DYN = NPC_CN20K_MCAM_KEY_X1,
      10                 :            :         NPC_CN20K_MCAM_KEY_X2,
      11                 :            :         NPC_CN20K_MCAM_KEY_X4,
      12                 :            :         NPC_CN20K_MCAM_KEY_MAX,
      13                 :            : };
      14                 :            : 
      15                 :            : uint8_t
      16                 :          0 : npc_get_key_type(struct npc *npc, struct roc_npc_flow *flow)
      17                 :            : {
      18                 :            :         int i;
      19                 :            : 
      20                 :            :         /* KEX is configured just for X2 */
      21         [ #  # ]:          0 :         if (npc->keyw[ROC_NPC_INTF_RX] == 1)
      22                 :            :                 return NPC_CN20K_MCAM_KEY_X2;
      23                 :            : 
      24                 :            :         /* KEX is configured just for X4 */
      25         [ #  # ]:          0 :         if (npc->keyw[ROC_NPC_INTF_RX] == 2)
      26                 :            :                 return NPC_CN20K_MCAM_KEY_X4;
      27                 :            : 
      28                 :            :         /* KEX is configured for both X2 and X4 */
      29                 :            :         /* Check mask for upper 256 bits. if mask is set, then it is X4 entry */
      30         [ #  # ]:          0 :         for (i = 4; i < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; i++) {
      31         [ #  # ]:          0 :                 if (flow->mcam_mask[i] != 0)
      32                 :            :                         return NPC_CN20K_MCAM_KEY_X4;
      33                 :            :         }
      34                 :            :         return NPC_CN20K_MCAM_KEY_X2;
      35                 :            : }
      36                 :            : 
      37                 :            : static void
      38                 :            : npc_prep_mcam_ldata(uint8_t *ptr, const uint8_t *data, int len)
      39                 :            : {
      40                 :            :         int idx;
      41                 :            : 
      42   [ #  #  #  # ]:          0 :         for (idx = 0; idx < len; idx++)
      43                 :          0 :                 ptr[idx] = data[len - 1 - idx];
      44                 :            : }
      45                 :            : 
      46                 :            : static int
      47                 :            : npc_check_copysz(size_t size, size_t len)
      48                 :            : {
      49                 :          0 :         if (len <= size)
      50                 :            :                 return len;
      51                 :            :         return NPC_ERR_PARAM;
      52                 :            : }
      53                 :            : 
      54                 :            : static inline int
      55                 :            : npc_mem_is_zero(const void *mem, int len)
      56                 :            : {
      57                 :            :         const char *m = mem;
      58                 :            :         int i;
      59                 :            : 
      60   [ #  #  #  # ]:          0 :         for (i = 0; i < len; i++) {
      61   [ #  #  #  # ]:          0 :                 if (m[i] != 0)
      62                 :            :                         return 0;
      63                 :            :         }
      64                 :            :         return 1;
      65                 :            : }
      66                 :            : 
      67                 :            : static void
      68                 :            : npc_set_hw_mask(struct npc_parse_item_info *info, struct npc_xtract_info *xinfo,
      69                 :            :                 char *hw_mask)
      70                 :            : {
      71                 :            :         int max_off, offset;
      72                 :            :         int j;
      73                 :            : 
      74         [ #  # ]:          0 :         if (xinfo->enable == 0)
      75                 :            :                 return;
      76                 :            : 
      77   [ #  #  #  #  :          0 :         if (xinfo->hdr_off < info->hw_hdr_len)
                   #  # ]
      78                 :            :                 return;
      79                 :            : 
      80                 :          0 :         max_off = xinfo->hdr_off + xinfo->len - info->hw_hdr_len;
      81                 :            : 
      82                 :          0 :         if (max_off > info->len)
      83                 :            :                 max_off = info->len;
      84                 :            : 
      85                 :          0 :         offset = xinfo->hdr_off - info->hw_hdr_len;
      86   [ #  #  #  #  :          0 :         for (j = offset; j < max_off; j++)
                   #  # ]
      87                 :          0 :                 hw_mask[j] = 0xff;
      88                 :            : }
      89                 :            : 
      90                 :            : static void
      91                 :            : npc_ipv6_hash_mask_get(struct npc_xtract_info *xinfo, struct npc_parse_item_info *info)
      92                 :            : {
      93                 :            :         int offset = 0;
      94                 :          0 :         uint8_t *hw_mask = info->hw_mask;
      95                 :            : 
      96                 :          0 :         offset = xinfo->hdr_off - info->hw_hdr_len;
      97                 :          0 :         memset(&hw_mask[offset], 0xFF, NPC_HASH_FIELD_LEN);
      98                 :          0 : }
      99                 :            : 
     100                 :            : static void
     101                 :          0 : npc_get_hw_supp_mask_legacy(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
     102                 :            :                             int lt)
     103                 :            : {
     104                 :            :         struct npc_xtract_info *xinfo, *lfinfo;
     105                 :          0 :         char *hw_mask = info->hw_mask;
     106                 :            :         int lf_cfg = 0;
     107                 :            :         int i, j;
     108                 :            :         int intf;
     109                 :            : 
     110                 :          0 :         intf = pst->nix_intf;
     111                 :          0 :         xinfo = pst->npc->prx_dxcfg[intf][lid][lt].xtract;
     112                 :          0 :         memset(hw_mask, 0, info->len);
     113                 :            : 
     114         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_LD; i++) {
     115   [ #  #  #  # ]:          0 :                 if (pst->npc->hash_extract_cap && xinfo[i].use_hash)
     116                 :            :                         npc_ipv6_hash_mask_get(&xinfo[i], info);
     117                 :            :                 else
     118         [ #  # ]:          0 :                         npc_set_hw_mask(info, &xinfo[i], hw_mask);
     119                 :            :         }
     120                 :            : 
     121         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_LD; i++) {
     122         [ #  # ]:          0 :                 if (xinfo[i].flags_enable == 0)
     123                 :          0 :                         continue;
     124                 :            : 
     125                 :          0 :                 lf_cfg = pst->npc->prx_lfcfg[i].i;
     126         [ #  # ]:          0 :                 if (lf_cfg == lid) {
     127         [ #  # ]:          0 :                         for (j = 0; j < NPC_MAX_LFL; j++) {
     128         [ #  # ]:          0 :                                 lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
     129                 :            :                                 npc_set_hw_mask(info, &lfinfo[0], hw_mask);
     130                 :            :                         }
     131                 :            :                 }
     132                 :            :         }
     133                 :          0 : }
     134                 :            : 
     135                 :            : static void
     136                 :          0 : npc_get_hw_supp_mask_o20k(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
     137                 :            :                           int lt)
     138                 :            : {
     139                 :            :         struct npc_xtract_info *xinfo;
     140                 :            :         union npc_kex_ldata_flags_cfg *lid_info;
     141                 :          0 :         char *hw_mask = info->hw_mask;
     142                 :            :         int ex;
     143                 :            :         int intf;
     144                 :            : 
     145                 :          0 :         intf = pst->nix_intf;
     146                 :          0 :         memset(hw_mask, 0, info->len);
     147         [ #  # ]:          0 :         for (ex = 0; ex < NPC_MAX_EXTRACTTORS; ex++) {
     148                 :          0 :                 lid_info = &pst->npc->lid_cfg[intf][ex];
     149         [ #  # ]:          0 :                 if (lid_info->s.lid != lid)
     150                 :          0 :                         continue;
     151                 :            :                 xinfo = &pst->npc->prx_dxcfg_cn20k[intf][ex][lt].xtract;
     152                 :            : 
     153   [ #  #  #  # ]:          0 :                 if (pst->npc->hash_extract_cap && xinfo->use_hash)
     154                 :            :                         npc_ipv6_hash_mask_get(xinfo, info);
     155                 :            :                 else
     156                 :            :                         npc_set_hw_mask(info, xinfo, hw_mask);
     157                 :            :         }
     158                 :          0 : }
     159                 :            : 
     160                 :            : void
     161         [ #  # ]:          0 : npc_get_hw_supp_mask(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid, int lt)
     162                 :            : {
     163         [ #  # ]:          0 :         if (!roc_model_is_cn20k())
     164                 :          0 :                 return npc_get_hw_supp_mask_legacy(pst, info, lid, lt);
     165                 :            :         else
     166                 :          0 :                 return npc_get_hw_supp_mask_o20k(pst, info, lid, lt);
     167                 :            : }
     168                 :            : 
     169                 :            : inline int
     170                 :          0 : npc_mask_is_supported(const char *mask, const char *hw_mask, int len)
     171                 :            : {
     172                 :            :         /*
     173                 :            :          * If no hw_mask, assume nothing is supported.
     174                 :            :          * mask is never NULL
     175                 :            :          */
     176         [ #  # ]:          0 :         if (hw_mask == NULL)
     177                 :          0 :                 return npc_mem_is_zero(mask, len);
     178                 :            : 
     179   [ #  #  #  # ]:          0 :         while (len--) {
     180   [ #  #  #  # ]:          0 :                 if ((mask[len] | hw_mask[len]) != hw_mask[len])
     181                 :            :                         return 0; /* False */
     182                 :            :         }
     183                 :            :         return 1;
     184                 :            : }
     185                 :            : 
     186                 :            : int
     187                 :          0 : npc_parse_item_basic(const struct roc_npc_item_info *item,
     188                 :            :                      struct npc_parse_item_info *info)
     189                 :            : {
     190                 :            :         /* Item must not be NULL */
     191         [ #  # ]:          0 :         if (item == NULL)
     192                 :            :                 return NPC_ERR_PARAM;
     193                 :            : 
     194                 :            :         /* Don't support ranges */
     195         [ #  # ]:          0 :         if (item->last != NULL)
     196                 :            :                 return NPC_ERR_INVALID_RANGE;
     197                 :            : 
     198                 :            :         /* If spec is NULL, both mask and last must be NULL, this
     199                 :            :          * makes it to match ANY value (eq to mask = 0).
     200                 :            :          * Setting either mask or last without spec is an error
     201                 :            :          */
     202         [ #  # ]:          0 :         if (item->spec == NULL) {
     203         [ #  # ]:          0 :                 if (item->last == NULL && item->mask == NULL) {
     204                 :          0 :                         info->spec = NULL;
     205                 :          0 :                         return 0;
     206                 :            :                 }
     207                 :            :                 return NPC_ERR_INVALID_SPEC;
     208                 :            :         }
     209                 :            : 
     210                 :            :         /* We have valid spec */
     211         [ #  # ]:          0 :         if (item->type != ROC_NPC_ITEM_TYPE_RAW)
     212                 :          0 :                 info->spec = item->spec;
     213                 :            : 
     214                 :            :         /* If mask is not set, use default mask, err if default mask is
     215                 :            :          * also NULL.
     216                 :            :          */
     217         [ #  # ]:          0 :         if (item->mask == NULL) {
     218         [ #  # ]:          0 :                 if (info->def_mask == NULL)
     219                 :            :                         return NPC_ERR_PARAM;
     220                 :          0 :                 info->mask = info->def_mask;
     221                 :            :         } else {
     222         [ #  # ]:          0 :                 if (item->type != ROC_NPC_ITEM_TYPE_RAW)
     223                 :          0 :                         info->mask = item->mask;
     224                 :            :         }
     225                 :            : 
     226         [ #  # ]:          0 :         if (info->mask == NULL)
     227                 :            :                 return NPC_ERR_INVALID_MASK;
     228                 :            : 
     229                 :            :         /* mask specified must be subset of hw supported mask
     230                 :            :          * mask | hw_mask == hw_mask
     231                 :            :          */
     232   [ #  #  #  # ]:          0 :         if (!npc_mask_is_supported(info->mask, info->hw_mask, info->len))
     233                 :          0 :                 return NPC_ERR_INVALID_MASK;
     234                 :            : 
     235                 :            :         return 0;
     236                 :            : }
     237                 :            : 
     238                 :            : static int
     239                 :          0 : npc_update_extraction_data(struct npc_parse_state *pst,
     240                 :            :                            struct npc_parse_item_info *info,
     241                 :            :                            struct npc_xtract_info *xinfo)
     242                 :            : {
     243                 :            :         uint8_t int_info_mask[NPC_MAX_EXTRACT_DATA_LEN];
     244                 :            :         uint8_t int_info[NPC_MAX_EXTRACT_DATA_LEN];
     245                 :            :         struct npc_xtract_info *x;
     246                 :            :         int hdr_off;
     247                 :            :         int len = 0;
     248                 :            : 
     249                 :            :         x = xinfo;
     250         [ #  # ]:          0 :         if (x->len > NPC_MAX_EXTRACT_DATA_LEN)
     251                 :            :                 return NPC_ERR_INVALID_SIZE;
     252                 :            : 
     253                 :          0 :         len = x->len;
     254                 :          0 :         hdr_off = x->hdr_off;
     255                 :            : 
     256         [ #  # ]:          0 :         if (hdr_off < info->hw_hdr_len)
     257                 :            :                 return 0;
     258                 :            : 
     259         [ #  # ]:          0 :         if (x->enable == 0)
     260                 :            :                 return 0;
     261                 :            : 
     262                 :          0 :         hdr_off -= info->hw_hdr_len;
     263                 :            : 
     264         [ #  # ]:          0 :         if (hdr_off >= info->len)
     265                 :            :                 return 0;
     266                 :            : 
     267         [ #  # ]:          0 :         if (hdr_off + len > info->len)
     268                 :          0 :                 len = info->len - hdr_off;
     269                 :            : 
     270         [ #  # ]:          0 :         len = npc_check_copysz((ROC_NPC_MAX_MCAM_WIDTH_DWORDS * 8) - x->key_off,
     271                 :            :                                len);
     272         [ #  # ]:          0 :         if (len < 0)
     273                 :            :                 return NPC_ERR_INVALID_SIZE;
     274                 :            : 
     275                 :            :         /* Need to reverse complete structure so that dest addr is at
     276                 :            :          * MSB so as to program the MCAM using mcam_data & mcam_mask
     277                 :            :          * arrays
     278                 :            :          */
     279                 :          0 :         npc_prep_mcam_ldata(int_info, (const uint8_t *)info->spec + hdr_off,
     280                 :            :                             x->len);
     281                 :            :         npc_prep_mcam_ldata(int_info_mask,
     282                 :          0 :                             (const uint8_t *)info->mask + hdr_off, x->len);
     283                 :            : 
     284                 :          0 :         memcpy(pst->mcam_mask + x->key_off, int_info_mask, len);
     285                 :          0 :         memcpy(pst->mcam_data + x->key_off, int_info, len);
     286                 :          0 :         return 0;
     287                 :            : }
     288                 :            : 
     289                 :            : static int
     290                 :          0 : npc_field_hash_secret_get(struct npc *npc, struct npc_hash_cfg *hash_cfg)
     291                 :            : {
     292                 :            :         struct npc_get_field_hash_info_req *req;
     293                 :            :         struct npc_get_field_hash_info_rsp *rsp;
     294                 :          0 :         struct mbox *mbox = mbox_get(npc->mbox);
     295                 :            :         int rc = 0;
     296                 :            : 
     297                 :          0 :         req = mbox_alloc_msg_npc_get_field_hash_info(mbox);
     298         [ #  # ]:          0 :         if (req == NULL)
     299                 :            :                 return -ENOSPC;
     300                 :            :         rc = mbox_process_msg(mbox, (void *)&rsp);
     301         [ #  # ]:          0 :         if (rc) {
     302                 :          0 :                 plt_err("Failed to fetch field hash secret key");
     303                 :          0 :                 goto done;
     304                 :            :         }
     305                 :            : 
     306         [ #  # ]:          0 :         mbox_memcpy(hash_cfg->secret_key, rsp->secret_key, sizeof(rsp->secret_key));
     307                 :          0 :         mbox_memcpy(hash_cfg->hash_mask, rsp->hash_mask, sizeof(rsp->hash_mask));
     308                 :          0 :         mbox_memcpy(hash_cfg->hash_ctrl, rsp->hash_ctrl, sizeof(rsp->hash_ctrl));
     309                 :            : 
     310                 :          0 : done:
     311                 :            :         mbox_put(mbox);
     312                 :          0 :         return rc;
     313                 :            : }
     314                 :            : 
     315                 :            : static inline void
     316                 :            : be32_to_cpu_array(uint32_t *dst, const uint32_t *src, size_t len)
     317                 :            : {
     318                 :            :         size_t i;
     319                 :            : 
     320         [ #  # ]:          0 :         for (i = 0; i < len; i++)
     321         [ #  # ]:          0 :                 dst[i] = plt_be_to_cpu_32(src[i]);
     322                 :            : }
     323                 :            : 
     324                 :            : static uint64_t
     325                 :          0 : npc_wide_extract(const uint64_t input[], size_t start_bit, size_t width_bits)
     326                 :            : {
     327                 :          0 :         const uint64_t mask = ~(uint64_t)((~(__uint128_t)0) << width_bits);
     328                 :          0 :         const size_t msb = start_bit + width_bits - 1;
     329                 :          0 :         const size_t lword = start_bit >> 6;
     330                 :          0 :         const size_t uword = msb >> 6;
     331                 :            :         size_t lbits;
     332                 :            :         uint64_t hi, lo;
     333                 :            : 
     334         [ #  # ]:          0 :         if (lword == uword)
     335                 :          0 :                 return (input[lword] >> (start_bit & 63)) & mask;
     336                 :            : 
     337                 :          0 :         lbits = 64 - (start_bit & 63);
     338                 :          0 :         hi = input[uword];
     339                 :          0 :         lo = (input[lword] >> (start_bit & 63));
     340                 :          0 :         return ((hi << lbits) | lo) & mask;
     341                 :            : }
     342                 :            : 
     343                 :            : static void
     344                 :            : npc_lshift_key(uint64_t *key, size_t key_bit_len)
     345                 :            : {
     346                 :            :         uint64_t prev_orig_word = 0;
     347                 :            :         uint64_t cur_orig_word = 0;
     348                 :          0 :         size_t extra = key_bit_len % 64;
     349                 :          0 :         size_t max_idx = key_bit_len / 64;
     350                 :            :         size_t i;
     351                 :            : 
     352         [ #  # ]:          0 :         if (extra)
     353                 :          0 :                 max_idx++;
     354                 :            : 
     355         [ #  # ]:          0 :         for (i = 0; i < max_idx; i++) {
     356                 :          0 :                 cur_orig_word = key[i];
     357                 :          0 :                 key[i] = key[i] << 1;
     358                 :          0 :                 key[i] |= ((prev_orig_word >> 63) & 0x1);
     359                 :            :                 prev_orig_word = cur_orig_word;
     360                 :            :         }
     361                 :            : }
     362                 :            : 
     363                 :            : static uint32_t
     364                 :          0 : npc_toeplitz_hash(const uint64_t *data, uint64_t *key, size_t data_bit_len, size_t key_bit_len)
     365                 :            : {
     366                 :            :         uint32_t hash_out = 0;
     367                 :            :         uint64_t temp_data = 0;
     368                 :            :         int i;
     369                 :            : 
     370         [ #  # ]:          0 :         for (i = data_bit_len - 1; i >= 0; i--) {
     371                 :          0 :                 temp_data = (data[i / 64]);
     372                 :          0 :                 temp_data = temp_data >> (i % 64);
     373                 :          0 :                 temp_data &= 0x1;
     374         [ #  # ]:          0 :                 if (temp_data)
     375                 :          0 :                         hash_out ^= (uint32_t)(npc_wide_extract(key, key_bit_len - 32, 32));
     376                 :            : 
     377                 :            :                 npc_lshift_key(key, key_bit_len);
     378                 :            :         }
     379                 :            : 
     380                 :          0 :         return hash_out;
     381                 :            : }
     382                 :            : 
     383                 :            : static uint32_t
     384                 :          0 : npc_field_hash_calc(uint64_t *ldata, struct npc_hash_cfg *hash_cfg, uint8_t intf, uint8_t hash_idx)
     385                 :            : {
     386                 :            :         uint64_t hash_key[3];
     387                 :            :         uint64_t data_padded[2];
     388                 :            :         uint32_t field_hash;
     389                 :            : 
     390                 :          0 :         hash_key[0] = hash_cfg->secret_key[1] << 31;
     391                 :          0 :         hash_key[0] |= hash_cfg->secret_key[2];
     392                 :          0 :         hash_key[1] = hash_cfg->secret_key[1] >> 33;
     393                 :          0 :         hash_key[1] |= hash_cfg->secret_key[0] << 31;
     394                 :          0 :         hash_key[2] = hash_cfg->secret_key[0] >> 33;
     395                 :            : 
     396                 :          0 :         data_padded[0] = hash_cfg->hash_mask[intf][hash_idx][0] & ldata[0];
     397                 :          0 :         data_padded[1] = hash_cfg->hash_mask[intf][hash_idx][1] & ldata[1];
     398                 :          0 :         field_hash = npc_toeplitz_hash(data_padded, hash_key, 128, 159);
     399                 :            : 
     400                 :          0 :         field_hash &= hash_cfg->hash_ctrl[intf][hash_idx] >> 32;
     401                 :          0 :         field_hash |= hash_cfg->hash_ctrl[intf][hash_idx];
     402                 :          0 :         return field_hash;
     403                 :            : }
     404                 :            : 
     405                 :            : static int
     406                 :          0 : npc_ipv6_field_hash_get(struct npc *npc, const uint32_t *ip6addr, uint8_t intf, int hash_idx,
     407                 :            :                         uint32_t *hash)
     408                 :            : {
     409                 :            : #define IPV6_WORDS 4
     410                 :            :         uint32_t ipv6_addr[IPV6_WORDS];
     411                 :            :         struct npc_hash_cfg hash_cfg;
     412                 :            :         uint64_t ldata[2];
     413                 :            :         int rc = 0;
     414                 :            : 
     415                 :          0 :         rc = npc_field_hash_secret_get(npc, &hash_cfg);
     416         [ #  # ]:          0 :         if (rc)
     417                 :            :                 return -1;
     418                 :            : 
     419                 :            :         be32_to_cpu_array(ipv6_addr, ip6addr, IPV6_WORDS);
     420                 :          0 :         ldata[0] = (uint64_t)ipv6_addr[2] << 32 | ipv6_addr[3];
     421                 :          0 :         ldata[1] = (uint64_t)ipv6_addr[0] << 32 | ipv6_addr[1];
     422                 :          0 :         *hash = npc_field_hash_calc(ldata, &hash_cfg, intf, hash_idx);
     423                 :            : 
     424                 :          0 :         return 0;
     425                 :            : }
     426                 :            : 
     427                 :            : static int
     428                 :          0 : npc_hash_field_get(struct npc_xtract_info *xinfo, const struct roc_npc_flow_item_ipv6 *ipv6_spec,
     429                 :            :                    const struct roc_npc_flow_item_ipv6 *ipv6_mask, uint8_t *hash_field)
     430                 :            : {
     431                 :            :         const uint8_t *ipv6_hdr_spec, *ipv6_hdr_mask;
     432                 :            :         struct roc_ipv6_hdr ipv6_buf;
     433         [ #  # ]:          0 :         int offset = xinfo->hdr_off;
     434                 :            : 
     435                 :            :         memset(&ipv6_buf, 0, sizeof(ipv6_buf));
     436                 :            : 
     437                 :          0 :         ipv6_hdr_spec = (const uint8_t *)&ipv6_spec->hdr;
     438                 :          0 :         ipv6_hdr_mask = (const uint8_t *)&ipv6_mask->hdr;
     439                 :            : 
     440                 :            :         /* Check if mask is set for the field to be hashed */
     441         [ #  # ]:          0 :         if (memcmp(ipv6_hdr_mask + offset, &ipv6_buf, ROC_IPV6_ADDR_LEN) == 0)
     442                 :            :                 return 0;
     443                 :            : 
     444                 :            :         /* Extract the field to be hashed from item spec */
     445                 :          0 :         memcpy(hash_field, ipv6_hdr_spec + offset, ROC_IPV6_ADDR_LEN);
     446                 :          0 :         return 1;
     447                 :            : }
     448                 :            : 
     449                 :            : static int
     450                 :          0 : npc_process_ipv6_field_hash_legacy(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
     451                 :            :                                    const struct roc_npc_flow_item_ipv6 *ipv6_mask,
     452                 :            :                                    struct npc_parse_state *pst, uint8_t ltype)
     453                 :            : {
     454                 :            :         struct npc_lid_lt_xtract_info *lid_lt_xinfo;
     455                 :            :         uint8_t hash_field[ROC_IPV6_ADDR_LEN];
     456                 :            :         struct npc_xtract_info *xinfo;
     457                 :            :         struct roc_ipv6_hdr ipv6_buf;
     458                 :          0 :         uint32_t hash = 0, mask;
     459                 :            :         int intf, i, rc = 0;
     460                 :            : 
     461                 :            :         memset(&ipv6_buf, 0, sizeof(ipv6_buf));
     462                 :            :         memset(hash_field, 0, sizeof(hash_field));
     463                 :            : 
     464                 :          0 :         intf = pst->nix_intf;
     465                 :          0 :         lid_lt_xinfo = &pst->npc->prx_dxcfg[intf][NPC_LID_LC][ltype];
     466                 :            : 
     467         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_LD; i++) {
     468                 :          0 :                 xinfo = &lid_lt_xinfo->xtract[i];
     469         [ #  # ]:          0 :                 if (!xinfo->use_hash)
     470                 :          0 :                         continue;
     471                 :            : 
     472                 :          0 :                 rc = npc_hash_field_get(xinfo, ipv6_spec, ipv6_mask, hash_field);
     473         [ #  # ]:          0 :                 if (rc == 0)
     474                 :          0 :                         continue;
     475                 :            : 
     476                 :          0 :                 rc = npc_ipv6_field_hash_get(pst->npc, (const uint32_t *)hash_field, intf, i,
     477                 :            :                                              &hash);
     478         [ #  # ]:          0 :                 if (rc)
     479                 :          0 :                         return rc;
     480                 :            : 
     481                 :          0 :                 mask = GENMASK(31, 0);
     482                 :          0 :                 memcpy(pst->mcam_mask + xinfo->key_off, (uint8_t *)&mask, 4);
     483                 :          0 :                 memcpy(pst->mcam_data + xinfo->key_off, (uint8_t *)&hash, 4);
     484                 :            :         }
     485                 :            : 
     486                 :            :         return 0;
     487                 :            : }
     488                 :            : 
     489                 :            : static int
     490                 :          0 : npc_process_ipv6_field_hash_o20k(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
     491                 :            :                                  const struct roc_npc_flow_item_ipv6 *ipv6_mask,
     492                 :            :                                  struct npc_parse_state *pst, uint8_t ltype)
     493                 :            : {
     494                 :            :         struct npc_lid_lt_xtract_info_cn20k *lid_lt_xinfo;
     495                 :            :         union npc_kex_ldata_flags_cfg *lid_cfg;
     496                 :            :         uint8_t hash_field[ROC_IPV6_ADDR_LEN];
     497                 :            :         struct npc_xtract_info *xinfo;
     498                 :            :         struct roc_ipv6_hdr ipv6_buf;
     499                 :          0 :         uint32_t hash = 0, mask;
     500                 :            :         int intf, i, rc = 0;
     501                 :            : 
     502                 :            :         memset(&ipv6_buf, 0, sizeof(ipv6_buf));
     503                 :            :         memset(hash_field, 0, sizeof(hash_field));
     504                 :            : 
     505                 :          0 :         intf = pst->nix_intf;
     506         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_EXTRACTTORS; i++) {
     507                 :          0 :                 lid_cfg = &pst->npc->lid_cfg[intf][i];
     508         [ #  # ]:          0 :                 if (lid_cfg->s.lid != NPC_LID_LC)
     509                 :          0 :                         continue;
     510                 :          0 :                 lid_lt_xinfo = &pst->npc->prx_dxcfg_cn20k[intf][NPC_LID_LC][ltype];
     511                 :            : 
     512                 :          0 :                 xinfo = &lid_lt_xinfo->xtract;
     513         [ #  # ]:          0 :                 if (!xinfo->use_hash)
     514                 :          0 :                         continue;
     515                 :            : 
     516                 :          0 :                 rc = npc_hash_field_get(xinfo, ipv6_spec, ipv6_mask, hash_field);
     517         [ #  # ]:          0 :                 if (rc == 0)
     518                 :          0 :                         continue;
     519                 :            : 
     520                 :          0 :                 rc = npc_ipv6_field_hash_get(pst->npc, (const uint32_t *)hash_field, intf, i,
     521                 :            :                                              &hash);
     522         [ #  # ]:          0 :                 if (rc)
     523                 :          0 :                         return rc;
     524                 :            : 
     525                 :          0 :                 mask = GENMASK(31, 0);
     526                 :          0 :                 memcpy(pst->mcam_mask + xinfo->key_off, (uint8_t *)&mask, 4);
     527                 :          0 :                 memcpy(pst->mcam_data + xinfo->key_off, (uint8_t *)&hash, 4);
     528                 :            :         }
     529                 :            : 
     530                 :            :         return 0;
     531                 :            : }
     532                 :            : 
     533                 :            : int
     534         [ #  # ]:          0 : npc_process_ipv6_field_hash(const struct roc_npc_flow_item_ipv6 *ipv6_spec,
     535                 :            :                             const struct roc_npc_flow_item_ipv6 *ipv6_mask,
     536                 :            :                             struct npc_parse_state *pst, uint8_t ltype)
     537                 :            : {
     538         [ #  # ]:          0 :         if (!roc_model_is_cn20k())
     539                 :          0 :                 return npc_process_ipv6_field_hash_legacy(ipv6_spec, ipv6_mask, pst, ltype);
     540                 :            :         else
     541                 :          0 :                 return npc_process_ipv6_field_hash_o20k(ipv6_spec, ipv6_mask, pst, ltype);
     542                 :            : }
     543                 :            : 
     544                 :            : static int
     545                 :          0 : npc_update_parse_state_legacy(struct npc_parse_state *pst, struct npc_parse_item_info *info,
     546                 :            :                               int lid, int lt, uint8_t flags)
     547                 :            : {
     548                 :            :         struct npc_lid_lt_xtract_info *xinfo;
     549                 :            :         struct roc_npc_flow_dump_data *dump;
     550                 :            :         struct npc_xtract_info *lfinfo;
     551                 :            :         int intf, lf_cfg;
     552                 :            :         int i, j, rc = 0;
     553                 :            : 
     554                 :          0 :         pst->layer_mask |= lid;
     555                 :          0 :         pst->lt[lid] = lt;
     556                 :          0 :         pst->flags[lid] = flags;
     557                 :            : 
     558                 :          0 :         intf = pst->nix_intf;
     559                 :          0 :         xinfo = &pst->npc->prx_dxcfg[intf][lid][lt];
     560         [ #  # ]:          0 :         if (xinfo->is_terminating)
     561                 :          0 :                 pst->terminate = 1;
     562                 :            : 
     563         [ #  # ]:          0 :         if (info->spec == NULL)
     564                 :          0 :                 goto done;
     565                 :            : 
     566         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_LD; i++) {
     567         [ #  # ]:          0 :                 if (xinfo->xtract[i].use_hash)
     568                 :          0 :                         continue;
     569                 :          0 :                 rc = npc_update_extraction_data(pst, info, &xinfo->xtract[i]);
     570         [ #  # ]:          0 :                 if (rc != 0)
     571                 :          0 :                         return rc;
     572                 :            :         }
     573                 :            : 
     574         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_LD; i++) {
     575         [ #  # ]:          0 :                 if (xinfo->xtract[i].flags_enable == 0)
     576                 :          0 :                         continue;
     577         [ #  # ]:          0 :                 if (xinfo->xtract[i].use_hash)
     578                 :          0 :                         continue;
     579                 :            : 
     580                 :          0 :                 lf_cfg = pst->npc->prx_lfcfg[i].i;
     581         [ #  # ]:          0 :                 if (lf_cfg == lid) {
     582         [ #  # ]:          0 :                         for (j = 0; j < NPC_MAX_LFL; j++) {
     583                 :          0 :                                 lfinfo = pst->npc->prx_fxcfg[intf][i][j].xtract;
     584                 :          0 :                                 rc = npc_update_extraction_data(pst, info, &lfinfo[0]);
     585         [ #  # ]:          0 :                                 if (rc != 0)
     586                 :          0 :                                         return rc;
     587                 :            : 
     588         [ #  # ]:          0 :                                 if (lfinfo[0].enable)
     589                 :          0 :                                         pst->flags[lid] = j;
     590                 :            :                         }
     591                 :            :                 }
     592                 :            :         }
     593                 :            : 
     594                 :          0 : done:
     595                 :          0 :         dump = &pst->flow->dump_data[pst->flow->num_patterns++];
     596                 :          0 :         dump->lid = lid;
     597                 :          0 :         dump->ltype = lt;
     598                 :          0 :         pst->pattern++;
     599                 :          0 :         return 0;
     600                 :            : }
     601                 :            : 
     602                 :            : static int
     603                 :          0 : npc_update_parse_state_o20(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
     604                 :            :                            int lt, uint8_t flags)
     605                 :            : {
     606                 :            :         struct npc_lid_lt_xtract_info_cn20k *xinfo;
     607                 :            :         union npc_kex_ldata_flags_cfg *lid_cfg;
     608                 :            :         struct roc_npc_flow_dump_data *dump;
     609                 :            :         int intf;
     610                 :            :         int i, rc = 0;
     611                 :            : 
     612                 :          0 :         pst->layer_mask |= lid;
     613                 :          0 :         pst->lt[lid] = lt;
     614                 :          0 :         pst->flags[lid] = flags;
     615                 :            : 
     616                 :          0 :         intf = pst->nix_intf;
     617         [ #  # ]:          0 :         if (info->spec == NULL)
     618                 :          0 :                 goto done;
     619                 :            : 
     620         [ #  # ]:          0 :         for (i = 0; i < NPC_MAX_EXTRACTTORS; i++) {
     621                 :          0 :                 lid_cfg = &pst->npc->lid_cfg[intf][i];
     622         [ #  # ]:          0 :                 if (lid_cfg->s.lid != lid)
     623                 :          0 :                         continue;
     624                 :            :                 xinfo = &pst->npc->prx_dxcfg_cn20k[intf][i][lt];
     625         [ #  # ]:          0 :                 if (xinfo->is_terminating)
     626                 :          0 :                         pst->terminate = 1;
     627                 :            : 
     628         [ #  # ]:          0 :                 if (xinfo->xtract.use_hash)
     629                 :          0 :                         continue;
     630                 :          0 :                 rc = npc_update_extraction_data(pst, info, &xinfo->xtract);
     631         [ #  # ]:          0 :                 if (rc != 0)
     632                 :          0 :                         return rc;
     633                 :            :         }
     634                 :            : 
     635                 :          0 : done:
     636                 :          0 :         dump = &pst->flow->dump_data[pst->flow->num_patterns++];
     637                 :          0 :         dump->lid = lid;
     638                 :          0 :         dump->ltype = lt;
     639                 :          0 :         pst->pattern++;
     640                 :          0 :         return 0;
     641                 :            : }
     642                 :            : 
     643                 :            : int
     644         [ #  # ]:          0 : npc_update_parse_state(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
     645                 :            :                        int lt, uint8_t flags)
     646                 :            : {
     647         [ #  # ]:          0 :         if (roc_model_is_cn20k())
     648                 :          0 :                 return npc_update_parse_state_o20(pst, info, lid, lt, flags);
     649                 :            :         else
     650                 :          0 :                 return npc_update_parse_state_legacy(pst, info, lid, lt, flags);
     651                 :            : }
     652                 :            : 
     653                 :            : int
     654                 :          0 : npc_mcam_init(struct npc *npc, struct roc_npc_flow *flow, int mcam_id)
     655                 :            : {
     656                 :            :         struct msg_rsp *rsp;
     657                 :          0 :         struct mbox *mbox = mbox_get(npc->mbox);
     658                 :            :         int rc = 0, idx;
     659                 :            : 
     660         [ #  # ]:          0 :         if (roc_model_is_cn20k()) {
     661                 :            :                 struct npc_cn20k_mcam_write_entry_req *req;
     662                 :            : 
     663                 :          0 :                 req = mbox_alloc_msg_npc_cn20k_mcam_write_entry(mbox);
     664         [ #  # ]:          0 :                 if (req == NULL) {
     665                 :            :                         rc = -ENOSPC;
     666                 :          0 :                         goto exit;
     667                 :            :                 }
     668                 :          0 :                 req->cntr = 0;
     669                 :          0 :                 req->entry = mcam_id;
     670                 :            : 
     671                 :          0 :                 req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
     672                 :          0 :                 req->enable_entry = 1;
     673                 :          0 :                 req->entry_data.action = flow->npc_action;
     674                 :          0 :                 req->entry_data.vtag_action = flow->vtag_action;
     675                 :            : 
     676         [ #  # ]:          0 :                 for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
     677                 :          0 :                         req->entry_data.kw[idx] = 0x0;
     678                 :          0 :                         req->entry_data.kw_mask[idx] = 0x0;
     679                 :            :                 }
     680                 :            : 
     681         [ #  # ]:          0 :                 if (flow->nix_intf == NIX_INTF_RX) {
     682                 :          0 :                         req->entry_data.kw[0] |= (uint64_t)npc->channel;
     683                 :          0 :                         req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
     684                 :            :                 } else {
     685                 :          0 :                         uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
     686                 :            : 
     687         [ #  # ]:          0 :                         pf_func = plt_cpu_to_be_16(pf_func);
     688                 :          0 :                         req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
     689                 :          0 :                         req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
     690                 :            :                 }
     691                 :            :         } else {
     692                 :            :                 struct npc_mcam_write_entry_req *req;
     693                 :            : 
     694                 :          0 :                 req = mbox_alloc_msg_npc_mcam_write_entry(mbox);
     695         [ #  # ]:          0 :                 if (req == NULL) {
     696                 :            :                         rc = -ENOSPC;
     697                 :          0 :                         goto exit;
     698                 :            :                 }
     699                 :          0 :                 req->set_cntr = 0;
     700                 :          0 :                 req->cntr = 0;
     701                 :          0 :                 req->entry = mcam_id;
     702                 :            : 
     703                 :          0 :                 req->intf = (flow->nix_intf == NIX_INTF_RX) ? NPC_MCAM_RX : NPC_MCAM_TX;
     704                 :          0 :                 req->enable_entry = 1;
     705                 :          0 :                 req->entry_data.action = flow->npc_action;
     706                 :          0 :                 req->entry_data.vtag_action = flow->vtag_action;
     707                 :            : 
     708         [ #  # ]:          0 :                 for (idx = 0; idx < ROC_NPC_MAX_MCAM_WIDTH_DWORDS; idx++) {
     709                 :          0 :                         req->entry_data.kw[idx] = 0x0;
     710                 :          0 :                         req->entry_data.kw_mask[idx] = 0x0;
     711                 :            :                 }
     712                 :            : 
     713         [ #  # ]:          0 :                 if (flow->nix_intf == NIX_INTF_RX) {
     714                 :          0 :                         req->entry_data.kw[0] |= (uint64_t)npc->channel;
     715                 :          0 :                         req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
     716                 :            :                 } else {
     717                 :          0 :                         uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
     718                 :            : 
     719         [ #  # ]:          0 :                         pf_func = plt_cpu_to_be_16(pf_func);
     720                 :          0 :                         req->entry_data.kw[0] |= ((uint64_t)pf_func << 32);
     721                 :          0 :                         req->entry_data.kw_mask[0] |= ((uint64_t)0xffff << 32);
     722                 :            :                 }
     723                 :            :         }
     724                 :            : 
     725                 :            :         rc = mbox_process_msg(mbox, (void *)&rsp);
     726         [ #  # ]:          0 :         if (rc != 0) {
     727                 :          0 :                 plt_err("npc: mcam initialisation write failed");
     728                 :          0 :                 goto exit;
     729                 :            :         }
     730                 :            :         rc = 0;
     731                 :          0 : exit:
     732                 :            :         mbox_put(mbox);
     733                 :          0 :         return rc;
     734                 :            : }
     735                 :            : 
     736                 :            : int
     737                 :          0 : npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent)
     738                 :            : {
     739                 :            :         struct npc_mcam_shift_entry_req *req;
     740                 :            :         struct npc_mcam_shift_entry_rsp *rsp;
     741                 :            :         int rc = -ENOSPC;
     742                 :            : 
     743                 :            :         /* Old entry is disabled & it's contents are moved to new_entry,
     744                 :            :          * new entry is enabled finally.
     745                 :            :          */
     746                 :          0 :         req = mbox_alloc_msg_npc_mcam_shift_entry(mbox_get(mbox));
     747         [ #  # ]:          0 :         if (req == NULL)
     748                 :          0 :                 goto exit;
     749                 :          0 :         req->curr_entry[0] = old_ent;
     750                 :          0 :         req->new_entry[0] = new_ent;
     751                 :          0 :         req->shift_count = 1;
     752                 :            : 
     753                 :            :         rc = mbox_process_msg(mbox, (void *)&rsp);
     754         [ #  # ]:          0 :         if (rc)
     755                 :          0 :                 goto exit;
     756                 :            : 
     757                 :            :         rc = 0;
     758                 :          0 : exit:
     759                 :            :         mbox_put(mbox);
     760                 :          0 :         return rc;
     761                 :            : }
     762                 :            : 
     763                 :            : enum SHIFT_DIR {
     764                 :            :         SLIDE_ENTRIES_TO_LOWER_INDEX,
     765                 :            :         SLIDE_ENTRIES_TO_HIGHER_INDEX,
     766                 :            : };
     767                 :            : 
     768                 :            : static int
     769                 :          0 : npc_slide_mcam_entries(struct mbox *mbox, struct npc *npc, int prio,
     770                 :            :                        uint16_t *free_mcam_id, int dir)
     771                 :            : {
     772                 :            :         uint16_t to_mcam_id = 0, from_mcam_id = 0;
     773                 :            :         struct npc_prio_flow_list_head *list;
     774                 :            :         struct npc_prio_flow_entry *curr = 0;
     775                 :            :         int rc = 0;
     776                 :            : 
     777                 :          0 :         list = &npc->prio_flow_list[prio];
     778                 :            : 
     779                 :          0 :         to_mcam_id = *free_mcam_id;
     780         [ #  # ]:          0 :         if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
     781                 :          0 :                 curr = TAILQ_LAST(list, npc_prio_flow_list_head);
     782         [ #  # ]:          0 :         else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
     783                 :          0 :                 curr = TAILQ_FIRST(list);
     784                 :            : 
     785         [ #  # ]:          0 :         while (curr) {
     786                 :          0 :                 from_mcam_id = curr->flow->mcam_id;
     787                 :          0 :                 if ((dir == SLIDE_ENTRIES_TO_HIGHER_INDEX &&
     788         [ #  # ]:          0 :                      from_mcam_id < to_mcam_id) ||
     789                 :          0 :                     (dir == SLIDE_ENTRIES_TO_LOWER_INDEX &&
     790         [ #  # ]:          0 :                      from_mcam_id > to_mcam_id)) {
     791                 :            :                         /* Newly allocated entry and the source entry given to
     792                 :            :                          * npc_mcam_shift_entry_req will be in disabled state.
     793                 :            :                          * Initialise and enable before moving an entry into
     794                 :            :                          * this mcam.
     795                 :            :                          */
     796                 :          0 :                         rc = npc_mcam_init(npc, curr->flow, to_mcam_id);
     797         [ #  # ]:          0 :                         if (rc)
     798                 :          0 :                                 return rc;
     799                 :          0 :                         rc = npc_mcam_move(mbox, from_mcam_id, to_mcam_id);
     800         [ #  # ]:          0 :                         if (rc)
     801                 :          0 :                                 return rc;
     802                 :          0 :                         curr->flow->mcam_id = to_mcam_id;
     803                 :            :                         to_mcam_id = from_mcam_id;
     804                 :            :                 }
     805                 :            : 
     806         [ #  # ]:          0 :                 if (dir == SLIDE_ENTRIES_TO_HIGHER_INDEX)
     807                 :          0 :                         curr = TAILQ_PREV(curr, npc_prio_flow_list_head, next);
     808         [ #  # ]:          0 :                 else if (dir == SLIDE_ENTRIES_TO_LOWER_INDEX)
     809                 :          0 :                         curr = TAILQ_NEXT(curr, next);
     810                 :            :         }
     811                 :            : 
     812                 :          0 :         *free_mcam_id = from_mcam_id;
     813                 :            : 
     814                 :          0 :         return 0;
     815                 :            : }
     816                 :            : 
     817                 :            : /*
     818                 :            :  * The mcam_alloc request is first made with NPC_MCAM_LOWER_PRIO with the last
     819                 :            :  * entry in the requested priority level as the reference entry. If it fails,
     820                 :            :  * the alloc request is retried with NPC_MCAM_HIGHER_PRIO with the first entry
     821                 :            :  * in the next lower priority level as the reference entry. After obtaining
     822                 :            :  * the free MCAM from kernel, we check if it is at the right user requested
     823                 :            :  * priority level. If not, the flow rules are moved across MCAM entries till
     824                 :            :  * the user requested priority levels are met.
     825                 :            :  * The MCAM sorting algorithm works as below.
     826                 :            :  * For any given free MCAM obtained from the kernel, there are 3 possibilities.
     827                 :            :  * Case 1:
     828                 :            :  * There are entries belonging to higher user priority level (numerically
     829                 :            :  * lesser) in higher mcam indices. In this case, the entries with higher user
     830                 :            :  * priority are slided towards lower indices and a free entry is created in the
     831                 :            :  * higher indices.
     832                 :            :  * Example:
     833                 :            :  * Assume free entry = 1610, user requested priority = 2 and
     834                 :            :  * max user priority levels = 5 with below entries in respective priority
     835                 :            :  * levels.
     836                 :            :  * 0: 1630, 1635, 1641
     837                 :            :  * 1: 1646, 1650, 1651
     838                 :            :  * 2: 1652, 1655, 1660
     839                 :            :  * 3: 1661, 1662, 1663, 1664
     840                 :            :  * 4: 1665, 1667, 1670
     841                 :            :  *
     842                 :            :  * Entries (1630, 1635, 1641, 1646, 1650, 1651) have to be slided down towards
     843                 :            :  * lower indices.
     844                 :            :  * Shifting sequence will be as below:
     845                 :            :  *     1610 <- 1630 <- 1635 <- 1641 <- 1646 <- 1650 <- 1651
     846                 :            :  * Entry 1651 will be free-ed for writing the new flow. This entry will now
     847                 :            :  * become the head of priority level 2.
     848                 :            :  *
     849                 :            :  * Case 2:
     850                 :            :  * There are entries belonging to lower user priority level (numerically
     851                 :            :  * bigger) in lower mcam indices. In this case, the entries with lower user
     852                 :            :  * priority are slided towards higher indices and a free entry is created in the
     853                 :            :  * lower indices.
     854                 :            :  *
     855                 :            :  * Example:
     856                 :            :  * free entry = 1653, user requested priority = 0
     857                 :            :  * 0: 1630, 1635, 1641
     858                 :            :  * 1: 1646, 1650, 1651
     859                 :            :  * 2: 1652, 1655, 1660
     860                 :            :  * 3: 1661, 1662, 1663, 1664
     861                 :            :  * 4: 1665, 1667, 1670
     862                 :            :  *
     863                 :            :  * Entries (1646, 1650, 1651, 1652) have to be slided up towards higher
     864                 :            :  * indices.
     865                 :            :  * Shifting sequence will be as below:
     866                 :            :  *     1646 -> 1650 -> 1651 -> 1652 -> 1653
     867                 :            :  * Entry 1646 will be free-ed for writing the new flow. This entry will now
     868                 :            :  * become the last element in priority level 0.
     869                 :            :  *
     870                 :            :  * Case 3:
     871                 :            :  * Free mcam is at the right place, ie, all higher user priority level
     872                 :            :  * mcams lie in lower indices and all lower user priority level mcams lie in
     873                 :            :  * higher mcam indices.
     874                 :            :  *
     875                 :            :  * The priority level lists are scanned first for case (1) and if the
     876                 :            :  * condition is found true, case(2) is skipped because they are mutually
     877                 :            :  * exclusive. For example, consider below state.
     878                 :            :  * 0: 1630, 1635, 1641
     879                 :            :  * 1: 1646, 1650, 1651
     880                 :            :  * 2: 1652, 1655, 1660
     881                 :            :  * 3: 1661, 1662, 1663, 1664
     882                 :            :  * 4: 1665, 1667, 1670
     883                 :            :  * free entry = 1610, user requested priority = 2
     884                 :            :  *
     885                 :            :  * Case 1: Here the condition is;
     886                 :            :  * "if (requested_prio > prio_idx && free_mcam < tail->flow->mcam_id ){}"
     887                 :            :  * If this condition is true, it means at some higher priority level than
     888                 :            :  * requested priority level, there are entries at lower indices than the given
     889                 :            :  * free mcam. That is, we have found in levels 0,1 there is an mcam X which is
     890                 :            :  * greater than 1610.
     891                 :            :  * If, for any free entry and user req prio, the above condition is true, then
     892                 :            :  * the below case(2) condition will always be false since the lists are kept
     893                 :            :  * sorted. The case(2) condition is;
     894                 :            :  *  "if (requested_prio < prio_idx && free_mcam > head->flow->mcam_id){}"
     895                 :            :  * There can't be entries at lower indices at priority level higher
     896                 :            :  * than the requested priority level. That is, here, at levels 3 & 4 there
     897                 :            :  * cannot be any entry greater than 1610. Because all entries in 3 & 4 must be
     898                 :            :  * greater than X which was found to be greater than 1610 earlier.
     899                 :            :  */
     900                 :            : 
     901                 :            : static int
     902                 :          0 : npc_sort_mcams_by_user_prio_level(struct mbox *mbox,
     903                 :            :                                   struct npc_prio_flow_entry *flow_list_entry,
     904                 :            :                                   struct npc *npc,
     905                 :            :                                   struct npc_mcam_alloc_entry_rsp *rsp)
     906                 :            : {
     907                 :          0 :         int requested_prio = flow_list_entry->flow->priority;
     908                 :            :         struct npc_prio_flow_entry *head, *tail;
     909                 :            :         struct npc_prio_flow_list_head *list;
     910                 :          0 :         uint16_t free_mcam = rsp->entry;
     911                 :            :         bool do_reverse_scan = true;
     912                 :            :         int prio_idx = 0, rc = 0;
     913                 :            : 
     914         [ #  # ]:          0 :         while (prio_idx <= npc->flow_max_priority - 1) {
     915                 :          0 :                 list = &npc->prio_flow_list[prio_idx];
     916                 :          0 :                 tail = TAILQ_LAST(list, npc_prio_flow_list_head);
     917                 :            : 
     918                 :            :                 /* requested priority is lower than current level
     919                 :            :                  * ie, numerically req prio is higher
     920                 :            :                  */
     921         [ #  # ]:          0 :                 if ((requested_prio > prio_idx) && tail) {
     922                 :            :                         /* but there are some mcams in current level
     923                 :            :                          * at higher indices, ie, at priority lower
     924                 :            :                          * than free_mcam.
     925                 :            :                          */
     926         [ #  # ]:          0 :                         if (free_mcam < tail->flow->mcam_id) {
     927                 :          0 :                                 rc = npc_slide_mcam_entries(
     928                 :            :                                         mbox, npc, prio_idx, &free_mcam,
     929                 :            :                                         SLIDE_ENTRIES_TO_LOWER_INDEX);
     930         [ #  # ]:          0 :                                 if (rc)
     931                 :          0 :                                         return rc;
     932                 :            :                                 do_reverse_scan = false;
     933                 :            :                         }
     934                 :            :                 }
     935                 :          0 :                 prio_idx++;
     936                 :            :         }
     937                 :            : 
     938                 :          0 :         prio_idx = npc->flow_max_priority - 1;
     939         [ #  # ]:          0 :         while (prio_idx && do_reverse_scan) {
     940                 :          0 :                 list = &npc->prio_flow_list[prio_idx];
     941                 :          0 :                 head = TAILQ_FIRST(list);
     942                 :            : 
     943                 :            :                 /* requested priority is higher than current level
     944                 :            :                  * ie, numerically req prio is lower
     945                 :            :                  */
     946         [ #  # ]:          0 :                 if (requested_prio < prio_idx && head) {
     947                 :            :                         /* but free mcam is higher than lowest priority
     948                 :            :                          * mcam in current level
     949                 :            :                          */
     950         [ #  # ]:          0 :                         if (free_mcam > head->flow->mcam_id) {
     951                 :          0 :                                 rc = npc_slide_mcam_entries(
     952                 :            :                                         mbox, npc, prio_idx, &free_mcam,
     953                 :            :                                         SLIDE_ENTRIES_TO_HIGHER_INDEX);
     954         [ #  # ]:          0 :                                 if (rc)
     955                 :          0 :                                         return rc;
     956                 :            :                         }
     957                 :            :                 }
     958                 :          0 :                 prio_idx--;
     959                 :            :         }
     960                 :          0 :         rsp->entry = free_mcam;
     961                 :          0 :         return rc;
     962                 :            : }
     963                 :            : 
     964                 :            : static void
     965                 :          0 : npc_insert_into_flow_list(struct npc *npc, struct npc_prio_flow_entry *entry)
     966                 :            : {
     967                 :            :         struct npc_prio_flow_list_head *list;
     968                 :            :         struct npc_prio_flow_entry *curr;
     969                 :            : 
     970                 :          0 :         list = &npc->prio_flow_list[entry->flow->priority];
     971                 :          0 :         curr = TAILQ_FIRST(list);
     972                 :            : 
     973         [ #  # ]:          0 :         if (curr) {
     974         [ #  # ]:          0 :                 while (curr) {
     975         [ #  # ]:          0 :                         if (entry->flow->mcam_id > curr->flow->mcam_id)
     976                 :          0 :                                 curr = TAILQ_NEXT(curr, next);
     977                 :            :                         else
     978                 :            :                                 break;
     979                 :            :                 }
     980         [ #  # ]:          0 :                 if (curr)
     981                 :          0 :                         TAILQ_INSERT_BEFORE(curr, entry, next);
     982                 :            :                 else
     983                 :          0 :                         TAILQ_INSERT_TAIL(list, entry, next);
     984                 :            :         } else {
     985                 :          0 :                 TAILQ_INSERT_HEAD(list, entry, next);
     986                 :            :         }
     987                 :          0 : }
     988                 :            : 
     989                 :            : static int
     990                 :          0 : npc_allocate_mcam_entry(struct mbox *mbox, int prio, struct npc_mcam_alloc_entry_rsp *rsp_local,
     991                 :            :                         int ref_entry, uint8_t kw_type)
     992                 :            : {
     993                 :            :         struct npc_mcam_alloc_entry_rsp *rsp;
     994                 :            :         struct npc_mcam_alloc_entry_req *req;
     995                 :            : 
     996                 :            :         int rc = -ENOSPC;
     997                 :            : 
     998                 :          0 :         req = mbox_alloc_msg_npc_mcam_alloc_entry(mbox_get(mbox));
     999         [ #  # ]:          0 :         if (req == NULL)
    1000                 :          0 :                 goto exit;
    1001                 :          0 :         req->contig = 1;
    1002                 :          0 :         req->count = 1;
    1003                 :          0 :         req->ref_priority = prio;
    1004                 :          0 :         req->ref_entry = ref_entry;
    1005                 :          0 :         req->kw_type = kw_type;
    1006                 :            : 
    1007                 :            :         rc = mbox_process_msg(mbox, (void *)&rsp);
    1008         [ #  # ]:          0 :         if (rc)
    1009                 :          0 :                 goto exit;
    1010                 :            : 
    1011         [ #  # ]:          0 :         if (!rsp->count) {
    1012                 :            :                 rc = -ENOSPC;
    1013                 :          0 :                 goto exit;
    1014                 :            :         }
    1015                 :            : 
    1016                 :            :         mbox_memcpy(rsp_local, rsp, sizeof(*rsp));
    1017                 :            :         rc = 0;
    1018                 :          0 : exit:
    1019                 :            :         mbox_put(mbox);
    1020                 :          0 :         return rc;
    1021                 :            : }
    1022                 :            : 
    1023                 :            : static void
    1024                 :          0 : npc_find_mcam_ref_entry(struct roc_npc_flow *flow, struct npc *npc, int *prio,
    1025                 :            :                         int *ref_entry, int dir)
    1026                 :            : {
    1027                 :            :         struct npc_prio_flow_entry *head, *tail;
    1028                 :            :         struct npc_prio_flow_list_head *list;
    1029                 :          0 :         int prio_idx = flow->priority;
    1030                 :            : 
    1031         [ #  # ]:          0 :         if (dir == NPC_MCAM_LOWER_PRIO) {
    1032         [ #  # ]:          0 :                 while (prio_idx >= 0) {
    1033                 :          0 :                         list = &npc->prio_flow_list[prio_idx];
    1034                 :          0 :                         head = TAILQ_FIRST(list);
    1035         [ #  # ]:          0 :                         if (head) {
    1036                 :          0 :                                 *prio = NPC_MCAM_LOWER_PRIO;
    1037                 :          0 :                                 *ref_entry = head->flow->mcam_id;
    1038                 :          0 :                                 return;
    1039                 :            :                         }
    1040                 :          0 :                         prio_idx--;
    1041                 :            :                 }
    1042         [ #  # ]:          0 :         } else if (dir == NPC_MCAM_HIGHER_PRIO) {
    1043                 :            :                 prio_idx = flow->priority;
    1044         [ #  # ]:          0 :                 while (prio_idx <= npc->flow_max_priority - 1) {
    1045                 :          0 :                         list = &npc->prio_flow_list[prio_idx];
    1046                 :          0 :                         tail = TAILQ_LAST(list, npc_prio_flow_list_head);
    1047         [ #  # ]:          0 :                         if (tail) {
    1048                 :          0 :                                 *prio = NPC_MCAM_HIGHER_PRIO;
    1049                 :          0 :                                 *ref_entry = tail->flow->mcam_id;
    1050                 :          0 :                                 return;
    1051                 :            :                         }
    1052                 :          0 :                         prio_idx++;
    1053                 :            :                 }
    1054                 :            :         }
    1055                 :          0 :         *prio = NPC_MCAM_ANY_PRIO;
    1056                 :          0 :         *ref_entry = 0;
    1057                 :            : }
    1058                 :            : 
    1059                 :            : static int
    1060                 :          0 : npc_alloc_mcam_by_ref_entry(struct mbox *mbox, struct roc_npc_flow *flow, struct npc *npc,
    1061                 :            :                             struct npc_mcam_alloc_entry_rsp *rsp_local)
    1062                 :            : {
    1063                 :          0 :         int prio, ref_entry = 0, rc = 0, dir = NPC_MCAM_LOWER_PRIO;
    1064                 :            :         bool retry_done = false;
    1065                 :            : 
    1066                 :          0 : retry:
    1067                 :          0 :         npc_find_mcam_ref_entry(flow, npc, &prio, &ref_entry, dir);
    1068                 :          0 :         rc = npc_allocate_mcam_entry(mbox, prio, rsp_local, ref_entry, flow->key_type);
    1069         [ #  # ]:          0 :         if (rc && !retry_done) {
    1070                 :          0 :                 plt_npc_dbg(
    1071                 :            :                         "npc: Failed to allocate lower priority entry. Retrying for higher priority");
    1072                 :            : 
    1073                 :            :                 dir = NPC_MCAM_HIGHER_PRIO;
    1074                 :            :                 retry_done = true;
    1075                 :          0 :                 goto retry;
    1076         [ #  # ]:          0 :         } else if (rc && retry_done) {
    1077                 :          0 :                 return rc;
    1078                 :            :         }
    1079                 :            : 
    1080                 :            :         return 0;
    1081                 :            : }
    1082                 :            : 
    1083                 :            : int
    1084                 :          0 : npc_get_free_mcam_entry(struct mbox *mbox, struct roc_npc_flow *flow, struct npc *npc)
    1085                 :            : {
    1086                 :            :         struct npc_mcam_alloc_entry_rsp rsp_local;
    1087                 :            :         struct npc_prio_flow_entry *new_entry;
    1088                 :            :         int rc = 0;
    1089                 :            : 
    1090                 :          0 :         new_entry = plt_zmalloc(sizeof(*new_entry), 0);
    1091         [ #  # ]:          0 :         if (!new_entry)
    1092                 :            :                 return -ENOSPC;
    1093                 :            : 
    1094         [ #  # ]:          0 :         if (roc_model_is_cn20k()) {
    1095                 :          0 :                 rc = npc_allocate_mcam_entry(mbox, NPC_MCAM_ANY_PRIO, &rsp_local, 0,
    1096                 :          0 :                                              flow->key_type);
    1097         [ #  # ]:          0 :                 if (rc) {
    1098                 :          0 :                         plt_npc_dbg("npc: failed to allocate MCAM entry.");
    1099                 :          0 :                         return rc;
    1100                 :            :                 }
    1101                 :            : 
    1102                 :          0 :                 new_entry->flow = flow;
    1103                 :            :         } else {
    1104                 :          0 :                 rc = npc_alloc_mcam_by_ref_entry(mbox, flow, npc, &rsp_local);
    1105                 :            : 
    1106         [ #  # ]:          0 :                 if (rc)
    1107                 :            :                         return rc;
    1108                 :            : 
    1109                 :          0 :                 new_entry->flow = flow;
    1110                 :            : 
    1111                 :          0 :                 plt_npc_dbg("kernel allocated MCAM entry %d", rsp_local.entry);
    1112                 :            : 
    1113                 :          0 :                 rc = npc_sort_mcams_by_user_prio_level(mbox, new_entry, npc, &rsp_local);
    1114         [ #  # ]:          0 :                 if (rc)
    1115                 :          0 :                         goto err;
    1116                 :            : 
    1117                 :          0 :                 plt_npc_dbg("allocated MCAM entry after sorting %d", rsp_local.entry);
    1118                 :            :         }
    1119                 :            : 
    1120                 :          0 :         flow->mcam_id = rsp_local.entry;
    1121                 :          0 :         npc_insert_into_flow_list(npc, new_entry);
    1122                 :            : 
    1123                 :          0 :         return rsp_local.entry;
    1124                 :            : err:
    1125                 :          0 :         plt_free(new_entry);
    1126                 :          0 :         return rc;
    1127                 :            : }
    1128                 :            : 
    1129                 :            : void
    1130                 :          0 : npc_delete_prio_list_entry(struct npc *npc, struct roc_npc_flow *flow)
    1131                 :            : {
    1132                 :            :         struct npc_prio_flow_list_head *list;
    1133                 :            :         struct npc_prio_flow_entry *curr;
    1134                 :            : 
    1135                 :          0 :         list = &npc->prio_flow_list[flow->priority];
    1136                 :          0 :         curr = TAILQ_FIRST(list);
    1137                 :            : 
    1138         [ #  # ]:          0 :         if (!curr)
    1139                 :            :                 return;
    1140                 :            : 
    1141         [ #  # ]:          0 :         while (curr) {
    1142         [ #  # ]:          0 :                 if (flow->mcam_id == curr->flow->mcam_id) {
    1143         [ #  # ]:          0 :                         TAILQ_REMOVE(list, curr, next);
    1144                 :          0 :                         plt_free(curr);
    1145                 :          0 :                         break;
    1146                 :            :                 }
    1147                 :          0 :                 curr = TAILQ_NEXT(curr, next);
    1148                 :            :         }
    1149                 :            : }

Generated by: LCOV version 1.14