Commit 5868682b authored by Suman Ghosh's avatar Suman Ghosh Committed by Jakub Kicinski
Browse files

octeontx2-af: npc: cn20k: KPM profile changes



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: default avatarSuman Ghosh <sumang@marvell.com>
Signed-off-by: default avatarRatheesh Kannoth <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260224080009.4147301-3-rkannoth@marvell.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 1396771b
Loading
Loading
Loading
Loading
+229 −0
Original line number Diff line number Diff line
@@ -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;
+37 −0
Original line number Diff line number Diff line
@@ -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 */
+15 −2
Original line number Diff line number Diff line
@@ -77,8 +77,21 @@
#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 */
+3 −1
Original line number Diff line number Diff line
@@ -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 */
	u8	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 */
+38 −14
Original line number Diff line number Diff line
@@ -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,7 +1414,7 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
		iounmap(mkex_prfl_addr);
}

static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
			  const struct npc_kpu_profile_action *kpuaction,
			  int kpu, int entry, bool pkind)
{
@@ -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 @@ static int npc_load_kpu_profile_fwdb(struct rvu *rvu, const char *kpu_profile)
	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 (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,6 +2140,9 @@ int rvu_npc_init(struct rvu *rvu)
		return -ENOMEM;

	/* Configure KPU profile */
	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 */
Loading