]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
octeontx2-af: npc: cn20k: MKEX profile support
authorSuman Ghosh <sumang@marvell.com>
Tue, 24 Feb 2026 08:00:00 +0000 (13:30 +0530)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Feb 2026 18:29:25 +0000 (10:29 -0800)
In new silicon variant cn20k, a new parser profile is introduced. Instead
of having two layer-data information per key field type, a new key
extractor concept is introduced. As part of this change now a maximum of
24 extractor can be configured per packet parsing profile. For example,
LA type(ether) can have 24 unique parsing key, LC type(ip), LD
type(tcp/udp) also can have unique 24 parsing key associated.

Signed-off-by: Suman Ghosh <sumang@marvell.com>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260224080009.4147301-5-rkannoth@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/npc.h
drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c

index 0dec50b1e84ffd3a69a4de3ab9a42d3f00623ee7..41164b65085fe72524ab958b7586ccb30f0bad18 100644 (file)
@@ -29,19 +29,21 @@ static const char *npc_kw_name[NPC_MCAM_KEY_MAX] = {
                     (((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \
                     ((key_ofs) & 0x3F))
 
+static const char cn20k_def_pfl_name[] = "default";
+
 static struct npc_mcam_kex_extr npc_mkex_extr_default = {
-       .mkex_sign = MKEX_SIGN,
+       .mkex_sign = MKEX_CN20K_SIGN,
        .name = "default",
        .kpu_version = NPC_KPU_PROFILE_VER,
        .keyx_cfg = {
                /* nibble: LA..LE (ltype only) + Error code + Channel */
                [NIX_INTF_RX] = ((u64)NPC_MCAM_KEY_DYN << 32) |
                        NPC_PARSE_NIBBLE_INTF_RX |
-                                NPC_PARSE_NIBBLE_ERRCODE,
+                                NPC_CN20K_PARSE_NIBBLE_ERRCODE,
 
                /* nibble: LA..LE (ltype only) */
                [NIX_INTF_TX] = ((u64)NPC_MCAM_KEY_X2 << 32) |
-                       NPC_PARSE_NIBBLE_INTF_TX,
+                       NPC_CN20K_PARSE_NIBBLE_INTF_TX,
        },
        .intf_extr_lid = {
        /* Default RX MCAM KEX profile */
@@ -305,9 +307,9 @@ npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int kpm, int num_entries)
        u64 entry_mask;
 
        entry_mask = npc_enable_mask(num_entries);
-       /* Disable first KPU_MAX_CST_ENT entries for built-in profile */
+       /* Disable first KPU_CN20K_MAX_CST_ENT entries for built-in profile */
        if (!rvu->kpu.custom)
-               entry_mask |= GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0);
+               entry_mask |= GENMASK_ULL(KPU_CN20K_MAX_CST_ENT - 1, 0);
        rvu_write64(rvu, blkaddr,
                    NPC_AF_KPMX_ENTRY_DISX(kpm, 0), entry_mask);
        if (num_entries <= 64) {
@@ -428,6 +430,299 @@ struct npc_priv_t *npc_priv_get(void)
        return &npc_priv;
 }
 
+static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
+                               struct npc_mcam_kex_extr *mkex_extr,
+                               u8 intf)
+{
+       u8 num_extr = rvu->hw->npc_kex_extr;
+       int extr, lt;
+       u64 val;
+
+       if (is_npc_intf_tx(intf))
+               return;
+
+       rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf),
+                   mkex_extr->keyx_cfg[NIX_INTF_RX]);
+
+       /* Program EXTRACTOR */
+       for (extr = 0; extr < num_extr; extr++)
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr),
+                           mkex_extr->intf_extr_lid[intf][extr]);
+
+       /* Program EXTRACTOR_LTYPE */
+       for (extr = 0; extr < num_extr; extr++) {
+               for (lt = 0; lt < NPC_MAX_LT; lt++) {
+                       val = mkex_extr->intf_extr_lt[intf][extr][lt];
+                       CN20K_SET_EXTR_LT(intf, extr, lt, val);
+               }
+       }
+}
+
+static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
+                               struct npc_mcam_kex_extr *mkex_extr,
+                               u8 intf)
+{
+       u8 num_extr = rvu->hw->npc_kex_extr;
+       int extr, lt;
+       u64 val;
+
+       if (is_npc_intf_rx(intf))
+               return;
+
+       rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf),
+                   mkex_extr->keyx_cfg[NIX_INTF_TX]);
+
+       /* Program EXTRACTOR */
+       for (extr = 0; extr < num_extr; extr++)
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr),
+                           mkex_extr->intf_extr_lid[intf][extr]);
+
+       /* Program EXTRACTOR_LTYPE */
+       for (extr = 0; extr < num_extr; extr++) {
+               for (lt = 0; lt < NPC_MAX_LT; lt++) {
+                       val = mkex_extr->intf_extr_lt[intf][extr][lt];
+                       CN20K_SET_EXTR_LT(intf, extr, lt, val);
+               }
+       }
+}
+
+static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
+                                    struct npc_mcam_kex_extr *mkex_extr)
+{
+       struct rvu_hwinfo *hw = rvu->hw;
+       u8 intf;
+
+       for (intf = 0; intf < hw->npc_intfs; intf++) {
+               npc_program_mkex_rx(rvu, blkaddr, mkex_extr, intf);
+               npc_program_mkex_tx(rvu, blkaddr, mkex_extr, intf);
+       }
+
+       /* Programme mkex hash profile */
+       npc_program_mkex_hash(rvu, blkaddr);
+}
+
+void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr,
+                                const char *mkex_profile)
+{
+       struct npc_mcam_kex_extr *mcam_kex_extr;
+       struct device *dev = &rvu->pdev->dev;
+       void __iomem *mkex_prfl_addr = NULL;
+       u64 prfl_sz;
+       int ret;
+
+       /* If user not selected mkex profile */
+       if (rvu->kpu_fwdata_sz ||
+           !strncmp(mkex_profile, cn20k_def_pfl_name, MKEX_NAME_LEN))
+               goto program_mkex_extr;
+
+       /* Setting up the mapping for mkex profile image */
+       ret = npc_fwdb_prfl_img_map(rvu, &mkex_prfl_addr, &prfl_sz);
+       if (ret < 0)
+               goto program_mkex_extr;
+
+       mcam_kex_extr = (struct npc_mcam_kex_extr __force *)mkex_prfl_addr;
+
+       while (((s64)prfl_sz > 0) &&
+              (mcam_kex_extr->mkex_sign != MKEX_END_SIGN)) {
+               /* Compare with mkex mod_param name string */
+               if (mcam_kex_extr->mkex_sign == MKEX_CN20K_SIGN &&
+                   !strncmp(mcam_kex_extr->name, mkex_profile,
+                            MKEX_NAME_LEN)) {
+                       rvu->kpu.mcam_kex_prfl.mkex_extr = mcam_kex_extr;
+                       goto program_mkex_extr;
+               }
+
+               mcam_kex_extr++;
+               prfl_sz -= sizeof(struct npc_mcam_kex_extr);
+       }
+       dev_warn(dev, "Failed to load requested profile: %s\n", mkex_profile);
+       rvu->kpu.mcam_kex_prfl.mkex_extr = npc_mkex_extr_default_get();
+
+program_mkex_extr:
+       dev_info(rvu->dev, "Using %s mkex profile\n",
+                rvu->kpu.mcam_kex_prfl.mkex_extr->name);
+       /* Program selected mkex profile */
+       npc_program_mkex_profile(rvu, blkaddr,
+                                rvu->kpu.mcam_kex_prfl.mkex_extr);
+       if (mkex_prfl_addr)
+               iounmap(mkex_prfl_addr);
+}
+
+static u8 npc_map2cn20k_flag(u8 flag)
+{
+       switch (flag) {
+       case NPC_F_LC_U_IP_FRAG:
+               return NPC_CN20K_F_LC_L_IP_FRAG;
+
+       case NPC_F_LC_U_IP6_FRAG:
+               return NPC_CN20K_F_LC_L_IP6_FRAG;
+
+       case NPC_F_LC_L_6TO4:
+               return NPC_CN20K_F_LC_L_6TO4;
+
+       case NPC_F_LC_L_MPLS_IN_IP:
+               return NPC_CN20K_F_LC_U_MPLS_IN_IP;
+
+       case NPC_F_LC_L_IP6_TUN_IP6:
+               return NPC_CN20K_F_LC_U_IP6_TUN_IP6;
+
+       case NPC_F_LC_L_IP6_MPLS_IN_IP:
+               return NPC_CN20K_F_LC_U_IP6_MPLS_IN_IP;
+
+       default:
+               break;
+       }
+
+       WARN(1, "%s: Invalid flag=%u\n", __func__, flag);
+       return 0xff;
+}
+
+void
+npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,
+                                       struct npc_kpu_profile_adapter *pfl)
+{
+       struct npc_kpu_profile_action *action;
+       int entries, ltype;
+       u8 flags, val;
+
+       for (int i = 0; i < pfl->kpus; i++) {
+               action = pfl->kpu[i].action;
+               entries = pfl->kpu[i].action_entries;
+
+               for (int j = 0; j < entries; j++) {
+                       if (action[j].lid != NPC_LID_LC)
+                               continue;
+
+                       ltype = action[j].ltype;
+
+                       if (ltype != NPC_LT_LC_IP &&
+                           ltype != NPC_LT_LC_IP6 &&
+                           ltype != NPC_LT_LC_IP_OPT &&
+                           ltype != NPC_LT_LC_IP6_EXT)
+                               continue;
+
+                       flags = action[j].flags;
+
+                       switch (flags) {
+                       case NPC_F_LC_U_IP_FRAG:
+                       case NPC_F_LC_U_IP6_FRAG:
+                       case NPC_F_LC_L_6TO4:
+                       case NPC_F_LC_L_MPLS_IN_IP:
+                       case NPC_F_LC_L_IP6_TUN_IP6:
+                       case NPC_F_LC_L_IP6_MPLS_IN_IP:
+                               val = npc_map2cn20k_flag(flags);
+                               if (val == 0xFF) {
+                                       dev_err(rvu->dev,
+                                               "%s: Error to get flag value\n",
+                                               __func__);
+                                       return;
+                               }
+
+                               action[j].flags = val;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+}
+
+int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
+                              struct npc_kpu_profile_adapter *profile)
+{
+       struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
+       struct npc_kpu_profile_action *action;
+       struct npc_kpu_profile_cam *cam;
+       struct npc_kpu_fwdata *fw_kpu;
+       size_t hdr_sz, offset = 0;
+       u16 kpu, entry;
+       int entries;
+
+       hdr_sz = sizeof(struct npc_cn20k_kpu_profile_fwdata);
+
+       if (rvu->kpu_fwdata_sz < hdr_sz) {
+               dev_warn(rvu->dev, "Invalid KPU profile size\n");
+               return -EINVAL;
+       }
+
+       if (le64_to_cpu(fw->signature) != KPU_SIGN) {
+               dev_warn(rvu->dev, "Invalid KPU profile signature %llx\n",
+                        fw->signature);
+               return -EINVAL;
+       }
+
+       /* Verify if the using known profile structure */
+       if (NPC_KPU_VER_MAJ(profile->version) >
+           NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER)) {
+               dev_warn(rvu->dev, "Not supported Major version: %d > %d\n",
+                        NPC_KPU_VER_MAJ(profile->version),
+                        NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER));
+               return -EINVAL;
+       }
+
+       /* Verify if profile is aligned with the required kernel changes */
+       if (NPC_KPU_VER_MIN(profile->version) <
+           NPC_KPU_VER_MIN(NPC_KPU_PROFILE_VER)) {
+               dev_warn(rvu->dev,
+                        "Invalid KPU profile version: %d.%d.%d expected version <= %d.%d.%d\n",
+                        NPC_KPU_VER_MAJ(profile->version),
+                        NPC_KPU_VER_MIN(profile->version),
+                        NPC_KPU_VER_PATCH(profile->version),
+                        NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER),
+                        NPC_KPU_VER_MIN(NPC_KPU_PROFILE_VER),
+                        NPC_KPU_VER_PATCH(NPC_KPU_PROFILE_VER));
+               return -EINVAL;
+       }
+
+       /* Verify if profile fits the HW */
+       if (fw->kpus > profile->kpus) {
+               dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus,
+                        profile->kpus);
+               return -EINVAL;
+       }
+
+       profile->mcam_kex_prfl.mkex_extr = &fw->mkex;
+       if (profile->mcam_kex_prfl.mkex_extr->mkex_sign != MKEX_CN20K_SIGN) {
+               dev_warn(rvu->dev, "Invalid MKEX profile signature:%llx\n",
+                        profile->mcam_kex_prfl.mkex_extr->mkex_sign);
+               return -EINVAL;
+       }
+
+       profile->custom = 1;
+       profile->name = fw->name;
+       profile->version = le64_to_cpu(fw->version);
+       profile->lt_def = &fw->lt_def;
+
+       for (kpu = 0; kpu < fw->kpus; kpu++) {
+               fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
+               if (fw_kpu->entries > KPU_CN20K_MAX_CST_ENT)
+                       dev_warn(rvu->dev,
+                                "Too many custom entries on KPU%d: %d > %d\n",
+                                kpu, fw_kpu->entries, KPU_CN20K_MAX_CST_ENT);
+               entries = min(fw_kpu->entries, KPU_CN20K_MAX_CST_ENT);
+               cam = (struct npc_kpu_profile_cam *)fw_kpu->data;
+               offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);
+               action = (struct npc_kpu_profile_action *)(fw->data + offset);
+               offset += fw_kpu->entries * sizeof(*action);
+               if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
+                       dev_warn(rvu->dev,
+                                "Profile size mismatch on KPU%i parsing.\n",
+                                kpu + 1);
+                       return -EINVAL;
+               }
+
+               for (entry = 0; entry < entries; entry++) {
+                       profile->kpu[kpu].cam[entry] = cam[entry];
+                       profile->kpu[kpu].action[entry] = action[entry];
+               }
+       }
+       npc_cn20k_update_action_entries_n_flags(rvu, profile);
+
+       return 0;
+}
+
 static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
                                      u16 sub_off, u16 *mcam_idx)
 {
@@ -1960,6 +2255,38 @@ rvu_mbox_handler_npc_cn20k_get_fcnt(struct rvu *rvu,
        return 0;
 }
 
+int
+rvu_mbox_handler_npc_cn20k_get_kex_cfg(struct rvu *rvu,
+                                      struct msg_req *req,
+                                      struct npc_cn20k_get_kex_cfg_rsp *rsp)
+{
+       int extr, lt;
+
+       rsp->rx_keyx_cfg = CN20K_GET_KEX_CFG(NIX_INTF_RX);
+       rsp->tx_keyx_cfg = CN20K_GET_KEX_CFG(NIX_INTF_TX);
+
+       /* Get EXTRACTOR LID */
+       for (extr = 0; extr < NPC_MAX_EXTRACTOR; extr++) {
+               rsp->intf_extr_lid[NIX_INTF_RX][extr] =
+                       CN20K_GET_EXTR_LID(NIX_INTF_RX, extr);
+               rsp->intf_extr_lid[NIX_INTF_TX][extr] =
+                       CN20K_GET_EXTR_LID(NIX_INTF_TX, extr);
+       }
+
+       /* Get EXTRACTOR LTYPE */
+       for (extr = 0; extr < NPC_MAX_EXTRACTOR; extr++) {
+               for (lt = 0; lt < NPC_MAX_LT; lt++) {
+                       rsp->intf_extr_lt[NIX_INTF_RX][extr][lt] =
+                               CN20K_GET_EXTR_LT(NIX_INTF_RX, extr, lt);
+                       rsp->intf_extr_lt[NIX_INTF_TX][extr][lt] =
+                               CN20K_GET_EXTR_LT(NIX_INTF_TX, extr, lt);
+               }
+       }
+
+       memcpy(rsp->mkex_pfl_name, rvu->mkex_pfl_name, MKEX_NAME_LEN);
+       return 0;
+}
+
 static int *subbank_srch_order;
 
 static void npc_populate_restricted_idxs(int num_subbanks)
@@ -2172,6 +2499,23 @@ void npc_cn20k_deinit(struct rvu *rvu)
        kfree(subbank_srch_order);
 }
 
