]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
octeontx2-af: npc: cn20k: KPM profile changes
authorSuman Ghosh <sumang@marvell.com>
Tue, 24 Feb 2026 07:59:58 +0000 (13:29 +0530)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Feb 2026 18:29:25 +0000 (10:29 -0800)
KPU (Kangaroo Processing Unit) profiles are primarily used to set the
required packet pointers that will be used in later stages for key
generation. In the new CN20K silicon variant, a new KPM profile is
introduced alongside the existing KPU profiles.

In CN20K, a total of 16 KPUs are grouped into 8 KPM profiles. As per
the current hardware design, each KPM configuration contains a
combination of 2 KPUs:
    KPM0 = KPU0 + KPU8
    KPM1 = KPU1 + KPU9
    ...
    KPM7 = KPU7 + KPU15

This configuration enables more efficient use of KPU resources. This
patch adds support for the new KPM profile configuration.

Signed-off-by: Suman Ghosh <sumang@marvell.com>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260224080009.4147301-3-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/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h [new file with mode: 0644]

index 4ee946380212227e4db052bdfe1a08034e7d92ab..f65db0698c33e2ffb8ee80d36164fe8b2a56b5a0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "cn20k/npc.h"
 #include "cn20k/reg.h"
+#include "rvu_npc.h"
 
 static struct npc_priv_t npc_priv = {
        .num_banks = MAX_NUM_BANKS,
@@ -20,6 +21,234 @@ static const char *npc_kw_name[NPC_MCAM_KEY_MAX] = {
        [NPC_MCAM_KEY_X4] = "X4",
 };
 
+static void npc_config_kpmcam(struct rvu *rvu, int blkaddr,
+                             const struct npc_kpu_profile_cam *kpucam,
+                             int kpm, int entry)
+{
+       struct npc_kpu_cam cam0 = {0};
+       struct npc_kpu_cam cam1 = {0};
+
+       cam1.state = kpucam->state & kpucam->state_mask;
+       cam1.dp0_data = kpucam->dp0 & kpucam->dp0_mask;
+       cam1.dp1_data = kpucam->dp1 & kpucam->dp1_mask;
+       cam1.dp2_data = kpucam->dp2 & kpucam->dp2_mask;
+
+       cam0.state = ~kpucam->state & kpucam->state_mask;
+       cam0.dp0_data = ~kpucam->dp0 & kpucam->dp0_mask;
+       cam0.dp1_data = ~kpucam->dp1 & kpucam->dp1_mask;
+       cam0.dp2_data = ~kpucam->dp2 & kpucam->dp2_mask;
+
+       rvu_write64(rvu, blkaddr,
+                   NPC_AF_KPMX_ENTRYX_CAMX(kpm, entry, 0), *(u64 *)&cam0);
+       rvu_write64(rvu, blkaddr,
+                   NPC_AF_KPMX_ENTRYX_CAMX(kpm, entry, 1), *(u64 *)&cam1);
+}
+
+static void
+npc_config_kpmaction(struct rvu *rvu, int blkaddr,
+                    const struct npc_kpu_profile_action *kpuaction,
+                    int kpm, int entry, bool pkind)
+{
+       struct npc_kpm_action0 action0 = {0};
+       struct npc_kpu_action1 action1 = {0};
+       u64 reg;
+
+       action1.errlev = kpuaction->errlev;
+       action1.errcode = kpuaction->errcode;
+       action1.dp0_offset = kpuaction->dp0_offset;
+       action1.dp1_offset = kpuaction->dp1_offset;
+       action1.dp2_offset = kpuaction->dp2_offset;
+
+       if (pkind)
+               reg = NPC_AF_PKINDX_ACTION1(entry);
+       else
+               reg = NPC_AF_KPMX_ENTRYX_ACTION1(kpm, entry);
+
+       rvu_write64(rvu, blkaddr, reg, *(u64 *)&action1);
+
+       action0.byp_count = kpuaction->bypass_count & 0x7;
+       action0.capture_ena = kpuaction->cap_ena & 1;
+       action0.parse_done = kpuaction->parse_done & 1;
+       action0.next_state = kpuaction->next_state & 0xf;
+       action0.capture_lid = kpuaction->lid & 0x7;
+
+       /* Parser functionality will work correctly even though
+        * upper flag bits are silently discarded
+        */
+       action0.capture_ltype = kpuaction->ltype & 0xf;
+       action0.capture_flags = kpuaction->flags & 0xf;
+       action0.ptr_advance = kpuaction->ptr_advance;
+
+       action0.var_len_offset = kpuaction->offset;
+       action0.var_len_mask = kpuaction->mask;
+       action0.var_len_right = kpuaction->right & 1;
+       action0.var_len_shift = kpuaction->shift & 1;
+
+       if (pkind)
+               reg = NPC_AF_PKINDX_ACTION0(entry);
+       else
+               reg = NPC_AF_KPMX_ENTRYX_ACTION0(kpm, entry);
+
+       rvu_write64(rvu, blkaddr, reg, *(u64 *)&action0);
+}
+
+static void
+npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,
+                              int kpm, int start_entry,
+                              const struct npc_kpu_profile *profile)
+{
+       int entry, num_entries, max_entries;
+       u64 idx;
+
+       if (profile->cam_entries != profile->action_entries) {
+               dev_err(rvu->dev,
+                       "kpm%d: CAM and action entries [%d != %d] not equal\n",
+                       kpm, profile->cam_entries, profile->action_entries);
+
+               WARN(1, "Fatal error\n");
+               return;
+       }
+
+       max_entries = rvu->hw->npc_kpu_entries / 2;
+       entry = start_entry;
+       /* Program CAM match entries for previous kpm extracted data */
+       num_entries = min_t(int, profile->cam_entries, max_entries);
+       for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
+               npc_config_kpmcam(rvu, blkaddr, &profile->cam[idx],
+                                 kpm, entry);
+
+       entry = start_entry;
+       /* Program this kpm's actions */
+       num_entries = min_t(int, profile->action_entries, max_entries);
+       for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
+               npc_config_kpmaction(rvu, blkaddr, &profile->action[idx],
+                                    kpm, entry, false);
+}
+
+static void
+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 */
+       if (!rvu->kpu.custom)
+               entry_mask |= GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0);
+       rvu_write64(rvu, blkaddr,
+                   NPC_AF_KPMX_ENTRY_DISX(kpm, 0), entry_mask);
+       if (num_entries <= 64) {
+               /* Disable all the entries in W1, W2 and W3 */
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(kpm, 1),
+                           npc_enable_mask(0));
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(kpm, 2),
+                           npc_enable_mask(0));
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(kpm, 3),
+                           npc_enable_mask(0));
+               return;
+       }
+
+       num_entries = num_entries - 64;
+       entry_mask = npc_enable_mask(num_entries);
+       rvu_write64(rvu, blkaddr,
+                   NPC_AF_KPMX_ENTRY_DISX(kpm, 1), entry_mask);
+       if (num_entries <= 64) {
+               /* Disable all the entries in W2 and W3 */
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(kpm, 2),
+                           npc_enable_mask(0));
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(kpm, 3),
+                           npc_enable_mask(0));
+               return;
+       }
+
+       num_entries = num_entries - 64;
+       entry_mask = npc_enable_mask(num_entries);
+       rvu_write64(rvu, blkaddr,
+                   NPC_AF_KPMX_ENTRY_DISX(kpm, 2), entry_mask);
+       if (num_entries <= 64) {
+               /* Disable all the entries in W3 */
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(kpm, 3),
+                           npc_enable_mask(0));
+               return;
+       }
+
+       num_entries = num_entries - 64;
+       entry_mask = npc_enable_mask(num_entries);
+       rvu_write64(rvu, blkaddr,
+                   NPC_AF_KPMX_ENTRY_DISX(kpm, 3), entry_mask);
+}
+
+#define KPU_OFFSET     8
+static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)
+{
+       const struct npc_kpu_profile *profile1, *profile2;
+       int idx, total_cam_entries;
+
+       for (idx = 0; idx < num_kpms; idx++) {
+               profile1 = &rvu->kpu.kpu[idx];
+               npc_program_single_kpm_profile(rvu, blkaddr, idx, 0, profile1);
+               profile2 = &rvu->kpu.kpu[idx + KPU_OFFSET];
+               npc_program_single_kpm_profile(rvu, blkaddr, idx,
+                                              profile1->cam_entries,
+                                              profile2);
+               total_cam_entries = profile1->cam_entries +
+                       profile2->cam_entries;
+               npc_enable_kpm_entry(rvu, blkaddr, idx, total_cam_entries);
+               rvu_write64(rvu, blkaddr, NPC_AF_KPMX_PASS2_OFFSET(idx),
+                           profile1->cam_entries);
+               /* Enable the KPUs associated with this KPM */
+               rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x01);
+               rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx + KPU_OFFSET),
+                           0x01);
+       }
+}
+
+void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)
+{
+       struct rvu_hwinfo *hw = rvu->hw;
+       int num_pkinds, idx;
+
+       /* Disable all KPMs and their entries */
+       for (idx = 0; idx < hw->npc_kpms; idx++) {
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(idx, 0), ~0ULL);
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(idx, 1), ~0ULL);
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(idx, 2), ~0ULL);
+               rvu_write64(rvu, blkaddr,
+                           NPC_AF_KPMX_ENTRY_DISX(idx, 3), ~0ULL);
+       }
+
+       for (idx = 0; idx < hw->npc_kpus; idx++)
+               rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x00);
+
+       /* Load and customize KPU profile. */
+       npc_load_kpu_profile(rvu);
+
+       /* Configure KPU and KPM mapping for second pass */
+       rvu_write64(rvu, blkaddr, NPC_AF_KPM_PASS2_CFG, 0x76543210);
+
+       /* First program IKPU profile i.e PKIND configs.
+        * Check HW max count to avoid configuring junk or
+        * writing to unsupported CSR addresses.
+        */
+       num_pkinds = rvu->kpu.pkinds;
+       num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
+
+       for (idx = 0; idx < num_pkinds; idx++)
+               npc_config_kpmaction(rvu, blkaddr, &rvu->kpu.ikpu[idx],
+                                    0, idx, true);
+
+       /* Program KPM CAM and Action profiles */
+       npc_program_kpm_profile(rvu, blkaddr, hw->npc_kpms);
+}
+
 struct npc_priv_t *npc_priv_get(void)
 {
        return &npc_priv;
index d54253fd1e68fbfd86eb4e14f66fd8905769126a..fb4d5f4634618d2b41636b93f64ba2cb1cf937f2 100644 (file)
@@ -94,6 +94,42 @@ struct npc_priv_t {
        bool init_done;
 };
 
+struct npc_kpm_action0 {
+#if defined(__BIG_ENDIAN_BITFIELD)
+       u64 rsvd_63_57     : 7;
+       u64 byp_count      : 3;
+       u64 capture_ena    : 1;
+       u64 parse_done     : 1;
+       u64 next_state     : 8;
+       u64 rsvd_43        : 1;
+       u64 capture_lid    : 3;
+       u64 capture_ltype  : 4;
+       u64 rsvd_32_35     : 4;
+       u64 capture_flags  : 4;
+       u64 ptr_advance    : 8;
+       u64 var_len_offset : 8;
+       u64 var_len_mask   : 8;
+       u64 var_len_right  : 1;
+       u64 var_len_shift  : 3;
+#else
+       u64 var_len_shift  : 3;
+       u64 var_len_right  : 1;
+       u64 var_len_mask   : 8;
+       u64 var_len_offset : 8;
+       u64 ptr_advance    : 8;
+       u64 capture_flags  : 4;
+       u64 rsvd_32_35     : 4;
+       u64 capture_ltype  : 4;
+       u64 capture_lid    : 3;
+       u64 rsvd_43        : 1;
+       u64 next_state     : 8;
+       u64 parse_done     : 1;
+       u64 capture_ena    : 1;
+       u64 byp_count      : 3;
+       u64 rsvd_63_57     : 7;
+#endif
+};
+
 struct rvu;
 
 struct npc_priv_t *npc_priv_get(void);
@@ -107,4 +143,5 @@ int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifunc, int key_type,
                            int prio, u16 *mcam_idx, int ref, int limit,
                            bool contig, int count);
 int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count);
