In CN20K, the PF/VF driver is unaware of the NPC MCAM entry type (x2/x4)
required for a particular TC rule when the user installs rules through the
TC command. This forces the PF/VF driver to first query the AF driver for
the rule size, then allocate an entry, and finally install the flow. This
sequence requires three mailbox request/response exchanges from the PF. To
speed up the installation, the `install_flow` mailbox request message is
extended with additional fields that allow the AF driver to determine the
required NPC MCAM entry type, allocate the MCAM entry, and complete the
flow installation in a single step.
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 184 ++++++++++--
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 5 +-
.../net/ethernet/marvell/octeontx2/af/mbox.h | 48 ++++
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 4 +
.../marvell/octeontx2/af/rvu_npc_fs.c | 137 ++++++++-
.../marvell/octeontx2/af/rvu_npc_fs.h | 12 +
.../marvell/octeontx2/nic/otx2_flows.c | 265 +++++++++++++++++-
7 files changed, 598 insertions(+), 57 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7306414d1cf2..237e6f606fc1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -14,6 +14,7 @@
#include "rvu_npc.h"
#include "cn20k/npc.h"
#include "cn20k/reg.h"
+#include "rvu_npc_fs.h"
static struct npc_priv_t npc_priv = {
.num_banks = MAX_NUM_BANKS,
@@ -799,7 +800,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
bank));
- hw_prio = cfg & GENMASK_ULL(14, 8);
+ hw_prio = cfg & GENMASK_ULL(30, 24);
cfg = enable ? 1 : 0;
cfg |= hw_prio;
rvu_write64(rvu, blkaddr,
@@ -815,7 +816,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
bank));
- hw_prio = cfg & GENMASK_ULL(14, 8);
+ hw_prio = cfg & GENMASK_ULL(30, 24);
cfg = enable ? 1 : 0;
cfg |= hw_prio;
rvu_write64(rvu, blkaddr,
@@ -882,25 +883,33 @@ static void npc_cn20k_get_keyword(struct cn20k_mcam_entry *entry, int idx,
*cam0 = ~*cam1 & kw_mask;
}
-/*-----------------------------------------------------------------------------|
- *Kex type | mcam entry | cam1 | cam 0 || <----- output ----> |
- *profile | len | (key type) | (key type) || len | type |
- *-----------------------------------------------------------------------------|
- *X2 | 256 (X2) | 001b | 110b || X2 | X2 |
- *-----------------------------------------------------------------------------|
- *X4 | 256 (X2) | 000b | 000b || X2 | DYNAMIC |
- *-----------------------------------------------------------------------------|
- *X4 | 512 (X4) | 010b | 101b || X4 | X4 |
- *-----------------------------------------------------------------------------|
- *DYN | 256 (X2) | 000b | 000b || X2 | DYNAMIC |
- *-----------------------------------------------------------------------------|
- *DYN | 512 (X4) | 010b | 101b || X4 | X4 |
- *-----------------------------------------------------------------------------|
+/*-------------------------------------------------------------------------
+ *Kex type| mcam | cam1 |cam0 | req_kwtype||<----- output > |
+ * in | | | | || | |
+ * profile| len | | | ||len | type |
+ *-------------------------------------------------------------------------
+ *X2 | 256 (X2) | 001b |110b | 0 ||X2 | X2 |
+ *------------------------------------------------------------------------|
+ *X4 | 256 (X2) | 000b |000b | 0 ||X2 | DYN |
+ *------------------------------------------------------------------------|
+ *X4 | 512 (X4) | 010b |101b | 0 ||X4 | X4 |
+ *------------------------------------------------------------------------|
+ *DYN | 256 (X2) | 000b |000b | 0 ||X2 | DYN |
+ *------------------------------------------------------------------------|
+ *DYN | 512 (X4) | 010b |101b | 0 ||X4 | X4 |
+ *------------------------------------------------------------------------|
+ *X4 | 256 (X2) | 000b |000b | X2 ||DYN | DYN |
+ *------------------------------------------------------------------------|
+ *DYNC | 256 (X2) | 000b |000b | X2 ||DYN | DYN |
+ *------------------------------------------------------------------------|
+ * X2 | 512 (X4) | xxxb |xxxb | X4 ||INVAL | INVAL |
+ *------------------------------------------------------------------------|
*/
static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, int index, u8 intf,
struct cn20k_mcam_entry *entry,
- int bank, u8 kw_type, int kw)
+ int bank, u8 kw_type, int kw,
+ u8 req_kw_type)
{
u64 intf_ext = 0, intf_ext_mask = 0;
u8 tx_intf_mask = ~intf & 0x3;
@@ -925,6 +934,15 @@ static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam,
kw_type_mask = 0;
}
+ /* Say, we need to write x2 keyword in an x4 subbank.
+ * req_kw_type will be x2, and kw_type will be x4.
+ * So in the case ignore kw bits in mcam.
+ */
+ if (kw_type == NPC_MCAM_KEY_X4 && req_kw_type == NPC_MCAM_KEY_X2) {
+ kw_type = 0;
+ kw_type_mask = 0;
+ }
+
intf_ext = ((u64)kw_type << 16) | tx_intf;
intf_ext_mask = (((u64)kw_type_mask << 16) & GENMASK_ULL(18, 16)) |
tx_intf_mask;
@@ -972,14 +990,15 @@ static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam,
static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, int index, u8 intf,
struct cn20k_mcam_entry *entry,
- u8 kw_type)
+ u8 kw_type, u8 req_kw_type)
{
int kw = 0, bank;
for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4)
npc_cn20k_config_kw_x2(rvu, mcam, blkaddr,
index, intf,
- entry, bank, kw_type, kw);
+ entry, bank, kw_type,
+ kw, req_kw_type);
}
static void
@@ -989,7 +1008,7 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 bank_cfg;
- bank_cfg = (u64)hw_prio << 8;
+ bank_cfg = (u64)hw_prio << 24;
if (enable)
bank_cfg |= 0x1;
@@ -1012,7 +1031,7 @@ npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
u8 intf, struct cn20k_mcam_entry *entry,
- bool enable, u8 hw_prio)
+ bool enable, u8 hw_prio, u8 req_kw_type)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
int mcam_idx = index % mcam->banksize;
@@ -1035,27 +1054,34 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
npc_cn20k_clear_mcam_entry(rvu, blkaddr, bank, mcam_idx);
npc_cn20k_config_kw_x2(rvu, mcam, blkaddr,
mcam_idx, intf, entry,
- bank, kw_type, kw);
+ bank, kw_type, kw, req_kw_type);
/* Set 'action' */
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
bank, 0),
entry->action);
+ /* Set 'action2' for inline receive */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 2),
+ entry->action2);
+
/* Set TAG 'action' */
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
bank, 1),
entry->vtag_action);
-
goto set_cfg;
}
+
/* Clear mcam entry to avoid writes being suppressed by NPC */
npc_cn20k_clear_mcam_entry(rvu, blkaddr, 0, mcam_idx);
npc_cn20k_clear_mcam_entry(rvu, blkaddr, 1, mcam_idx);
npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
- mcam_idx, intf, entry, kw_type);
+ mcam_idx, intf, entry,
+ kw_type, req_kw_type);
for (bank = 0; bank < mcam->banks_per_entry; bank++) {
/* Set 'action' */
rvu_write64(rvu, blkaddr,
@@ -1068,6 +1094,12 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
bank, 1),
entry->vtag_action);
+
+ /* Set 'action2' for inline receive */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 2),
+ entry->action2);
}
set_cfg:
@@ -1156,7 +1188,7 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
bank_cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(index, bank));
*ena = bank_cfg & 0x1;
- *hw_prio = (bank_cfg & GENMASK_ULL(14, 8)) >> 8;
+ *hw_prio = (bank_cfg & GENMASK_ULL(30, 24)) >> 24;
if (kw_type == NPC_MCAM_KEY_X2) {
cam1 = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index,
@@ -1292,7 +1324,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
&req->entry_data, req->enable_entry,
- req->hw_prio);
+ req->hw_prio, req->req_kw_type);
rc = 0;
exit:
@@ -1370,7 +1402,7 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
&req->entry_data, req->enable_entry,
- req->hw_prio);
+ req->hw_prio, req->req_kw_type);
mutex_unlock(&mcam->lock);
@@ -1378,6 +1410,14 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
return 0;
}
+static int rvu_npc_get_base_steer_rule_type(struct rvu *rvu, u16 pcifunc)
+{
+ if (is_lbk_vf(rvu, pcifunc))
+ return NIXLF_PROMISC_ENTRY;
+
+ return NIXLF_UCAST_ENTRY;
+}
+
int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
struct msg_req *req,
struct npc_cn20k_mcam_read_base_rule_rsp *rsp)
@@ -1387,6 +1427,7 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
u16 pcifunc = req->hdr.pcifunc;
u8 intf, enable, hw_prio;
struct rvu_pfvf *pfvf;
+ int rl_type;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
@@ -1412,9 +1453,11 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
mutex_unlock(&mcam->lock);
goto out;
}
+
+ rl_type = rvu_npc_get_base_steer_rule_type(rvu, pcifunc);
+
/* Read the default ucast entry if there is no pkt steering rule */
- index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
- NIXLF_UCAST_ENTRY);
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, rl_type);
read_entry:
/* Read the mcam entry */
npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
@@ -3888,6 +3931,89 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
return set ? 0 : -ESRCH;
}
+int rvu_mbox_handler_npc_get_pfl_info(struct rvu *rvu, struct msg_req *req,
+ struct npc_get_pfl_info_rsp *rsp)
+{
+ if (!is_cn20k(rvu->pdev)) {
+ dev_err(rvu->dev, "Mbox support is only for cn20k\n");
+ return -EOPNOTSUPP;
+ }
+
+ rsp->kw_type = npc_priv.kw;
+ rsp->x4_slots = npc_priv.bank_depth;
+ return 0;
+}
+
+int rvu_mbox_handler_npc_get_num_kws(struct rvu *rvu,
+ struct npc_get_num_kws_req *req,
+ struct npc_get_num_kws_rsp *rsp)
+{
+ struct rvu_npc_mcam_rule dummy = { 0 };
+ struct cn20k_mcam_entry cn20k_entry = { 0 };
+ struct mcam_entry_mdata mdata = { };
+ struct mcam_entry entry = { 0 };
+ struct npc_install_flow_req *fl;
+ int i, cnt = 0, blkaddr;
+
+ if (!is_cn20k(rvu->pdev)) {
+ dev_err(rvu->dev, "Mbox support is only for cn20k\n");
+ return -EOPNOTSUPP;
+ }
+
+ fl = &req->fl;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0) {
+ dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
+ return NPC_MCAM_INVALID_REQ;
+ }
+
+ npc_populate_mcam_mdata(rvu, &mdata, &cn20k_entry, &entry);
+
+ npc_update_flow(rvu, &mdata, fl->features, &fl->packet,
+ &fl->mask, &dummy, fl->intf, blkaddr);
+
+ /* Find the most significant word valid. Traverse from
+ * MSB to LSB, check if cam0 or cam1 is set
+ */
+ for (i = NPC_CN20K_MAX_KWS_IN_KEY - 1; i >= 0; i--) {
+ if (cn20k_entry.kw[i] || cn20k_entry.kw_mask[i]) {
+ cnt = i + 1;
+ break;
+ }
+ }
+
+ rsp->kws = cnt;
+
+ return 0;
+}
+
+int rvu_mbox_handler_npc_get_dft_rl_idxs(struct rvu *rvu, struct msg_req *req,
+ struct npc_get_dft_rl_idxs_rsp *rsp)
+{
+ u16 bcast, mcast, promisc, ucast;
+ u16 pcifunc;
+ int rc;
+
+ if (!is_cn20k(rvu->pdev)) {
+ dev_err(rvu->dev, "Mbox support is only for cn20k\n");
+ return -EOPNOTSUPP;
+ }
+
+ pcifunc = req->hdr.pcifunc;
+
+ rc = npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &bcast, &mcast,
+ &promisc, &ucast);
+ if (rc)
+ return rc;
+
+ rsp->bcast = bcast;
+ rsp->mcast = mcast;
+ rsp->promisc = promisc;
+ rsp->ucast = ucast;
+ return 0;
+}
+
static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
{
return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) ||
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 178051b2535a..12a76aaa5317 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -321,9 +321,8 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
u16 *mcast, u16 *promisc, u16 *ucast);
void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
- u8 intf,
- struct cn20k_mcam_entry *entry,
- bool enable, u8 hw_prio);
+ u8 intf, struct cn20k_mcam_entry *entry,
+ bool enable, u8 hw_prio, u8 req_kw_type);
void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
int index, bool enable);
void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 1638bf4e15fd..79cb1c752c2b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -301,6 +301,15 @@ M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_read_base_steer_rule, \
M(NPC_MCAM_DEFRAG, 0x601b, npc_defrag, \
msg_req, \
msg_rsp) \
+M(NPC_MCAM_GET_NUM_KWS, 0x601c, npc_get_num_kws, \
+ npc_get_num_kws_req, \
+ npc_get_num_kws_rsp) \
+M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601d, npc_get_dft_rl_idxs, \
+ msg_req, \
+ npc_get_dft_rl_idxs_rsp)\
+M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601e, npc_get_pfl_info, \
+ msg_req, \
+ npc_get_pfl_info_rsp) \
/* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \
M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, \
nix_lf_alloc_req, nix_lf_alloc_rsp) \
@@ -1598,6 +1607,7 @@ struct cn20k_mcam_entry {
u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY];
u64 action;
u64 vtag_action;
+ u64 action2;
};
struct npc_cn20k_mcam_write_entry_req {
@@ -1608,6 +1618,7 @@ struct npc_cn20k_mcam_write_entry_req {
u8 intf; /* Rx or Tx interface */
u8 enable_entry;/* Enable this MCAM entry ? */
u8 hw_prio; /* hardware priority, valid for cn20k */
+ u8 req_kw_type; /* Type of kw which should be written */
u64 reserved; /* reserved for future use */
};
@@ -1694,6 +1705,7 @@ struct npc_cn20k_mcam_alloc_and_write_entry_req {
u8 enable_entry;/* Enable this MCAM entry ? */
u8 hw_prio; /* hardware priority, valid for cn20k */
u8 virt; /* Allocate virtual index */
+ u8 req_kw_type; /* Key type to be written */
u16 reserved[4]; /* reserved for future use */
};
@@ -1861,11 +1873,47 @@ struct npc_install_flow_req {
/* old counter value */
u16 cntr_val;
u8 hw_prio;
+ u8 req_kw_type; /* Key type to be written */
+ u8 alloc_entry; /* only for cn20k */
+ u16 ref_prio;
+ u16 ref_entry;
};
struct npc_install_flow_rsp {
struct mbox_msghdr hdr;
int counter; /* negative if no counter else counter number */
+ u16 entry;
+ u8 kw_type;
+};
+
+struct npc_get_num_kws_req {
+ struct mbox_msghdr hdr;
+ struct npc_install_flow_req fl;
+ u32 rsvd[4];
+};
+
+struct npc_get_num_kws_rsp {
+ struct mbox_msghdr hdr;
+ int kws;
+ u32 rsvd[4];
+};
+
+struct npc_get_dft_rl_idxs_rsp {
+ struct mbox_msghdr hdr;
+ u16 bcast;
+ u16 mcast;
+ u16 promisc;
+ u16 ucast;
+ u16 vf_ucast;
+ u16 rsvd[7];
+};
+
+struct npc_get_pfl_info_rsp {
+ struct mbox_msghdr hdr;
+ u16 x4_slots;
+ u8 kw_type;
+ u8 rsvd1[3];
+ u32 rsvd2[4];
};
struct npc_delete_flow_req {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 1c50fd150bd3..ca1c4b3178e6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -2678,6 +2678,10 @@ static int npc_mcam_alloc_entries(struct npc_mcam *mcam, u16 pcifunc,
if (!is_cn20k(rvu->pdev))
goto not_cn20k;
+ /* Only x2 or x4 key types are accepted */
+ if (req->kw_type != NPC_MCAM_KEY_X2 && req->kw_type != NPC_MCAM_KEY_X4)
+ return NPC_MCAM_INVALID_REQ;
+
/* The below table is being followed during allocation,
*
* 1. ref_entry == 0 && prio == HIGH && count == 1 : user wants to
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
index bff190ba95e2..b9572de1d175 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -1071,11 +1071,11 @@ static void npc_update_vlan_features(struct rvu *rvu,
~0ULL, 0, intf);
}
-static void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdata,
- u64 features, struct flow_msg *pkt,
- struct flow_msg *mask,
- struct rvu_npc_mcam_rule *output, u8 intf,
- int blkaddr)
+void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdata,
+ u64 features, struct flow_msg *pkt,
+ struct flow_msg *mask,
+ struct rvu_npc_mcam_rule *output, u8 intf,
+ int blkaddr)
{
u64 dmac_mask = ether_addr_to_u64(mask->dmac);
u64 smac_mask = ether_addr_to_u64(mask->smac);
@@ -1304,7 +1304,7 @@ static int npc_mcast_update_action_index(struct rvu *rvu, struct npc_install_flo
return 0;
}
-static void
+void
npc_populate_mcam_mdata(struct rvu *rvu,
struct mcam_entry_mdata *mdata,
struct cn20k_mcam_entry *cn20k_entry,
@@ -1549,6 +1549,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
cn20k_wreq.intf = req->intf;
cn20k_wreq.enable_entry = (u8)enable;
cn20k_wreq.hw_prio = req->hw_prio;
+ cn20k_wreq.req_kw_type = req->req_kw_type;
update_rule:
@@ -1642,6 +1643,79 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
return 0;
}
+static int
+rvu_npc_free_entry_for_flow_install(struct rvu *rvu, u16 pcifunc,
+ bool free_entry, int mcam_idx)
+{
+ struct npc_mcam_free_entry_req free_req;
+ struct msg_rsp rsp;
+ int rc;
+
+ if (!free_entry)
+ return 0;
+
+ free_req.hdr.pcifunc = pcifunc;
+ free_req.entry = mcam_idx;
+ rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
+ return rc;
+}
+
+static int
+rvu_npc_alloc_entry_for_flow_install(struct rvu *rvu,
+ struct npc_install_flow_req *fl_req,
+ u16 *mcam_idx, u8 *kw_type,
+ bool *allocated)
+{
+ struct npc_mcam_alloc_entry_req entry_req;
+ struct npc_mcam_alloc_entry_rsp entry_rsp;
+ struct npc_get_num_kws_req kws_req;
+ struct npc_get_num_kws_rsp kws_rsp;
+ int off, kw_bits, rc;
+ u8 *src, *dst;
+
+ if (!is_cn20k(rvu->pdev)) {
+ *kw_type = -1;
+ return 0;
+ }
+
+ if (!fl_req->alloc_entry) {
+ *kw_type = -1;
+ return 0;
+ }
+
+ off = offsetof(struct npc_install_flow_req, packet);
+ dst = (u8 *)&kws_req.fl + off;
+ src = (u8 *)fl_req + off;
+ memcpy(dst, src, sizeof(struct npc_install_flow_req) - off);
+ rc = rvu_mbox_handler_npc_get_num_kws(rvu, &kws_req, &kws_rsp);
+ if (rc)
+ return rc;
+
+ kw_bits = kws_rsp.kws * 64;
+
+ *kw_type = NPC_MCAM_KEY_X2;
+ if (kw_bits > 256)
+ *kw_type = NPC_MCAM_KEY_X4;
+
+ memset(&entry_req, 0, sizeof(entry_req));
+ memset(&entry_rsp, 0, sizeof(entry_rsp));
+
+ entry_req.hdr.pcifunc = fl_req->hdr.pcifunc;
+ entry_req.ref_prio = fl_req->ref_prio;
+ entry_req.ref_entry = fl_req->ref_entry;
+ entry_req.kw_type = *kw_type;
+ entry_req.count = 1;
+ rc = rvu_mbox_handler_npc_mcam_alloc_entry(rvu,
+ &entry_req,
+ &entry_rsp);
+ if (rc)
+ return rc;
+
+ *mcam_idx = entry_rsp.entry_list[0];
+ *allocated = true;
+ return 0;
+}
+
int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
struct npc_install_flow_req *req,
struct npc_install_flow_rsp *rsp)
@@ -1652,11 +1726,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
int blkaddr, nixlf, err;
struct rvu_pfvf *pfvf;
bool pf_set_vfs_mac = false;
+ bool allocated = false;
bool enable = true;
+ u8 kw_type;
u16 target;
- req->entry = npc_cn20k_vidx2idx(req->entry);
-
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0) {
dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
@@ -1666,6 +1740,17 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
if (!is_npc_interface_valid(rvu, req->intf))
return NPC_FLOW_INTF_INVALID;
+ err = rvu_npc_alloc_entry_for_flow_install(rvu, req, &req->entry,
+ &kw_type, &allocated);
+ if (err) {
+ dev_err(rvu->dev,
+ "%s: Error to alloc mcam entry for pcifunc=%#x\n",
+ __func__, req->hdr.pcifunc);
+ return err;
+ }
+
+ req->entry = npc_cn20k_vidx2idx(req->entry);
+
/* If DMAC is not extracted in MKEX, rules installed by AF
* can rely on L2MB bit set by hardware protocol checker for
* broadcast and multicast addresses.
@@ -1679,6 +1764,10 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
dev_warn(rvu->dev,
"%s: mkex profile does not support ucast flow\n",
__func__);
+ rvu_npc_free_entry_for_flow_install(rvu,
+ req->hdr.pcifunc,
+ allocated,
+ req->entry);
return NPC_FLOW_NOT_SUPPORTED;
}
@@ -1686,6 +1775,10 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
dev_warn(rvu->dev,
"%s: mkex profile does not support bcast/mcast flow",
__func__);
+ rvu_npc_free_entry_for_flow_install(rvu,
+ req->hdr.pcifunc,
+ allocated,
+ req->entry);
return NPC_FLOW_NOT_SUPPORTED;
}
@@ -1695,8 +1788,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
}
process_flow:
- if (from_vf && req->default_rule)
+ if (from_vf && req->default_rule) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_VF_PERM_DENIED;
+ }
/* Each PF/VF info is maintained in struct rvu_pfvf.
* rvu_pfvf for the target PF/VF needs to be retrieved
@@ -1724,8 +1820,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
req->chan_mask = 0xFFF;
err = npc_check_unsupported_flows(rvu, req->features, req->intf);
- if (err)
+ if (err) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_NOT_SUPPORTED;
+ }
pfvf = rvu_get_pfvf(rvu, target);
@@ -1744,8 +1843,11 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
/* Proceed if NIXLF is attached or not for TX rules */
err = nix_get_nixlf(rvu, target, &nixlf, NULL);
- if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac)
+ if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_NO_NIXLF;
+ }
/* don't enable rule when nixlf not attached or initialized */
if (!(is_nixlf_attached(rvu, target) &&
@@ -1760,20 +1862,31 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
enable = true;
/* Do not allow requests from uninitialized VFs */
- if (from_vf && !enable)
+ if (from_vf && !enable) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_VF_NOT_INIT;
+ }
/* PF sets VF mac & VF NIXLF is not attached, update the mac addr */
if (pf_set_vfs_mac && !enable) {
ether_addr_copy(pfvf->default_mac, req->packet.dmac);
ether_addr_copy(pfvf->mac_addr, req->packet.dmac);
set_bit(PF_SET_VF_MAC, &pfvf->flags);
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return 0;
}
mutex_lock(&rswitch->switch_lock);
err = npc_install_flow(rvu, blkaddr, target, nixlf, pfvf,
req, rsp, enable, pf_set_vfs_mac);
+ if (err)
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
+
+ rsp->kw_type = kw_type;
+ rsp->entry = req->entry;
mutex_unlock(&rswitch->switch_lock);
return err;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h
index 442287ee7baa..d3ba86c23959 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h
@@ -18,4 +18,16 @@ void npc_update_entry(struct rvu *rvu, enum key_fields type,
struct mcam_entry_mdata *mdata, u64 val_lo,
u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf);
+void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdata,
+ u64 features, struct flow_msg *pkt,
+ struct flow_msg *mask,
+ struct rvu_npc_mcam_rule *output, u8 intf,
+ int blkaddr);
+
+void
+npc_populate_mcam_mdata(struct rvu *rvu,
+ struct mcam_entry_mdata *mdata,
+ struct cn20k_mcam_entry *cn20k_entry,
+ struct mcam_entry *entry);
+
#endif /* RVU_NPC_FS_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 052d989f2d9a..23372f30dcc2 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -37,6 +37,98 @@ static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_
flow_cfg->max_flows = 0;
}
+static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2,
+ u16 *x4_slots)
+{
+ struct npc_get_pfl_info_rsp *rsp;
+ struct msg_req *req;
+ static struct {
+ bool is_set;
+ bool is_x2;
+ u16 x4_slots;
+ } pfl_info;
+
+ /* Avoid sending mboxes for constant information
+ * like x4_slots
+ */
+ if (pfl_info.is_set) {
+ *is_x2 = pfl_info.is_x2;
+ *x4_slots = pfl_info.x4_slots;
+ return 0;
+ }
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_npc_get_pfl_info(&pfvf->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ /* Send message to AF */
+ if (otx2_sync_mbox_msg(&pfvf->mbox)) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -EFAULT;
+ }
+
+ rsp = (struct npc_get_pfl_info_rsp *)otx2_mbox_get_rsp
+ (&pfvf->mbox.mbox, 0, &req->hdr);
+
+ if (IS_ERR(rsp)) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -EFAULT;
+ }
+
+ *is_x2 = (rsp->kw_type == NPC_MCAM_KEY_X2);
+ if (*is_x2)
+ *x4_slots = 0;
+ else
+ *x4_slots = rsp->x4_slots;
+
+ pfl_info.is_x2 = *is_x2;
+ pfl_info.x4_slots = *x4_slots;
+ pfl_info.is_set = true;
+
+ mutex_unlock(&pfvf->mbox.lock);
+ return 0;
+}
+
+static int otx2_get_dft_rl_idx(struct otx2_nic *pfvf, u16 *mcam_idx)
+{
+ struct npc_get_dft_rl_idxs_rsp *rsp;
+ struct msg_req *req;
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_npc_get_dft_rl_idxs(&pfvf->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ /* Send message to AF */
+ if (otx2_sync_mbox_msg(&pfvf->mbox)) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -EINVAL;
+ }
+
+ rsp = (struct npc_get_dft_rl_idxs_rsp *)otx2_mbox_get_rsp
+ (&pfvf->mbox.mbox, 0, &req->hdr);
+
+ if (IS_ERR(rsp)) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -EFAULT;
+ }
+
+ if (is_otx2_lbkvf(pfvf->pdev))
+ *mcam_idx = rsp->promisc;
+ else
+ *mcam_idx = rsp->ucast;
+
+ mutex_unlock(&pfvf->mbox.lock);
+ return 0;
+}
+
static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
@@ -69,7 +161,10 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct npc_mcam_alloc_entry_req *req;
struct npc_mcam_alloc_entry_rsp *rsp;
- int ent, allocated = 0;
+ u16 dft_idx = 0, x4_slots = 0;
+ int ent, allocated = 0, ref;
+ bool is_x2 = false;
+ int rc;
/* Free current ones and allocate new ones with requested count */
otx2_free_ntuple_mcam_entries(pfvf);
@@ -86,6 +181,22 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
return -ENOMEM;
}
+ if (is_cn20k(pfvf->pdev)) {
+ rc = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
+ if (rc) {
+ netdev_err(pfvf->netdev, "Error to retrieve profile info\n");
+ return rc;
+ }
+
+ rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
+ if (rc) {
+ netdev_err(pfvf->netdev,
+ "Error to retrieve ucast mcam idx for pcifunc %#x\n",
+ pfvf->pcifunc);
+ return -EFAULT;
+ }
+ }
+
mutex_lock(&pfvf->mbox.lock);
/* In a single request a max of NPC_MAX_NONCONTIG_ENTRIES MCAM entries
@@ -96,18 +207,31 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
if (!req)
goto exit;
+ req->kw_type = is_x2 ? NPC_MCAM_KEY_X2 : NPC_MCAM_KEY_X4;
req->contig = false;
req->count = (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ?
NPC_MAX_NONCONTIG_ENTRIES : count - allocated;
+ ref = 0;
+
+ if (is_cn20k(pfvf->pdev)) {
+ req->ref_prio = NPC_MCAM_HIGHER_PRIO;
+ ref = dft_idx;
+ }
+
/* Allocate higher priority entries for PFs, so that VF's entries
* will be on top of PF.
*/
if (!is_otx2_vf(pfvf->pcifunc)) {
req->ref_prio = NPC_MCAM_HIGHER_PRIO;
- req->ref_entry = flow_cfg->def_ent[0];
+ ref = flow_cfg->def_ent[0];
}
+ if (is_cn20k(pfvf->pdev))
+ ref = is_x2 ? ref : ref & (x4_slots - 1);
+
+ req->ref_entry = ref;
+
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox))
goto exit;
@@ -163,8 +287,24 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
struct npc_get_field_status_rsp *frsp;
struct npc_mcam_alloc_entry_req *req;
struct npc_mcam_alloc_entry_rsp *rsp;
- int vf_vlan_max_flows;
- int ent, count;
+ int vf_vlan_max_flows, count;
+ int rc, ref, prio, ent;
+ u16 dft_idx;
+
+ ref = 0;
+ prio = 0;
+ if (is_cn20k(pfvf->pdev)) {
+ rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
+ if (rc) {
+ netdev_err(pfvf->netdev,
+ "Error to retrieve ucast mcam idx for pcifunc %#x\n",
+ pfvf->pcifunc);
+ return -EFAULT;
+ }
+
+ ref = dft_idx;
+ prio = NPC_MCAM_HIGHER_PRIO;
+ }
vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
count = flow_cfg->ucast_flt_cnt +
@@ -183,8 +323,11 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
return -ENOMEM;
}
+ req->kw_type = NPC_MCAM_KEY_X2;
req->contig = false;
req->count = count;
+ req->ref_prio = prio;
+ req->ref_entry = ref;
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox)) {
@@ -819,7 +962,7 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
}
static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
- struct npc_install_flow_req *req)
+ struct npc_install_flow_req *req)
{
struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
@@ -945,6 +1088,58 @@ static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
return 0;
}
+static int otx2_get_kw_type(struct otx2_nic *pfvf,
+ struct npc_install_flow_req *fl_req,
+ u8 *kw_type)
+{
+ struct npc_get_num_kws_req *req;
+ struct npc_get_num_kws_rsp *rsp;
+ u8 *src, *dst;
+ int off, err;
+ int kw_bits;
+
+ off = offsetof(struct npc_install_flow_req, packet);
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_npc_get_num_kws(&pfvf->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -EINVAL;
+ }
+
+ dst = (u8 *)&req->fl + off;
+ src = (u8 *)fl_req + off;
+
+ memcpy(dst, src, sizeof(struct npc_install_flow_req) - off);
+
+ err = otx2_sync_mbox_msg(&pfvf->mbox);
+ if (err) {
+ mutex_unlock(&pfvf->mbox.lock);
+ netdev_err(pfvf->netdev,
+ "Error to get default number of keywords\n");
+ return err;
+ }
+
+ rsp = (struct npc_get_num_kws_rsp *)otx2_mbox_get_rsp
+ (&pfvf->mbox.mbox, 0, &req->hdr);
+ if (IS_ERR(rsp)) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -EFAULT;
+ }
+
+ kw_bits = rsp->kws * 64;
+
+ if (kw_bits <= 256)
+ *kw_type = NPC_MCAM_KEY_X2;
+ else
+ *kw_type = NPC_MCAM_KEY_X4;
+
+ mutex_unlock(&pfvf->mbox.lock);
+
+ return 0;
+}
+
static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
struct ethtool_rx_flow_spec *fsp)
{
@@ -973,12 +1168,41 @@ static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
{
+ struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
+ struct npc_install_flow_req *req, treq = { 0 };
u64 ring_cookie = flow->flow_spec.ring_cookie;
#ifdef CONFIG_DCB
int vlan_prio, qidx, pfc_rule = 0;
#endif
- struct npc_install_flow_req *req;
- int err, vf = 0;
+ int err, vf = 0, off, sz;
+ bool modify = false;
+ u8 kw_type = 0;
+ u8 *src, *dst;
+ u16 x4_slots;
+ bool is_x2;
+
+ if (is_cn20k(pfvf->pdev)) {
+ err = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
+ if (err) {
+ netdev_err(pfvf->netdev,
+ "Error to retrieve ucast mcam idx for pcifunc %#x\n",
+ pfvf->pcifunc);
+ return -EFAULT;
+ }
+
+ if (!is_x2) {
+ err = otx2_prepare_flow_request(&flow->flow_spec,
+ &treq);
+ if (err)
+ return err;
+
+ err = otx2_get_kw_type(pfvf, &treq, &kw_type);
+ if (err)
+ return err;
+
+ modify = true;
+ }
+ }
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
@@ -987,14 +1211,29 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
return -ENOMEM;
}
- err = otx2_prepare_flow_request(&flow->flow_spec, req);
- if (err) {
- /* free the allocated msg above */
- otx2_mbox_reset(&pfvf->mbox.mbox, 0);
- mutex_unlock(&pfvf->mbox.lock);
- return err;
+ if (modify) {
+ off = offsetof(struct npc_install_flow_req, packet);
+ sz = sizeof(struct npc_install_flow_req) - off;
+ dst = (u8 *)req + off;
+ src = (u8 *)&treq + off;
+
+ memcpy(dst, src, sz);
+ req->req_kw_type = kw_type;
+ } else {
+ err = otx2_prepare_flow_request(&flow->flow_spec, req);
+ if (err) {
+ /* free the allocated msg above */
+ otx2_mbox_reset(&pfvf->mbox.mbox, 0);
+ mutex_unlock(&pfvf->mbox.lock);
+ return err;
+ }
}
+ netdev_dbg(pfvf->netdev,
+ "flow entry (%u) installed at loc:%u kw_type=%u\n",
+ flow_cfg->flow_ent[flow->location],
+ flow->location, kw_type);
+
req->entry = flow->entry;
req->intf = NIX_INTF_RX;
req->set_cntr = 1;
--
2.43.0
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
octeontx2-af: npc: cn20k: Allocate MCAM entry for flow installation
In CN20K, the PF/VF driver is unaware of the NPC MCAM entry type (x2/x4)
required for a particular TC rule when the user installs rules through the
TC command. This forces the PF/VF driver to first query the AF driver for
the rule size, then allocate an entry, and finally install the flow. This
sequence requires three mailbox request/response exchanges from the PF. To
speed up the installation, the `install_flow` mailbox request message is
extended with additional fields that allow the AF driver to determine the
required NPC MCAM entry type, allocate the MCAM entry, and complete the
flow installation in a single step.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> index 7306414d1cf2..237e6f606fc1 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
[ ... ]
> @@ -1412,9 +1453,11 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
> mutex_unlock(&mcam->lock);
> goto out;
> }
> +
> + rl_type = rvu_npc_get_base_steer_rule_type(rvu, pcifunc);
> +
> /* Read the default ucast entry if there is no pkt steering rule */
> - index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
> - NIXLF_UCAST_ENTRY);
> + index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, rl_type);
> read_entry:
> /* Read the mcam entry */
> npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
The new function rvu_npc_get_base_steer_rule_type() returns
NIXLF_PROMISC_ENTRY for loopback VFs, but npc_get_nixlf_mcam_index() can
return negative error codes when it cannot find the requested entry.
Should there be an error check after calling npc_get_nixlf_mcam_index()
at line 1460?
When the promisc MCAM entry is not configured, npc_cn20k_dft_rules_idx_get()
returns -ESRCH, which causes npc_get_nixlf_mcam_index() to return -EFAULT.
Without an error check, this negative value gets cast to u16 when passed to
npc_cn20k_read_mcam_entry(), converting -14 to 65522 and potentially
causing an out-of-bounds hardware register read.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
> index bff190ba95e2..b9572de1d175 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
[ ... ]
> @@ -1549,6 +1549,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
> cn20k_wreq.intf = req->intf;
> cn20k_wreq.enable_entry = (u8)enable;
> cn20k_wreq.hw_prio = req->hw_prio;
> + cn20k_wreq.req_kw_type = req->req_kw_type;
>
> update_rule:
Looking at npc_install_flow(), req->req_kw_type is copied to
cn20k_wreq.req_kw_type, but is req->req_kw_type ever initialized with the
computed kw_type value?
In rvu_mbox_handler_npc_install_flow(), the function
rvu_npc_alloc_entry_for_flow_install() computes the correct kw_type based
on the flow requirements and stores it in the local variable 'kw_type' at
line 1746. However, this computed value is never assigned to
req->req_kw_type before calling npc_install_flow() at line 1887.
As a result, npc_install_flow() uses either a zero-initialized value or
whatever the PF driver sent, instead of the AF-computed value. This seems
inconsistent with the commit message stating "the AF driver determine the
required NPC MCAM entry type." The incorrect req_kw_type is then passed to
npc_cn20k_config_mcam_entry() which uses it for hardware configuration
mismatch handling in npc_cn20k_config_kw_x2() at lines 956-960.
> @@ -1642,6 +1643,79 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
> return 0;
> }
>
> +static int
> +rvu_npc_free_entry_for_flow_install(struct rvu *rvu, u16 pcifunc,
> + bool free_entry, int mcam_idx)
> +{
> + struct npc_mcam_free_entry_req free_req;
> + struct msg_rsp rsp;
> + int rc;
> +
> + if (!free_entry)
> + return 0;
> +
> + free_req.hdr.pcifunc = pcifunc;
> + free_req.entry = mcam_idx;
> + rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
> + return rc;
> +}
In rvu_npc_free_entry_for_flow_install(), the free_req structure is
declared on the stack without initialization. Only the hdr.pcifunc and
entry fields are explicitly set, leaving the 'all' field uninitialized.
When rvu_mbox_handler_npc_mcam_free_entry() is called, it checks
'if (req->all)' to decide whether to free a single entry or all entries
for the PF/VF. If the uninitialized 'all' field contains non-zero stack
garbage, could this cause the function to incorrectly call
npc_mcam_free_all_entries(), freeing ALL MCAM entries instead of just the
intended single entry?
In the same source file, the function rvu_npc_alloc_entry_for_flow_install()
correctly zero-initializes entry_req and entry_rsp structures using memset.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> index 052d989f2d9a..23372f30dcc2 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
[ ... ]
> +static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2,
> + u16 *x4_slots)
> +{
> + struct npc_get_pfl_info_rsp *rsp;
> + struct msg_req *req;
> + static struct {
> + bool is_set;
> + bool is_x2;
> + u16 x4_slots;
> + } pfl_info;
> +
> + /* Avoid sending mboxes for constant information
> + * like x4_slots
> + */
> + if (pfl_info.is_set) {
> + *is_x2 = pfl_info.is_x2;
> + *x4_slots = pfl_info.x4_slots;
> + return 0;
> + }
> +
> + mutex_lock(&pfvf->mbox.lock);
In otx2_mcam_pfl_info_get(), the static pfl_info structure is used as a
cache to avoid repeated mailbox queries. However, the cache check at line
54 reads pfl_info.is_set without holding the mutex, while lines 88-90
write to the same static variables with the mutex held.
Could this create a race condition between concurrent threads? For example:
Thread A: Reads pfl_info.is_set (false) at line 54
Thread B: Reads pfl_info.is_set (false) at line 54
Thread A: Acquires mutex, queries AF, writes pfl_info at lines 88-90
Thread B: Acquires mutex, queries AF again (redundant operation)
Or in a scenario with partial reads:
Thread A: Reads pfl_info.is_set (false)
Thread B: Reads pfl_info.is_set (false), starts to read the cache
Thread A: Sets pfl_info.is_set = true at line 90
Thread B: Re-reads and sees is_set==true, reads is_x2 and x4_slots
(but Thread A may not have finished writing these values)
Would it be safer to perform the cache check inside the mutex?
[ ... ]
> @@ -86,6 +181,22 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
> return -ENOMEM;
> }
>
> + if (is_cn20k(pfvf->pdev)) {
> + rc = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
> + if (rc) {
> + netdev_err(pfvf->netdev, "Error to retrieve profile info\n");
> + return rc;
> + }
> +
> + rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
> + if (rc) {
> + netdev_err(pfvf->netdev,
> + "Error to retrieve ucast mcam idx for pcifunc %#x\n",
> + pfvf->pcifunc);
> + return -EFAULT;
> + }
> + }
In otx2_alloc_mcam_entries(), when otx2_get_dft_rl_idx() fails, the
function returns -EFAULT. However, otx2_get_dft_rl_idx() can return
-ENOMEM (from otx2_mbox_alloc_msg_npc_get_dft_rl_idxs failure), -EINVAL
(from otx2_sync_mbox_msg failure), or -EFAULT (from IS_ERR(rsp) check).
Should the function return rc instead of hardcoding -EFAULT to preserve
the actual error code?
This is inconsistent with line 188 which correctly returns rc for a
similar error from otx2_mcam_pfl_info_get().
[ ... ]
> @@ -163,8 +287,24 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
> struct npc_get_field_status_rsp *frsp;
> struct npc_mcam_alloc_entry_req *req;
> struct npc_mcam_alloc_entry_rsp *rsp;
> - int vf_vlan_max_flows;
> - int ent, count;
> + int vf_vlan_max_flows, count;
> + int rc, ref, prio, ent;
> + u16 dft_idx;
> +
> + ref = 0;
> + prio = 0;
> + if (is_cn20k(pfvf->pdev)) {
> + rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
> + if (rc) {
> + netdev_err(pfvf->netdev,
> + "Error to retrieve ucast mcam idx for pcifunc %#x\n",
> + pfvf->pcifunc);
> + return -EFAULT;
> + }
> +
> + ref = dft_idx;
> + prio = NPC_MCAM_HIGHER_PRIO;
> + }
Same issue in otx2_mcam_entry_init() at line 302. When
otx2_get_dft_rl_idx() fails, the function returns -EFAULT, losing the
actual error code. Should this return rc instead?
[ ... ]
> @@ -973,12 +1168,41 @@ static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
>
> static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
> {
> + struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
> + struct npc_install_flow_req *req, treq = { 0 };
> u64 ring_cookie = flow->flow_spec.ring_cookie;
> #ifdef CONFIG_DCB
> int vlan_prio, qidx, pfc_rule = 0;
> #endif
> - struct npc_install_flow_req *req;
> - int err, vf = 0;
> + int err, vf = 0, off, sz;
> + bool modify = false;
> + u8 kw_type = 0;
> + u8 *src, *dst;
> + u16 x4_slots;
> + bool is_x2;
> +
> + if (is_cn20k(pfvf->pdev)) {
> + err = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
> + if (err) {
> + netdev_err(pfvf->netdev,
> + "Error to retrieve ucast mcam idx for pcifunc %#x\n",
> + pfvf->pcifunc);
> + return -EFAULT;
> + }
This isn't a bug, but the error message at lines 1187-1189 says "Error to
retrieve ucast mcam idx" but the failing function is
otx2_mcam_pfl_info_get(), which retrieves profile information (is_x2 and
x4_slots), not the unicast MCAM index. The unicast MCAM index is retrieved
by otx2_get_dft_rl_idx(). Would it be clearer to say "Error to retrieve
profile info" instead?
[ ... ]
> +static int otx2_get_kw_type(struct otx2_nic *pfvf,
> + struct npc_install_flow_req *fl_req,
> + u8 *kw_type)
> +{
> + struct npc_get_num_kws_req *req;
> + struct npc_get_num_kws_rsp *rsp;
> + u8 *src, *dst;
> + int off, err;
> + int kw_bits;
> +
> + off = offsetof(struct npc_install_flow_req, packet);
> +
> + mutex_lock(&pfvf->mbox.lock);
> +
> + req = otx2_mbox_alloc_msg_npc_get_num_kws(&pfvf->mbox);
> + if (!req) {
> + mutex_unlock(&pfvf->mbox.lock);
> + return -EINVAL;
> + }
This isn't a bug, but when otx2_mbox_alloc_msg_npc_get_num_kws() fails at
line 1120, the function returns -EINVAL. Memory allocation failures
typically return -ENOMEM per kernel convention. For consistency with line
177 in otx2_alloc_mcam_entries() which returns -ENOMEM for
devm_kmalloc_array failure, should this return -ENOMEM instead of -EINVAL?
© 2016 - 2026 Red Hat, Inc.