+static int npc_setup_mcam_section(struct rvu *rvu, int key_type)
+{
+       int blkaddr, sec;
+
+       blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+       if (blkaddr < 0) {
+               dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
+               return -ENODEV;
+       }
+
+       for (sec = 0; sec < npc_priv.num_subbanks; sec++)
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_MCAM_SECTIONX_CFG_EXT(sec), key_type);
+
+       return 0;
+}
+
 int npc_cn20k_init(struct rvu *rvu)
 {
        int err;
@@ -2183,6 +2527,13 @@ int npc_cn20k_init(struct rvu *rvu)
                return err;
        }
 
+       err = npc_setup_mcam_section(rvu, NPC_MCAM_KEY_X2);
+       if (err) {
+               dev_err(rvu->dev, "%s: mcam section configuration failure\n",
+                       __func__);
+               return err;
+       }
+
        npc_priv.init_done = true;
 
        return 0;
index 7cfca5cfe5fac6bbf3fc8df51d60a3035d8bd707..2ed59b3955f47a656bec9dcb6e35ec39908d3c86 100644 (file)
@@ -8,10 +8,77 @@
 #ifndef NPC_CN20K_H
 #define NPC_CN20K_H
 
+#define MKEX_CN20K_SIGN        0x19bbfdbd160
+
 #define MAX_NUM_BANKS 2
 #define MAX_NUM_SUB_BANKS 32
 #define MAX_SUBBANK_DEPTH 256
 