+void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr);
 #endif /* NPC_CN20K_H */
index 098b0247848b1137a83fc757c796908a35e213ec..073d4b815681db2eca18ef5ae66dd9a216804754 100644 (file)
 #define RVU_MBOX_VF_INT_ENA_W1S                        (0x30)
 #define RVU_MBOX_VF_INT_ENA_W1C                        (0x38)
 
+#define RVU_MBOX_VF_VFAF_TRIGX(a)              (0x2000 | (a) << 3)
 /* NPC registers */
-#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3)
+#define NPC_AF_INTFX_EXTRACTORX_CFG(a, b) \
+       (0x908000ull | (a) << 10 | (b) << 3)
+#define NPC_AF_INTFX_EXTRACTORX_LTX_CFG(a, b, c) \
+       (0x900000ull | (a) << 13 | (b) << 8  | (c) << 3)
+#define NPC_AF_KPMX_ENTRYX_CAMX(a, b, c) \
+       (0x100000ull | (a) << 14 | (b) << 6 | (c) << 3)
+#define NPC_AF_KPMX_ENTRYX_ACTION0(a, b) \
+       (0x100020ull | (a) << 14 | (b) << 6)
+#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)
 
-#define RVU_MBOX_VF_VFAF_TRIGX(a)              (0x2000 | (a) << 3)
 #endif /* RVU_MBOX_REG_H */
