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

Generated by: LCOV version 1.14