+/* strtoull of "mkexprof" with base:36 */
+#define MKEX_END_SIGN  0xdeadbeef
+
+#define NPC_CN20K_BYTESM GENMASK_ULL(18, 16)
+#define NPC_CN20K_PARSE_NIBBLE GENMASK_ULL(22, 0)
+#define NPC_CN20K_TOTAL_NIBBLE 23
+
+#define CN20K_SET_EXTR_LT(intf, extr, ltype, cfg)      \
+       rvu_write64(rvu, BLKADDR_NPC,   \
+                   NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype), cfg)
+
+#define CN20K_GET_KEX_CFG(intf)        \
+       rvu_read64(rvu, BLKADDR_NPC, NPC_AF_INTFX_KEX_CFG(intf))
+
+#define CN20K_GET_EXTR_LID(intf, extr) \
+       rvu_read64(rvu, BLKADDR_NPC,    \
+                  NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr))
+
+#define CN20K_SET_EXTR_LT(intf, extr, ltype, cfg)      \
+       rvu_write64(rvu, BLKADDR_NPC,   \
+                   NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype), cfg)
+
+#define CN20K_GET_EXTR_LT(intf, extr, ltype)   \
+       rvu_read64(rvu, BLKADDR_NPC,    \
+                  NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype))
+
+/* NPC_PARSE_KEX_S nibble definitions for each field */
+#define NPC_CN20K_PARSE_NIBBLE_CHAN GENMASK_ULL(2, 0)
+#define NPC_CN20K_PARSE_NIBBLE_ERRLEV BIT_ULL(3)
+#define NPC_CN20K_PARSE_NIBBLE_ERRCODE GENMASK_ULL(5, 4)
+#define NPC_CN20K_PARSE_NIBBLE_L2L3_BCAST BIT_ULL(6)
+#define NPC_CN20K_PARSE_NIBBLE_LA_FLAGS BIT_ULL(7)
+#define NPC_CN20K_PARSE_NIBBLE_LA_LTYPE BIT_ULL(8)
+#define NPC_CN20K_PARSE_NIBBLE_LB_FLAGS BIT_ULL(9)
+#define NPC_CN20K_PARSE_NIBBLE_LB_LTYPE BIT_ULL(10)
+#define NPC_CN20K_PARSE_NIBBLE_LC_FLAGS BIT_ULL(11)
+#define NPC_CN20K_PARSE_NIBBLE_LC_LTYPE BIT_ULL(12)
+#define NPC_CN20K_PARSE_NIBBLE_LD_FLAGS BIT_ULL(13)
+#define NPC_CN20K_PARSE_NIBBLE_LD_LTYPE BIT_ULL(14)
+#define NPC_CN20K_PARSE_NIBBLE_LE_FLAGS BIT_ULL(15)
+#define NPC_CN20K_PARSE_NIBBLE_LE_LTYPE BIT_ULL(16)
+#define NPC_CN20K_PARSE_NIBBLE_LF_FLAGS BIT_ULL(17)
+#define NPC_CN20K_PARSE_NIBBLE_LF_LTYPE BIT_ULL(18)
+#define NPC_CN20K_PARSE_NIBBLE_LG_FLAGS BIT_ULL(19)
+#define NPC_CN20K_PARSE_NIBBLE_LG_LTYPE BIT_ULL(20)
+#define NPC_CN20K_PARSE_NIBBLE_LH_FLAGS BIT_ULL(21)
+#define NPC_CN20K_PARSE_NIBBLE_LH_LTYPE BIT_ULL(22)
+
+/* Rx parse key extract nibble enable */
+#define NPC_CN20K_PARSE_NIBBLE_INTF_RX  (NPC_CN20K_PARSE_NIBBLE_CHAN | \
+                                        NPC_CN20K_PARSE_NIBBLE_L2L3_BCAST | \
+                                        NPC_CN20K_PARSE_NIBBLE_LA_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LB_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LC_FLAGS | \
+                                        NPC_CN20K_PARSE_NIBBLE_LC_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LD_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LE_LTYPE)
+
+/* Tx parse key extract nibble enable */
+#define NPC_CN20K_PARSE_NIBBLE_INTF_TX (NPC_CN20K_PARSE_NIBBLE_LA_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LB_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LC_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LD_LTYPE | \
+                                        NPC_CN20K_PARSE_NIBBLE_LE_LTYPE)
+
 /**
  * enum npc_subbank_flag - NPC subbank status
  *
@@ -147,6 +214,34 @@ struct npc_mcam_kex_extr {
        u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT];
 } __packed;
 
+struct npc_cn20k_kpu_profile_fwdata {
+#define KPU_SIGN       0x00666f727075706b
+#define KPU_NAME_LEN   32
+       /* Maximum number of custom KPU entries supported by
+        * the built-in profile.
+        */
+#define KPU_CN20K_MAX_CST_ENT  6
+       /* KPU Profle Header */
+       __le64  signature; /* "kpuprof\0" (8 bytes/ASCII characters) */
+       u8      name[KPU_NAME_LEN]; /* KPU Profile name */
+       __le64  version; /* KPU profile version */
+       u8      kpus;
+       u8      reserved[7];
+
+       /* Default MKEX profile to be used with this KPU profile. May be
+        * overridden with mkex_profile module parameter.
+        * Format is same as for the MKEX profile to streamline processing.
+        */
+       struct npc_mcam_kex_extr        mkex;
+       /* LTYPE values for specific HW offloaded protocols. */
+       struct npc_lt_def_cfg           lt_def;
+       /* Dynamically sized data:
+        *  Custom KPU CAM and ACTION configuration entries.
+        * struct npc_kpu_fwdata kpu[kpus];
+        */
+       u8      data[];
+} __packed;
+
 struct rvu;
 
 struct npc_priv_t *npc_priv_get(void);