index e85dac2c806d9fb0fb033abb1035428fa937edbf..14ca28ab493a8b13c18db229f9d6b8fb88837352 100644 (file)
@@ -447,9 +447,11 @@ struct rvu_hwinfo {
        u8      sdp_links;
        u8      cpt_links;      /* Number of CPT links */
        u8      npc_kpus;          /* No of parser units */
+       u8      npc_kpms;       /* Number of enhanced parser units */
+       u8      npc_kex_extr;   /* Number of LDATA extractors per KEX */
        u8      npc_pkinds;        /* No of port kinds */
        u8      npc_intfs;         /* No of interfaces */
-       u     npc_kpu_entries;   /* No of KPU entries */
+       u16     npc_kpu_entries;   /* No of KPU entries */
        u16     npc_counters;      /* No of match stats counters */
        u32     lbk_bufsize;       /* FIFO size supported by LBK */
        bool    npc_ext_set;       /* Extended register set */
index 638d6d1f2071d998a579eea4b17ca5796a68ac87..a113cab1e1a53fcaec3453a07e5e7cf1f41fe256 100644 (file)
@@ -17,6 +17,7 @@
 #include "npc_profile.h"
 #include "rvu_npc_hash.h"
 #include "cn20k/npc.h"
+#include "rvu_npc.h"
 
 #define RSVD_MCAM_ENTRIES_PER_PF       3 /* Broadcast, Promisc and AllMulticast */
 #define RSVD_MCAM_ENTRIES_PER_NIXLF    1 /* Ucast for LFs */
@@ -1413,9 +1414,9 @@ program_mkex:
                iounmap(mkex_prfl_addr);
 }
 
