summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRatheesh Kannoth <rkannoth@marvell.com>2026-04-29 05:27:13 +0300
committerJakub Kicinski <kuba@kernel.org>2026-05-01 04:50:15 +0300
commitaaadccde312f1f6c752461e015adcaa25d463cbc (patch)
tree00c16d0c96664728bda73264053bf6ec380c171b
parent75df490c9e8457990c8b227650f6491218ce018b (diff)
downloadlinux-aaadccde312f1f6c752461e015adcaa25d463cbc.tar.xz
octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
npc_mcam_idx_2_key_type() can fail; callers used to ignore it and still used kw_type when enabling, configuring, copying, and reading MCAM entries. That could program or decode hardware with an undefined key type. Return -EINVAL when key-type lookup fails. Return -EINVAL from npc_cn20k_copy_mcam_entry() when src and dest key types differ instead of failing silently. Change npc_cn20k_{enable,config,copy,read}_mcam_entry() to return int on success or error. Thread those errors through the cn20k MCAM write and read mbox handlers, the cn20k baseline steer read path, NPC defrag move (disable/copy/enable with dev_err and -EFAULT), and the DMAC update path in rvu_npc_fs.c. Make npc_copy_mcam_entry() return int so the cn20k branch can return npc_cn20k_copy_mcam_entry() without a void/int mismatch, and fail NPC_MCAM_SHIFT_ENTRY when copy fails. Cc: Suman Ghosh <sumang@marvell.com> Cc: Dan Carpenter <error27@gmail.com> Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs") Link: https://lore.kernel.org/netdev/adiQJvuKlEhq2ILx@stanley.mountain/ Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com> Link: https://patch.msgid.link/20260429022722.1110289-2-rkannoth@marvell.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c122
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h20
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c18
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c20
4 files changed, 124 insertions, 56 deletions
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7291fdb89b03..7170dcf26200 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -798,7 +798,7 @@ program_mkex_extr:
iounmap(mkex_prfl_addr);
}
-void
+int
npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
int index, bool enable)
{
@@ -808,7 +808,9 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
u64 cfg, hw_prio;
u8 kw_type;
- npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+ if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+ return -EINVAL;
+
if (kw_type == NPC_MCAM_KEY_X2) {
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
@@ -819,7 +821,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
cfg);
- return;
+ return 0;
}
/* For NPC_CN20K_MCAM_KEY_X4 keys, both the banks
@@ -836,6 +838,8 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
cfg);
}
+
+ return 0;
}
void
@@ -1042,9 +1046,9 @@ 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, u8 req_kw_type)
+int 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 req_kw_type)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
int mcam_idx = index % mcam->banksize;
@@ -1052,10 +1056,13 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
int kw = 0;
u8 kw_type;
+ if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+ return -EINVAL;
+
/* Disable before mcam entry update */
- npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false);
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false))
+ return -EINVAL;
- npc_mcam_idx_2_key_type(rvu, index, &kw_type);
/* CAM1 takes the comparison value and
* CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'.
* CAM1<n> = 0 & CAM0<n> = 1 => match if key<n> = 0
@@ -1120,9 +1127,11 @@ set_cfg:
/* PF installing VF rule */
npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
kw_type, enable, hw_prio);
+
+ return 0;
}
-void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
+int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 cfg, sreg, dreg, soff, doff;
@@ -1132,10 +1141,15 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
dbank = npc_get_bank(mcam, dest);
sbank = npc_get_bank(mcam, src);
- npc_mcam_idx_2_key_type(rvu, src, &src_kwtype);
- npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype);
+
+ if (npc_mcam_idx_2_key_type(rvu, src, &src_kwtype))
+ return -EINVAL;
+
+ if (npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype))
+ return -EINVAL;
+
if (src_kwtype != dest_kwtype)
- return;
+ return -EINVAL;
src &= (mcam->banksize - 1);
dest &= (mcam->banksize - 1);
@@ -1170,6 +1184,8 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
if (src_kwtype == NPC_MCAM_KEY_X2)
break;
}
+
+ return 0;
}
static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int idx,
@@ -1179,16 +1195,17 @@ static void npc_cn20k_fill_entryword(struct cn20k_mcam_entry *entry, int idx,
entry->kw_mask[idx] = cam1 ^ cam0;
}
-void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
- struct cn20k_mcam_entry *entry,
- u8 *intf, u8 *ena, u8 *hw_prio)
+int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+ struct cn20k_mcam_entry *entry,
+ u8 *intf, u8 *ena, u8 *hw_prio)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 cam0, cam1, bank_cfg, cfg;
int kw = 0, bank;
u8 kw_type;
- npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+ if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
+ return -EINVAL;
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
@@ -1298,6 +1315,8 @@ read_action:
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
entry->vtag_action = cfg;
+
+ return 0;
}
int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
@@ -1335,11 +1354,10 @@ int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
if (is_pffunc_af(req->hdr.pcifunc))
nix_intf = req->intf;
- npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
- &req->entry_data, req->enable_entry,
- req->hw_prio, req->req_kw_type);
+ rc = npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
+ &req->entry_data, req->enable_entry,
+ req->hw_prio, req->req_kw_type);
- rc = 0;
exit:
mutex_unlock(&mcam->lock);
return rc;
@@ -1361,11 +1379,13 @@ int rvu_mbox_handler_npc_cn20k_mcam_read_entry(struct rvu *rvu,
mutex_lock(&mcam->lock);
rc = npc_mcam_verify_entry(mcam, pcifunc, req->entry);
- if (!rc)
- npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry,
- &rsp->entry_data, &rsp->intf,
- &rsp->enable, &rsp->hw_prio);
+ if (rc)
+ goto fail;
+ rc = npc_cn20k_read_mcam_entry(rvu, blkaddr, req->entry,
+ &rsp->entry_data, &rsp->intf,
+ &rsp->enable, &rsp->hw_prio);
+fail:
mutex_unlock(&mcam->lock);
return rc;
}
@@ -1375,11 +1395,13 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
struct npc_mcam_alloc_and_write_entry_rsp *rsp)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
+ struct npc_mcam_free_entry_req free_req = { 0 };
struct npc_mcam_alloc_entry_req entry_req;
struct npc_mcam_alloc_entry_rsp entry_rsp;
struct npc_mcam *mcam = &rvu->hw->mcam;
u16 entry = NPC_MCAM_ENTRY_INVALID;
- int blkaddr, rc;
+ struct msg_rsp free_rsp;
+ int blkaddr, rc, err;
u8 nix_intf;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
@@ -1415,12 +1437,23 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
else
nix_intf = pfvf->nix_rx_intf;
- npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
- &req->entry_data, req->enable_entry,
- req->hw_prio, req->req_kw_type);
+ rc = npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
+ &req->entry_data, req->enable_entry,
+ req->hw_prio, req->req_kw_type);
mutex_unlock(&mcam->lock);
+ if (rc) {
+ free_req.hdr.pcifunc = req->hdr.pcifunc;
+ free_req.entry = entry_rsp.entry;
+ err = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &free_rsp);
+ if (err)
+ dev_err(rvu->dev,
+ "%s: Error to free mcam idx %u\n",
+ __func__, entry_rsp.entry);
+ return rc;
+ }
+
rsp->entry = entry_rsp.entry;
return 0;
}
@@ -1480,9 +1513,9 @@ int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
read_entry:
/* Read the mcam entry */
- npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
- &rsp->entry, &intf,
- &enable, &hw_prio);
+ rc = npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
+ &rsp->entry, &intf,
+ &enable, &hw_prio);
mutex_unlock(&mcam->lock);
out:
return rc;
@@ -3607,9 +3640,30 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(midx,
bank));
- npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false);
- npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx);
- npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true);
+ /* If bug happened during copy/enable mcam, then there is a bug in allocation
+ * algorithm itself. There is no point in rewinding and returning, as it
+ * will face further issue. Return error after printing error
+ */
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false)) {
+ dev_err(rvu->dev,
+ "%s: Error happened while disabling old_mid=%u\n",
+ __func__, old_midx);
+ return -EFAULT;
+ }
+
+ if (npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx)) {
+ dev_err(rvu->dev,
+ "%s: Error happened while copying old_midx=%u new_midx=%u\n",
+ __func__, old_midx, new_midx);
+ return -EFAULT;
+ }
+
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true)) {
+ dev_err(rvu->dev,
+ "%s: Error happened while enabling new_mid=%u\n",
+ __func__, new_midx);
+ return -EFAULT;
+ }
midx = new_midx % mcam->banksize;
bank = new_midx / mcam->banksize;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 815d0b257a7e..8f3eea9cfb1d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -320,16 +320,16 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc);
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 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,
- u16 src, u16 dest);
-void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
- struct cn20k_mcam_entry *entry, u8 *intf,
- u8 *ena, u8 *hw_prio);
+int 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 req_kw_type);
+int npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
+ int index, bool enable);
+int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
+ u16 src, u16 dest);
+int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+ struct cn20k_mcam_entry *entry, u8 *intf,
+ u8 *ena, u8 *hw_prio);
void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr,
int bank, int index);
int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c2ca5ed1d028..ecaf0946b852 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -241,7 +241,10 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
if (index < 0 || index >= mcam->banksize * mcam->banks)
return;
- return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable))
+ dev_err(rvu->dev, "Error to %s mcam %u entry\n",
+ enable ? "enable" : "disable", index);
+ return;
}
index &= (mcam->banksize - 1);
@@ -589,8 +592,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_CFG(src, sbank)) & 1;
}
-static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
- int blkaddr, u16 src, u16 dest)
+static int npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, u16 src, u16 dest)
{
int dbank = npc_get_bank(mcam, dest);
int sbank = npc_get_bank(mcam, src);
@@ -630,6 +633,7 @@ static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_CFG(src, sbank));
rvu_write64(rvu, blkaddr,
NPC_AF_MCAMEX_BANKX_CFG(dest, dbank), cfg);
+ return 0;
}
u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
@@ -3266,7 +3270,10 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu,
npc_enable_mcam_entry(rvu, mcam, blkaddr, new_entry, false);
/* Copy rule from old entry to new entry */
- npc_copy_mcam_entry(rvu, mcam, blkaddr, old_entry, new_entry);
+ if (npc_copy_mcam_entry(rvu, mcam, blkaddr, old_entry, new_entry)) {
+ rc = NPC_MCAM_INVALID_REQ;
+ break;
+ }
/* Copy counter mapping, if any */
cntr = mcam->entry2cntr_map[old_entry];
@@ -3284,7 +3291,8 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu,
/* If shift has failed then report the failed index */
if (index != req->shift_count) {
- rc = NPC_MCAM_PERM_DENIED;
+ if (!rc)
+ rc = NPC_MCAM_PERM_DENIED;
rsp->failed_entry_idx = index;
}
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 b45798d9fdab..fe10554b1f0e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -1980,13 +1980,15 @@ static int npc_update_dmac_value(struct rvu *rvu, int npcblkaddr,
ether_addr_copy(rule->packet.dmac, pfvf->mac_addr);
- if (is_cn20k(rvu->pdev))
- npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry,
- cn20k_entry, &intf,
- &enable, &hw_prio);
- else
+ if (is_cn20k(rvu->pdev)) {
+ if (npc_cn20k_read_mcam_entry(rvu, npcblkaddr, rule->entry,
+ cn20k_entry, &intf,
+ &enable, &hw_prio))
+ return -EINVAL;
+ } else {
npc_read_mcam_entry(rvu, mcam, npcblkaddr, rule->entry,
entry, &intf, &enable);
+ }
npc_update_entry(rvu, NPC_DMAC, &mdata,
ether_addr_to_u64(pfvf->mac_addr), 0,
@@ -2038,8 +2040,12 @@ void npc_mcam_enable_flows(struct rvu *rvu, u16 target)
continue;
}
- if (rule->vfvlan_cfg)
- npc_update_dmac_value(rvu, blkaddr, rule, pfvf);
+ if (rule->vfvlan_cfg) {
+ if (npc_update_dmac_value(rvu, blkaddr, rule, pfvf))
+ dev_err(rvu->dev,
+ "Update dmac failed for %u, target=%#x\n",
+ rule->entry, target);
+ }
if (rule->rx_action.op == NIX_RX_ACTION_DEFAULT) {
if (!def_ucast_rule)