@@ -162,4 +257,12 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifunc, int key_type,
 int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count);
 void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr);
 struct npc_mcam_kex_extr *npc_mkex_extr_default_get(void);
+void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr,
+                                const char *mkex_profile);
+int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
+                              struct npc_kpu_profile_adapter *profile);
+
+void
+npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,
+                                       struct npc_kpu_profile_adapter *pfl);
 #endif /* NPC_CN20K_H */
index 073d4b815681db2eca18ef5ae66dd9a216804754..bf50d999528b1ca309f87cb9e189c05d4bdc4579 100644 (file)
 #define RVU_MBOX_VF_VFAF_TRIGX(a)              (0x2000 | (a) << 3)
 /* NPC registers */
 #define NPC_AF_INTFX_EXTRACTORX_CFG(a, b) \
-       (0x908000ull | (a) << 10 | (b) << 3)
+       (0x20c000ull | (a) << 16 | (b) << 8)
 #define NPC_AF_INTFX_EXTRACTORX_LTX_CFG(a, b, c) \
-       (0x900000ull | (a) << 13 | (b) << 8  | (c) << 3)
+       (0x204000ull | (a) << 16 | (b) << 8  | (c) << 3)
 #define NPC_AF_KPMX_ENTRYX_CAMX(a, b, c) \
-       (0x100000ull | (a) << 14 | (b) << 6 | (c) << 3)
+       (0x20000ull | (a) << 12 | (b) << 3 | (c) << 16)
 #define NPC_AF_KPMX_ENTRYX_ACTION0(a, b) \
-       (0x100020ull | (a) << 14 | (b) << 6)
+       (0x40000ull | (a) << 12 | (b) << 3)
 #define NPC_AF_KPMX_ENTRYX_ACTION1(a, b) \
-       (0x100028ull | (a) << 14 | (b) << 6)
-#define NPC_AF_KPMX_ENTRY_DISX(a, b)   (0x180000ull | (a) << 6 | (b) << 3)
-#define NPC_AF_KPM_PASS2_CFG   0x580
-#define NPC_AF_KPMX_PASS2_OFFSET(a)    (0x190000ull | (a) << 3)
-#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a)        (0xC000000ull | (a) << 3)
+       (0x50000ull | (a) << 12 | (b) << 3)
+#define NPC_AF_KPMX_ENTRY_DISX(a, b)   (0x60000ull | (a) << 12 | (b) << 3)
+#define NPC_AF_KPM_PASS2_CFG   0x10210
+#define NPC_AF_KPMX_PASS2_OFFSET(a)    (0x60040ull | (a) << 12)
+#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a)        (0xf000000ull | (a) << 3)
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(a, b, c) ({            \
+       u64 offset;                                                     \
+       offset = (0x8000000ull | (a) << 4 | (b) << 20 | (c) << 3);      \
+       offset; })
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(a, b, c) ({              \
+       u64 offset;                                                     \
+       offset = (0x9000000ull | (a) << 4 | (b) << 20 | (c) << 3);      \
+       offset; })
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(a, b, c) ({              \
+       u64 offset;                                                     \
+       offset = (0x9400000ull | (a) << 4 | (b) << 20 | (c) << 3);      \
+       offset; })
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(a, b, c) ({              \
+       u64 offset;                                                     \
+       offset = (0x9800000ull | (a) << 4 | (b) << 20 | (c) << 3);      \
+       offset; })
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(a, b, c) ({              \
+       u64 offset;                                                     \
+       offset = (0x9c00000ull | (a) << 4 | (b) << 20 | (c) << 3);      \
+       offset; })
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(a, b) ({             \
+       u64 offset;                                             \
+       offset = (0xa000000ull | (a) << 4 | (b) << 20);         \
+       offset; })
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(a, b, c) ({              \
+       u64 offset;                                                     \
+       offset = (0xc000000ull | (a) << 4 | (b) << 20 | (c) << 22);     \
+       offset; })
+
+#define NPC_AF_INTFX_MISS_ACTX(a, b)   (0xf003000 | (a) << 6 | (b) << 4)
+
+#define NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(a, b) ({            \
+       u64 offset;                                             \
+       offset = (0xb000000ull | (a) << 4 | (b) << 20);         \
+       offset; })
 
 #endif /* RVU_MBOX_REG_H */
index 1c4b3683278809750b4509e2b61a0e888afbae25..a393bf884fd68e086bd3b2da97cb5872f3f67172 100644 (file)
@@ -285,6 +285,8 @@ M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status,                     \
                                   npc_get_field_status_rsp)              \
 M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_fcnt,           \
                                 msg_req, npc_cn20k_get_fcnt_rsp)       \
+M(NPC_CN20K_GET_KEX_CFG, 0x6016, npc_cn20k_get_kex_cfg,                        \
+                                  msg_req, npc_cn20k_get_kex_cfg_rsp)  \
 /* NIX mbox IDs (range 0x8000 - 0xFFFF) */                             \
 M(NIX_LF_ALLOC,                0x8000, nix_lf_alloc,                           \
                                 nix_lf_alloc_req, nix_lf_alloc_rsp)    \