-static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
-                                const struct npc_kpu_profile_action *kpuaction,
-                                int kpu, int entry, bool pkind)
+void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
+                         const struct npc_kpu_profile_action *kpuaction,
+                         int kpu, int entry, bool pkind)
 {
        struct npc_kpu_action0 action0 = {0};
        struct npc_kpu_action1 action1 = {0};
@@ -1478,7 +1479,7 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,
                    NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 1), *(u64 *)&cam1);
 }
 
-static inline u64 enable_mask(int count)
+u64 npc_enable_mask(int count)
 {
        return (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL));
 }
@@ -1511,7 +1512,7 @@ static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
 
        /* Enable all programmed entries */
        num_entries = min_t(int, profile->action_entries, profile->cam_entries);
-       entry_mask = enable_mask(num_entries);
+       entry_mask = npc_enable_mask(num_entries);
        /* Disable first KPU_MAX_CST_ENT entries for built-in profile */
        if (!rvu->kpu.custom)
                entry_mask |= GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0);
@@ -1520,7 +1521,7 @@ static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
        if (num_entries > 64) {
                rvu_write64(rvu, blkaddr,
                            NPC_AF_KPUX_ENTRY_DISX(kpu, 1),
-                           enable_mask(num_entries - 64));
+                           npc_enable_mask(num_entries - 64));
        }
 
        /* Enable this KPU */
