octeontx2-af: npc: cn20k: MKEX profile support

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>
This commit is contained in:
Suman Ghosh
2026-02-24 13:30:00 +05:30
committed by Jakub Kicinski
parent a2df2f95ea
commit ef992a0f12
11 changed files with 809 additions and 70 deletions

View 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;

View 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 */

View File

@@ -80,18 +80,60 @@
#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 */

View 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)

View 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)

View 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,

View 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;

View 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 @@ void npc_load_kpu_profile(struct rvu *rvu)
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))

View 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 */

View 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_scan_parse_result(struct npc_mcam *mcam, u8 bit_number,
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 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 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
/* 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];

View 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
*/