@@ -1559,7 +1561,7 @@ struct npc_mcam_free_entry_req {
 };
 
 struct mcam_entry {
-#define NPC_MAX_KWS_IN_KEY     7 /* Number of keywords in max keywidth */
+#define NPC_MAX_KWS_IN_KEY     8 /* Number of keywords in max keywidth */
        u64     kw[NPC_MAX_KWS_IN_KEY];
        u64     kw_mask[NPC_MAX_KWS_IN_KEY];
        u64     action;
@@ -1663,6 +1665,19 @@ struct npc_get_kex_cfg_rsp {
        u8 mkex_pfl_name[MKEX_NAME_LEN];
 };
 
+struct npc_cn20k_get_kex_cfg_rsp {
+       struct mbox_msghdr hdr;
+       u64 rx_keyx_cfg;   /* NPC_AF_INTF(0)_KEX_CFG */
+       u64 tx_keyx_cfg;   /* NPC_AF_INTF(1)_KEX_CFG */
+#define NPC_MAX_EXTRACTOR 24
+       /* MKEX Extractor data */
+       u64 intf_extr_lid[NPC_MAX_INTF][NPC_MAX_EXTRACTOR];
+       /* KEX configuration per extractor */
+       u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT];
+#define MKEX_NAME_LEN 128
+       u8 mkex_pfl_name[MKEX_NAME_LEN];
+};
+
 struct ptp_get_cap_rsp {
        struct mbox_msghdr hdr;
 #define        PTP_CAP_HW_ATOMIC_UPDATE BIT_ULL(0)
index 6c3aca6f278db7172c03dc9cce25daa29a11ba6e..cb05ec69e0b3e98b78ca8c81dd6bbee76e52d3a3 100644 (file)
@@ -429,6 +429,7 @@ struct nix_rx_action {
 
 /* NPC_AF_INTFX_KEX_CFG field masks */
 #define NPC_PARSE_NIBBLE               GENMASK_ULL(30, 0)
+#define NPC_TOTAL_NIBBLE               31
 
 /* NPC_PARSE_KEX_S nibble definitions for each field */
 #define NPC_PARSE_NIBBLE_CHAN          GENMASK_ULL(2, 0)
index 561b01fcdbdef3e95428d233604bac098eec7b69..db74f7fdf0288331b6345954955e30cb9939b423 100644 (file)
@@ -321,6 +321,18 @@ enum npc_kpu_lb_lflag {
        NPC_F_LB_L_FDSA,
 };
 
+enum npc_cn20k_kpu_lc_uflag {
+       NPC_CN20K_F_LC_U_MPLS_IN_IP = 0x20,
+       NPC_CN20K_F_LC_U_IP6_TUN_IP6 = 0x40,
+       NPC_CN20K_F_LC_U_IP6_MPLS_IN_IP = 0x80,
+};
+
+enum npc_cn20k_kpu_lc_lflag {
+       NPC_CN20K_F_LC_L_IP_FRAG = 2,
+       NPC_CN20K_F_LC_L_IP6_FRAG,
+       NPC_CN20K_F_LC_L_6TO4,
+};
+
 enum npc_kpu_lc_uflag {
        NPC_F_LC_U_UNK_PROTO = 0x10,
        NPC_F_LC_U_IP_FRAG = 0x20,
index 14ca28ab493a8b13c18db229f9d6b8fb88837352..dd930aa05582c62041846e81b03a36de131efa17 100644 (file)
@@ -554,7 +554,11 @@ struct npc_kpu_profile_adapter {
        const struct npc_lt_def_cfg     *lt_def;
        const struct npc_kpu_profile_action     *ikpu; /* array[pkinds] */
        const struct npc_kpu_profile    *kpu; /* array[kpus] */
-       struct npc_mcam_kex             *mkex;
+       union npc_mcam_key_prfl {
+               struct npc_mcam_kex             *mkex;
+                                       /* used for cn9k and cn10k */
+               struct npc_mcam_kex_extr        *mkex_extr; /* used for cn20k */
+       } mcam_kex_prfl;
        struct npc_mcam_kex_hash        *mkex_hash;
        bool                            custom;
        size_t                          pkinds;
index a113cab1e1a53fcaec3453a07e5e7cf1f41fe256..3e4f4fee791a2c34318b7baaf66d098f971e31a0 100644 (file)
@@ -1340,8 +1340,8 @@ static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
        npc_program_mkex_hash(rvu, blkaddr);
 }
 
-static int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
-                                u64 *size)
+int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
+                         u64 *size)
 {
        u64 prfl_addr, prfl_sz;
 
@@ -1397,7 +1397,7 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
                         */
                        if (!is_rvu_96xx_B0(rvu) ||
                            mcam_kex->keyx_cfg[NIX_INTF_RX] == mcam_kex->keyx_cfg[NIX_INTF_TX])
-                               rvu->kpu.mkex = mcam_kex;
+                               rvu->kpu.mcam_kex_prfl.mkex = mcam_kex;
                        goto program_mkex;
                }
 
@@ -1407,9 +1407,10 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
        dev_warn(dev, "Failed to load requested profile: %s\n", mkex_profile);
 
 program_mkex:
-       dev_info(rvu->dev, "Using %s mkex profile\n", rvu->kpu.mkex->name);
+       dev_info(rvu->dev, "Using %s mkex profile\n",
+                rvu->kpu.mcam_kex_prfl.mkex->name);
        /* Program selected mkex profile */
-       npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mkex);
+       npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mcam_kex_prfl.mkex);
        if (mkex_prfl_addr)
                iounmap(mkex_prfl_addr);
 }
@@ -1528,7 +1529,8 @@ static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
        rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(kpu), 0x01);
 }
 
-static int npc_prepare_default_kpu(struct npc_kpu_profile_adapter *profile)
+static void npc_prepare_default_kpu(struct rvu *rvu,
+                                   struct npc_kpu_profile_adapter *profile)
 {
        profile->custom = 0;
        profile->name = def_pfl_name;
@@ -1538,23 +1540,38 @@ static int npc_prepare_default_kpu(struct npc_kpu_profile_adapter *profile)
        profile->kpu = npc_kpu_profiles;
        profile->kpus = ARRAY_SIZE(npc_kpu_profiles);
        profile->lt_def = &npc_lt_defaults;
-       profile->mkex = &npc_mkex_default;
        profile->mkex_hash = &npc_mkex_hash_default;
 
-       return 0;
+       if (!is_cn20k(rvu->pdev)) {
+               profile->mcam_kex_prfl.mkex = &npc_mkex_default;
+               return;
+       }
+
+       profile->mcam_kex_prfl.mkex_extr = npc_mkex_extr_default_get();
+       ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].offset = 6;
+       ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].mask = 0xe0;
+       ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].shift = 0x5;
+       ikpu_action_entries[NPC_RX_CPT_HDR_PKIND].right = 0x1;
+
+       npc_cn20k_update_action_entries_n_flags(rvu, profile);
 }
 
 static int npc_apply_custom_kpu(struct rvu *rvu,
                                struct npc_kpu_profile_adapter *profile)
 {
        size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;
-       struct npc_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
        struct npc_kpu_profile_action *action;
+       struct npc_kpu_profile_fwdata *fw;
        struct npc_kpu_profile_cam *cam;
        struct npc_kpu_fwdata *fw_kpu;
        int entries;
        u16 kpu, entry;
 
+       if (is_cn20k(rvu->pdev))
+               return npc_cn20k_apply_custom_kpu(rvu, profile);
+
+       fw = rvu->kpu_fwdata;
+
        if (rvu->kpu_fwdata_sz < hdr_sz) {
                dev_warn(rvu->dev, "Invalid KPU profile size\n");
                return -EINVAL;
@@ -1595,7 +1612,7 @@ static int npc_apply_custom_kpu(struct rvu *rvu,
        profile->custom = 1;
        profile->name = fw->name;
        profile->version = le64_to_cpu(fw->version);
-       profile->mkex = &fw->mkex;
+       profile->mcam_kex_prfl.mkex = &fw->mkex;
        profile->lt_def = &fw->lt_def;
 
        for (kpu = 0; kpu < fw->kpus; kpu++) {
@@ -1720,7 +1737,7 @@ void npc_load_kpu_profile(struct rvu *rvu)
        if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))
                goto revert_to_default;
        /* First prepare default KPU, then we'll customize top entries. */
-       npc_prepare_default_kpu(profile);
+       npc_prepare_default_kpu(rvu, profile);
 
        /* Order of preceedence for load loading NPC profile (high to low)
         * Firmware binary in filesystem.
@@ -1783,7 +1800,7 @@ program_kpu:
        return;
 
 revert_to_default:
-       npc_prepare_default_kpu(profile);
+       npc_prepare_default_kpu(rvu, profile);
 }
 
 static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
@@ -2036,12 +2053,21 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blkaddr)
 
 static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr)
 {
-       struct npc_mcam_kex *mkex = rvu->kpu.mkex;
+       struct npc_mcam_kex_extr *mkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;
+       struct npc_mcam_kex *mkex = rvu->kpu.mcam_kex_prfl.mkex;
        struct npc_mcam *mcam = &rvu->hw->mcam;
        struct rvu_hwinfo *hw = rvu->hw;
        u64 nibble_ena, rx_kex, tx_kex;
+       u64 *keyx_cfg;
        u8 intf;
 
+       if (is_cn20k(rvu->pdev)) {
+               keyx_cfg = mkex_extr->keyx_cfg;
+               goto skip_miss_cntr;
+       }
+
+       keyx_cfg = mkex->keyx_cfg;
+
        /* Reserve last counter for MCAM RX miss action which is set to
         * drop packet. This way we will know how many pkts didn't match
         * any MCAM entry.
@@ -2049,15 +2075,17 @@ static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr)
        mcam->counters.max--;
        mcam->rx_miss_act_cntr = mcam->counters.max;
 
-       rx_kex = mkex->keyx_cfg[NIX_INTF_RX];
-       tx_kex = mkex->keyx_cfg[NIX_INTF_TX];
+skip_miss_cntr:
+       rx_kex = keyx_cfg[NIX_INTF_RX];
+       tx_kex = keyx_cfg[NIX_INTF_TX];
+
        nibble_ena = FIELD_GET(NPC_PARSE_NIBBLE, rx_kex);
 
        nibble_ena = rvu_npc_get_tx_nibble_cfg(rvu, nibble_ena);
        if (nibble_ena) {
                tx_kex &= ~NPC_PARSE_NIBBLE;
                tx_kex |= FIELD_PREP(NPC_PARSE_NIBBLE, nibble_ena);
-               mkex->keyx_cfg[NIX_INTF_TX] = tx_kex;
+               keyx_cfg[NIX_INTF_TX] = tx_kex;
        }
 
        /* Configure RX interfaces */
@@ -2069,6 +2097,9 @@ static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr)
                rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf),
                            rx_kex);
 