@@ -1708,7 +1709,7 @@ done:
        return ret;
 }
 
-static void npc_load_kpu_profile(struct rvu *rvu)
+void npc_load_kpu_profile(struct rvu *rvu)
 {
        struct npc_kpu_profile_adapter *profile = &rvu->kpu;
        const char *kpu_profile = rvu->kpu_pfl_name;
@@ -1850,12 +1851,19 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
        mcam->keysize = cfg;
 
        /* Number of banks combined per MCAM entry */
-       if (cfg == NPC_MCAM_KEY_X4)
-               mcam->banks_per_entry = 4;
-       else if (cfg == NPC_MCAM_KEY_X2)
-               mcam->banks_per_entry = 2;
-       else
-               mcam->banks_per_entry = 1;
+       if (is_cn20k(rvu->pdev)) {
+               if (cfg == NPC_MCAM_KEY_X2)
+                       mcam->banks_per_entry = 1;
+               else
+                       mcam->banks_per_entry = 2;
+       } else {
+               if (cfg == NPC_MCAM_KEY_X4)
+                       mcam->banks_per_entry = 4;
+               else if (cfg == NPC_MCAM_KEY_X2)
+                       mcam->banks_per_entry = 2;
+               else
+                       mcam->banks_per_entry = 1;
+       }
 
        /* Reserve one MCAM entry for each of the NIX LF to
         * guarantee space to install default matching DMAC rule.
@@ -1985,6 +1993,19 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blkaddr)
        hw->npc_pkinds = (npc_const1 >> 12) & 0xFFULL;
        hw->npc_kpu_entries = npc_const1 & 0xFFFULL;
        hw->npc_kpus = (npc_const >> 8) & 0x1FULL;
+       /* For Cn20k silicon, check if enhanced parser
+        * is present, then set the NUM_KPMS = NUM_KPUS / 2 and
+        * number of LDATA extractors per KEX.
+        */
+       if (is_cn20k(rvu->pdev)) {
+               if (!(npc_const1 & BIT_ULL(62))) {
+                       WARN(1, "Enhanced parser is not supported\n");
+                       return;
+               }
+               hw->npc_kpms = hw->npc_kpus / 2;
+               hw->npc_kex_extr = (npc_const1 >> 36) & 0x3FULL;
+       }
+
        hw->npc_intfs = npc_const & 0xFULL;
        hw->npc_counters = (npc_const >> 48) & 0xFFFFULL;
 
@@ -2119,7 +2140,10 @@ int rvu_npc_init(struct rvu *rvu)
                return -ENOMEM;
 
        /* Configure KPU profile */
-       npc_parser_profile_init(rvu, blkaddr);
+       if (is_cn20k(rvu->pdev))
+               npc_cn20k_parser_profile_init(rvu, blkaddr);
+       else
+               npc_parser_profile_init(rvu, blkaddr);
 
        /* Config Outer L2, IPv4's NPC layer info */
        rvu_write64(rvu, blkaddr, NPC_AF_PCK_DEF_OL2,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h
new file mode 100644 (file)
index 0000000..80c6361
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell RVU Admin Function driver
+ *
+ * Copyright (C) 2026 Marvell.
+ *
+ */
+
+#ifndef RVU_NPC_H
+#define RVU_NPC_H
+
+u64 npc_enable_mask(int count);
+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);
+
+#endif /* RVU_NPC_H */