+               if (is_cn20k(rvu->pdev))
+                       continue;
+
                /* If MCAM lookup doesn't result in a match, drop the received
                 * packet. And map this action to a counter to count dropped
                 * packets.
@@ -2174,7 +2205,10 @@ int rvu_npc_init(struct rvu *rvu)
 
        npc_config_secret_key(rvu, blkaddr);
        /* Configure MKEX profile */
-       npc_load_mkex_profile(rvu, blkaddr, rvu->mkex_pfl_name);
+       if (is_cn20k(rvu->pdev))
+               npc_cn20k_load_mkex_profile(rvu, blkaddr, rvu->mkex_pfl_name);
+       else
+               npc_load_mkex_profile(rvu, blkaddr, rvu->mkex_pfl_name);
 
        err = npc_mcam_rsrcs_init(rvu, blkaddr);
        if (err)
@@ -2184,7 +2218,10 @@ int rvu_npc_init(struct rvu *rvu)
        if (err) {
                dev_err(rvu->dev,
                        "Incorrect mkex profile loaded using default mkex\n");
-               npc_load_mkex_profile(rvu, blkaddr, def_pfl_name);
+               if (is_cn20k(rvu->pdev))
+                       npc_cn20k_load_mkex_profile(rvu, blkaddr, def_pfl_name);
+               else
+                       npc_load_mkex_profile(rvu, blkaddr, def_pfl_name);
        }
 
        if (is_cn20k(rvu->pdev))
index 80c63618ec47fed81989c4dc6c22f7d9f896590a..346e6ada158ef9fdc71cb19f7805d7683ef169c7 100644 (file)
@@ -13,5 +13,7 @@ void npc_load_kpu_profile(struct rvu *rvu);
 void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
                          const struct npc_kpu_profile_action *kpuaction,
                          int kpu, int entry, bool pkind);
+int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
+                         u64 *size);
 
 #endif /* RVU_NPC_H */
index 1930b54e72f219412b3a93c7eedc2ab96d9bc616..5f51a05de5dec2fd9d44dd318f6f38cf70326138 100644 (file)
@@ -12,6 +12,8 @@
 #include "npc.h"
 #include "rvu_npc_fs.h"
 #include "rvu_npc_hash.h"
+#include "cn20k/reg.h"
+#include "cn20k/npc.h"
 
 static const char * const npc_flow_names[] = {
        [NPC_DMAC]      = "dmac",
@@ -81,19 +83,26 @@ const char *npc_get_field_name(u8 hdr)
 /* Compute keyword masks and figure out the number of keywords a field
  * spans in the key.
  */
-static void npc_set_kw_masks(struct npc_mcam *mcam, u8 type,
+static void npc_set_kw_masks(struct rvu *rvu, struct npc_mcam *mcam, u8 type,
                             u8 nr_bits, int start_kwi, int offset, u8 intf)
 {
        struct npc_key_field *field = &mcam->rx_key_fields[type];
        u8 bits_in_kw;
        int max_kwi;
 
-       if (mcam->banks_per_entry == 1)
-               max_kwi = 1; /* NPC_MCAM_KEY_X1 */
-       else if (mcam->banks_per_entry == 2)
-               max_kwi = 3; /* NPC_MCAM_KEY_X2 */
-       else
-               max_kwi = 6; /* NPC_MCAM_KEY_X4 */
+       if (is_cn20k(rvu->pdev)) {
+               if (mcam->banks_per_entry == 1)
+                       max_kwi = 3; /* NPC_MCAM_KEY_X2 */
+               else
+                       max_kwi = 7; /* NPC_MCAM_KEY_X4 */
+       } else {
+               if (mcam->banks_per_entry == 1)
+                       max_kwi = 1; /* NPC_MCAM_KEY_X1 */
+               else if (mcam->banks_per_entry == 2)
+                       max_kwi = 3; /* NPC_MCAM_KEY_X2 */
+               else
+                       max_kwi = 6; /* NPC_MCAM_KEY_X4 */
+       }
 
        if (is_npc_intf_tx(intf))
                field = &mcam->tx_key_fields[type];
@@ -155,7 +164,8 @@ static bool npc_is_same(struct npc_key_field *input,
                     sizeof(struct npc_layer_mdata)) == 0;
 }
 
-static void npc_set_layer_mdata(struct npc_mcam *mcam, enum key_fields type,
+static void npc_set_layer_mdata(struct rvu *rvu,
+                               struct npc_mcam *mcam, enum key_fields type,
                                u64 cfg, u8 lid, u8 lt, u8 intf)
 {
        struct npc_key_field *input = &mcam->rx_key_fields[type];
@@ -165,13 +175,17 @@ static void npc_set_layer_mdata(struct npc_mcam *mcam, enum key_fields type,
 
        input->layer_mdata.hdr = FIELD_GET(NPC_HDR_OFFSET, cfg);
        input->layer_mdata.key = FIELD_GET(NPC_KEY_OFFSET, cfg);
-       input->layer_mdata.len = FIELD_GET(NPC_BYTESM, cfg) + 1;
+       if (is_cn20k(rvu->pdev))
+               input->layer_mdata.len = FIELD_GET(NPC_CN20K_BYTESM, cfg) + 1;
+       else
+               input->layer_mdata.len = FIELD_GET(NPC_BYTESM, cfg) + 1;
        input->layer_mdata.ltype = lt;
        input->layer_mdata.lid = lid;
 }
 
 static bool npc_check_overlap_fields(struct npc_key_field *input1,
-                                    struct npc_key_field *input2)
+                                    struct npc_key_field *input2,
+                                    int max_kw)
 {
        int kwi;
 
@@ -182,7 +196,7 @@ static bool npc_check_overlap_fields(struct npc_key_field *input1,
            input1->layer_mdata.ltype != input2->layer_mdata.ltype)
                return false;
 
-       for (kwi = 0; kwi < NPC_MAX_KWS_IN_KEY; kwi++) {
+       for (kwi = 0; kwi < max_kw; kwi++) {
                if (input1->kw_mask[kwi] & input2->kw_mask[kwi])
                        return true;
        }
@@ -202,6 +216,7 @@ static bool npc_check_overlap(struct rvu *rvu, int blkaddr,
        struct npc_key_field *dummy, *input;
        int start_kwi, offset;
        u8 nr_bits, lid, lt, ld;
+       int extr, kws;
        u64 cfg;
 
        dummy = &mcam->rx_key_fields[NPC_UNKNOWN];
@@ -212,6 +227,10 @@ static bool npc_check_overlap(struct rvu *rvu, int blkaddr,
                input = &mcam->tx_key_fields[type];
        }
 
+       if (is_cn20k(rvu->pdev))
+               goto skip_cn10k_config;
+
+       kws = NPC_MAX_KWS_IN_KEY - 1;
        for (lid = start_lid; lid < NPC_MAX_LID; lid++) {
                for (lt = 0; lt < NPC_MAX_LT; lt++) {
                        for (ld = 0; ld < NPC_MAX_LD; ld++) {
@@ -221,8 +240,8 @@ static bool npc_check_overlap(struct rvu *rvu, int blkaddr,
                                if (!FIELD_GET(NPC_LDATA_EN, cfg))
                                        continue;
                                memset(dummy, 0, sizeof(struct npc_key_field));
-                               npc_set_layer_mdata(mcam, NPC_UNKNOWN, cfg,
-                                                   lid, lt, intf);
+                               npc_set_layer_mdata(rvu, mcam, NPC_UNKNOWN,
+                                                   cfg, lid, lt, intf);
                                /* exclude input */
                                if (npc_is_same(input, dummy))
                                        continue;
@@ -230,16 +249,50 @@ static bool npc_check_overlap(struct rvu *rvu, int blkaddr,
                                offset = (dummy->layer_mdata.key * 8) % 64;
                                nr_bits = dummy->layer_mdata.len * 8;
                                /* form KW masks */
-                               npc_set_kw_masks(mcam, NPC_UNKNOWN, nr_bits,
-                                                start_kwi, offset, intf);
+                               npc_set_kw_masks(rvu, mcam, NPC_UNKNOWN,
+                                                nr_bits, start_kwi,
+                                                offset, intf);
                                /* check any input field bits falls in any
                                 * other field bits.
                                 */
-                               if (npc_check_overlap_fields(dummy, input))
+                               if (npc_check_overlap_fields(dummy, input,
+                                                            kws))
                                        return true;
                        }
                }
        }
+       return false;
+
+skip_cn10k_config:
+       for (extr = 0 ; extr < rvu->hw->npc_kex_extr; extr++) {
+               lid = CN20K_GET_EXTR_LID(intf, extr);
+               if (lid < start_lid)
+                       continue;
+               for (lt = 0; lt < NPC_MAX_LT; lt++) {
+                       cfg = CN20K_GET_EXTR_LT(intf, extr, lt);
+                       if (!FIELD_GET(NPC_LDATA_EN, cfg))
+                               continue;
+
+                       memset(dummy, 0, sizeof(struct npc_key_field));
+                       npc_set_layer_mdata(rvu, mcam, NPC_UNKNOWN, cfg,
+                                           lid, lt, intf);
+                       /* exclude input */
+                       if (npc_is_same(input, dummy))
+                               continue;
+                       start_kwi = dummy->layer_mdata.key / 8;
+                       offset = (dummy->layer_mdata.key * 8) % 64;
+                       nr_bits = dummy->layer_mdata.len * 8;
+                       /* form KW masks */
+                       npc_set_kw_masks(rvu, mcam, NPC_UNKNOWN, nr_bits,
+                                        start_kwi, offset, intf);
+                       /* check any input field bits falls in any other
+                        * field bits
+                        */
+                       if (npc_check_overlap_fields(dummy, input,
+                                                    NPC_MAX_KWS_IN_KEY))
+                               return true;
+               }
+       }
 
        return false;
 }
@@ -253,7 +306,8 @@ static bool npc_check_field(struct rvu *rvu, int blkaddr, enum key_fields type,
        return true;
 }
 
-static void npc_scan_exact_result(struct npc_mcam *mcam, u8 bit_number,
+static void npc_scan_exact_result(struct rvu *rvu,
+                                 struct npc_mcam *mcam, u8 bit_number,
                                  u8 key_nibble, u8 intf)
 {
        u8 offset = (key_nibble * 4) % 64; /* offset within key word */
@@ -269,10 +323,63 @@ static void npc_scan_exact_result(struct npc_mcam *mcam, u8 bit_number,
        default:
                return;
        }
-       npc_set_kw_masks(mcam, type, nr_bits, kwi, offset, intf);
+       npc_set_kw_masks(rvu, mcam, type, nr_bits, kwi, offset, intf);
+}
+
+static void npc_cn20k_scan_parse_result(struct rvu *rvu, struct npc_mcam *mcam,
+                                       u8 bit_number, u8 key_nibble, u8 intf)
+{
+       u8 offset = (key_nibble * 4) % 64; /* offset within key word */
+       u8 kwi = (key_nibble * 4) / 64; /* which word in key */
+       u8 nr_bits = 4; /* bits in a nibble */
+       u8 type;
+
+       switch (bit_number) {
+       case 0 ... 2:
+               type = NPC_CHAN;
+               break;
+       case 3:
+               type = NPC_ERRLEV;
+               break;
+       case 4 ... 5:
+               type = NPC_ERRCODE;
+               break;
+       case 6:
+               type = NPC_LXMB;
+               break;
+       case 8:
+               type = NPC_LA;
+               break;
+       case 10:
+               type = NPC_LB;
+               break;
+       case 12:
+               type = NPC_LC;
+               break;
+       case 14:
+               type = NPC_LD;
+               break;
+       case 16:
+               type = NPC_LE;
+               break;
+       case 18:
+               type = NPC_LF;
+               break;
+       case 20:
+               type = NPC_LG;
+               break;
+       case 22:
+               type = NPC_LH;
+               break;
+       default:
+               return;
+       }
+
+       npc_set_kw_masks(rvu, mcam, type, nr_bits, kwi, offset, intf);
 }
 
-static void npc_scan_parse_result(struct npc_mcam *mcam, u8 bit_number,
+static void npc_scan_parse_result(struct rvu *rvu,
+                                 struct npc_mcam *mcam, u8 bit_number,
                                  u8 key_nibble, u8 intf)
 {
        u8 offset = (key_nibble * 4) % 64; /* offset within key word */
@@ -280,6 +387,12 @@ static void npc_scan_parse_result(struct npc_mcam *mcam, u8 bit_number,
        u8 nr_bits = 4; /* bits in a nibble */
        u8 type;
 
+       if (is_cn20k(rvu->pdev)) {
+               npc_cn20k_scan_parse_result(rvu, mcam, bit_number,
+                                           key_nibble, intf);
+               return;
+       }
+
        switch (bit_number) {
        case 0 ... 2:
                type = NPC_CHAN;
@@ -322,7 +435,7 @@ static void npc_scan_parse_result(struct npc_mcam *mcam, u8 bit_number,
                return;
        }
 
-       npc_set_kw_masks(mcam, type, nr_bits, kwi, offset, intf);
+       npc_set_kw_masks(rvu, mcam, type, nr_bits, kwi, offset, intf);
 }
 
 static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
@@ -343,8 +456,13 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
        /* Inner VLAN TCI for double tagged frames */
        struct npc_key_field *vlan_tag3;
        u64 *features;
+       int i, max_kw;
        u8 start_lid;
-       int i;
+
+       if (is_cn20k(rvu->pdev))
+               max_kw = NPC_MAX_KWS_IN_KEY;
+       else
+               max_kw = NPC_MAX_KWS_IN_KEY - 1;
 
        key_fields = mcam->rx_key_fields;
        features = &mcam->rx_features;
@@ -382,7 +500,7 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
 
        /* if key profile programmed extracts Ethertype from multiple layers */
        if (etype_ether->nr_kws && etype_tag1->nr_kws) {
-               for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
+               for (i = 0; i < max_kw; i++) {
                        if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i]) {
                                dev_err(rvu->dev, "mkex: Etype pos is different for untagged and tagged pkts.\n");
                                goto vlan_tci;
@@ -391,7 +509,7 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
                key_fields[NPC_ETYPE] = *etype_tag1;
        }
        if (etype_ether->nr_kws && etype_tag2->nr_kws) {
-               for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
+               for (i = 0; i < max_kw; i++) {
                        if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i]) {
                                dev_err(rvu->dev, "mkex: Etype pos is different for untagged and double tagged pkts.\n");
                                goto vlan_tci;
@@ -400,7 +518,7 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
                key_fields[NPC_ETYPE] = *etype_tag2;
        }
        if (etype_tag1->nr_kws && etype_tag2->nr_kws) {
-               for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
+               for (i = 0; i < max_kw; i++) {
                        if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i]) {
                                dev_err(rvu->dev, "mkex: Etype pos is different for tagged and double tagged pkts.\n");
                                goto vlan_tci;
@@ -431,7 +549,7 @@ vlan_tci:
 
        /* if key profile extracts outer vlan tci from multiple layers */
        if (vlan_tag1->nr_kws && vlan_tag2->nr_kws) {
-               for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
+               for (i = 0; i < max_kw; i++) {
                        if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i]) {
                                dev_err(rvu->dev, "mkex: Out vlan tci pos is different for tagged and double tagged pkts.\n");
                                goto done;
@@ -466,7 +584,11 @@ static void npc_scan_ldata(struct rvu *rvu, int blkaddr, u8 lid,
        /* starting KW index and starting bit position */
        int start_kwi, offset;
 
-       nr_bytes = FIELD_GET(NPC_BYTESM, cfg) + 1;
+       if (is_cn20k(rvu->pdev))
+               nr_bytes = FIELD_GET(NPC_CN20K_BYTESM, cfg) + 1;
+       else
+               nr_bytes = FIELD_GET(NPC_BYTESM, cfg) + 1;
+
        hdr = FIELD_GET(NPC_HDR_OFFSET, cfg);
        key = FIELD_GET(NPC_KEY_OFFSET, cfg);
 
@@ -489,11 +611,12 @@ do {                                                                             \
                if ((hstart) >= hdr &&                                         \
                    ((hstart) + (hlen)) <= (hdr + nr_bytes)) {                 \
                        bit_offset = (hdr + nr_bytes - (hstart) - (hlen)) * 8; \
-                       npc_set_layer_mdata(mcam, (name), cfg, lid, lt, intf); \
+                       npc_set_layer_mdata(rvu, mcam, (name), cfg, lid, lt,   \
+                                                                       intf); \
                        offset += bit_offset;                                  \
                        start_kwi += offset / 64;                              \
                        offset %= 64;                                          \
-                       npc_set_kw_masks(mcam, (name), (hlen) * 8,             \
+                       npc_set_kw_masks(rvu, mcam, (name), (hlen) * 8,        \
                                         start_kwi, offset, intf);             \
                }                                                              \
        }                                                                      \
@@ -636,6 +759,7 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, u8 intf)
        u8 lid, lt, ld, bitnr;
        u64 cfg, masked_cfg;
        u8 key_nibble = 0;
+       int extr;
 
        /* Scan and note how parse result is going to be in key.
         * A bit set in PARSE_NIBBLE_ENA corresponds to a nibble from
@@ -643,10 +767,22 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, u8 intf)
         * will be concatenated in key.
         */
        cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf));
-       masked_cfg = cfg & NPC_PARSE_NIBBLE;
-       for_each_set_bit(bitnr, (unsigned long *)&masked_cfg, 31) {
-               npc_scan_parse_result(mcam, bitnr, key_nibble, intf);
-               key_nibble++;
+       if (is_cn20k(rvu->pdev)) {
+               masked_cfg = cfg & NPC_CN20K_PARSE_NIBBLE;
+               for_each_set_bit(bitnr, (unsigned long *)&masked_cfg,
+                                NPC_CN20K_TOTAL_NIBBLE) {
+                       npc_scan_parse_result(rvu, mcam, bitnr,
+                                             key_nibble, intf);
+                       key_nibble++;
+               }
+       } else {
+               masked_cfg = cfg & NPC_PARSE_NIBBLE;
+               for_each_set_bit(bitnr, (unsigned long *)&masked_cfg,
+                                NPC_TOTAL_NIBBLE) {
+                       npc_scan_parse_result(rvu, mcam, bitnr,
+                                             key_nibble, intf);
+                       key_nibble++;
+               }
        }
 
        /* Ignore exact match bits for mcam entries except the first rule
@@ -656,10 +792,13 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, u8 intf)
        masked_cfg = cfg & NPC_EXACT_NIBBLE;
        bitnr = NPC_EXACT_NIBBLE_START;
        for_each_set_bit_from(bitnr, (unsigned long *)&masked_cfg, NPC_EXACT_NIBBLE_END + 1) {
-               npc_scan_exact_result(mcam, bitnr, key_nibble, intf);
+               npc_scan_exact_result(rvu, mcam, bitnr, key_nibble, intf);
                key_nibble++;
        }
 
+       if (is_cn20k(rvu->pdev))
+               goto skip_cn10k_config;
+
        /* Scan and note how layer data is going to be in key */
        for (lid = 0; lid < NPC_MAX_LID; lid++) {
                for (lt = 0; lt < NPC_MAX_LT; lt++) {
@@ -676,6 +815,19 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, u8 intf)
        }
 
        return 0;
+
+skip_cn10k_config:
+       for (extr = 0 ; extr < rvu->hw->npc_kex_extr; extr++) {
+               lid = CN20K_GET_EXTR_LID(intf, extr);
+               for (lt = 0; lt < NPC_MAX_LT; lt++) {
+                       cfg = CN20K_GET_EXTR_LT(intf, extr, lt);
+                       if (!FIELD_GET(NPC_LDATA_EN, cfg))
+                               continue;
+                       npc_scan_ldata(rvu, blkaddr, lid, lt, cfg,
+                                      intf);
+               }
+       }
+       return 0;
 }
 
 static int npc_scan_verify_kex(struct rvu *rvu, int blkaddr)
@@ -758,8 +910,8 @@ void npc_update_entry(struct rvu *rvu, enum key_fields type,
        struct mcam_entry dummy = { {0} };
        struct npc_key_field *field;
        u64 kw1, kw2, kw3;
+       int i, max_kw;
        u8 shift;
-       int i;
 
        field = &mcam->rx_key_fields[type];
        if (is_npc_intf_tx(intf))
@@ -768,7 +920,12 @@ void npc_update_entry(struct rvu *rvu, enum key_fields type,
        if (!field->nr_kws)
                return;
 
-       for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
+       if (is_cn20k(rvu->pdev))
+               max_kw = NPC_MAX_KWS_IN_KEY;
+       else
+               max_kw = NPC_MAX_KWS_IN_KEY - 1;
+
+       for (i = 0; i < max_kw; i++) {
                if (!field->kw_mask[i])
                        continue;
                /* place key value in kw[x] */
@@ -820,7 +977,7 @@ void npc_update_entry(struct rvu *rvu, enum key_fields type,
        /* dummy is ready with values and masks for given key
         * field now clear and update input entry with those
         */
-       for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
+       for (i = 0; i < max_kw; i++) {
                if (!field->kw_mask[i])
                        continue;
                entry->kw[i] &= ~field->kw_mask[i];
index 906d712cef1984635bc089ff4fee8b081fc436dc..beebcd6aa3d89259305fa22e0e64d549a2446bbb 100644 (file)
@@ -125,6 +125,9 @@ static void npc_program_mkex_hash_rx(struct rvu *rvu, int blkaddr,
        struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash;
        int lid, lt, ld, hash_cnt = 0;
 
+       if (is_cn20k(rvu->pdev))
+               return;
+
        if (is_npc_intf_tx(intf))
                return;
 
@@ -165,6 +168,9 @@ static void npc_program_mkex_hash_tx(struct rvu *rvu, int blkaddr,
        struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash;
        int lid, lt, ld, hash_cnt = 0;
 
+       if (is_cn20k(rvu->pdev))
+               return;
+
        if (is_npc_intf_rx(intf))
                return;
 
@@ -224,6 +230,9 @@ void npc_program_mkex_hash(struct rvu *rvu, int blkaddr)
        struct rvu_hwinfo *hw = rvu->hw;
        u64 cfg;
 
+       if (is_cn20k(rvu->pdev))
+               return;
+
        /* Check if hardware supports hash extraction */
        if (!hwcap->npc_hash_extract)
                return;
@@ -288,6 +297,9 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf,
        u32 field_hash;
        u8 hash_idx;
 
+       if (is_cn20k(rvu->pdev))
+               return;
+
        if (!rvu->hw->cap.npc_hash_extract) {
                dev_dbg(rvu->dev, "%s: Field hash extract feature is not supported\n", __func__);
                return;
@@ -1874,6 +1886,9 @@ int rvu_npc_exact_init(struct rvu *rvu)
        u64 cfg;
        bool rc;
 
+       if (is_cn20k(rvu->pdev))
+               return 0;
+
        /* Read NPC_AF_CONST3 and check for have exact
         * match functionality is present
         */