* [PATCH v5 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-30 4:05 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 02/10] octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init Ratheesh Kannoth
` (9 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Suman Ghosh, Dan Carpenter
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>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 122 +++++++++++++-----
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 20 +--
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 18 ++-
.../marvell/octeontx2/af/rvu_npc_fs.c | 20 ++-
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 @@ void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr,
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 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
/* 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 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
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)
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v5 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
2026-04-29 2:27 ` [PATCH v5 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k Ratheesh Kannoth
@ 2026-04-30 4:05 ` Ratheesh Kannoth
0 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-30 4:05 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Suman Ghosh, Dan Carpenter
On 2026-04-29 at 07:57:13, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> 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.
> 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
[ ... ]
> @@ -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;
>This isn't a bug introduced here, but entry_req is allocated on the stack
>and is not zero-initialized. Its kw_type field does not appear to be set
>before calling rvu_mbox_handler_npc_mcam_alloc_entry().
>Could this uninitialized stack garbage lead to unpredictable bounds-check
>failures or random mcam allocation errors?
I see your concern regarding the uninitialized entry_req. The reason it was left as-is is that this patch
focuses specifically on the MCAM key-type error propagation logic. However, I agree that leaving stack garbage is suboptimal.
If you prefer not to bundle this with the current Smatch fix
> @@ -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;
> + }
>When these early returns execute, the software vidx map has already been
>redirected to new_midx via a preceding call to npc_vidx_maps_modify().
>Since the early returns skip the remaining bookkeeping steps (updating
>mcam->entry2pfvf_map, freeing old_midx, and updating counts), does this leave
>the system in a corrupted state?
>Would the vidx now point to a new_midx that the user does not officially own
>(causing NPC_MCAM_PERM_DENIED on future accesses), while old_midx is left
>disabled and permanently leaked?
understand the concern regarding the vidx map falling out of sync. However, npc_defrag_move_vdx_to_free runs under a mutex, and
a failure during the copy/enable phase indicates the NPC block has entered a non-deterministic state.
In this specific 'should-never-happen' scenario, attempting a graceful software rewind could mask a critical fault or lead to further exceptions.
My intention with this Smatch fix was to ensure the error is at least caught and logged rather than silently ignored.
I can address a full transactional rollback mechanism in a separate hardening series for net-next.
But issue is graceful rollback can also fail as it is kind of another defrag process.
> @@ -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 npc_update_dmac_value() fails and returns an error like -EINVAL, execution
>falls through and logs the error, but continues processing the current rule.
>The code then computes a hardware offset via NPC_AF_MCAMEX_BANKX_ACTION()
>and unconditionally performs a direct hardware write using rule->entry.
>If rule->entry happens to be invalid or out-of-bounds, could this fall-through
>cause unrelated device registers to be corrupted, or trigger a data abort?
>Even though a later patch in this series hardens some helpers, is a continue
>statement missing here to protect the immediate rvu_write64() that follows?
>Additionally, this is not a regression in this patch, but I noticed that
>list_for_each_entry() is used to iterate over mcam->mcam_rules while
>holding mcam->lock.
>If npc_update_dmac_value() is called, it explicitly drops mcam->lock before
>invoking the mailbox handler.
>If a concurrent thread acquires the lock and deletes the current rule while
>it is dropped, will the list iteration resume with a use-after-free on the
>freed rule pointer?
>Should a safe list iteration macro be used instead, combined with reference
>counting to preserve the rule?
I acknowledge that dropping mcam->lock during list_for_each_entry is a significant architectural vulnerability.
However, fixing this properly requires moving to a reference-counted rule model or an RCU-based iteration to prevent regressions.
Since this series is a targeted bug fix for net focused on Smatch errors, I believe a full locking refactor is
too high-risk for this specific pull request. Will work on hardening patch to net-next.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v5 net 02/10] octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback Ratheesh Kannoth
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Dan Carpenter, Simon Horman
debugfs is not intended to be checked for allocation failures the way other
kernel APIs are: callers should not fail probe or subsystem init because a
debugfs node could not be created, including when debugfs is disabled in
Kconfig. Replacing NULL checks with IS_ERR() checks is similarly wrong for
optional debugfs.
Remove dentry checks and -EFAULT returns from npc_cn20k_debugfs_init().
See:
https://staticthinking.wordpress.com/2023/07/24/
debugfs-functions-are-not-supposed-to-be-checked/
Cc: Dan Carpenter <error27@gmail.com>
Fixes: 528530dff56b ("octeontx2-af: npc: cn20k: add debugfs support")
Link: https://lore.kernel.org/netdev/adjNGPWKMOk3KgWL@stanley.mountain/
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../marvell/octeontx2/af/cn20k/debugfs.c | 33 ++++++-------------
1 file changed, 10 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
index 3debf2fae1a4..6f13296303cb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
@@ -249,34 +249,21 @@ DEFINE_SHOW_ATTRIBUTE(npc_defrag);
int npc_cn20k_debugfs_init(struct rvu *rvu)
{
struct npc_priv_t *npc_priv = npc_priv_get();
- struct dentry *npc_dentry;
- npc_dentry = debugfs_create_file("mcam_layout", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_mcam_layout_fops);
+ debugfs_create_file("mcam_layout", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_mcam_layout_fops);
- if (!npc_dentry)
- return -EFAULT;
+ debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
+ rvu, &npc_mcam_default_fops);
- npc_dentry = debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
- rvu, &npc_mcam_default_fops);
+ debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_vidx2idx_map_fops);
- if (!npc_dentry)
- return -EFAULT;
+ debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_idx2vidx_map_fops);
- npc_dentry = debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_vidx2idx_map_fops);
- if (!npc_dentry)
- return -EFAULT;
-
- npc_dentry = debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_idx2vidx_map_fops);
- if (!npc_dentry)
- return -EFAULT;
-
- npc_dentry = debugfs_create_file("defrag", 0444, rvu->rvu_dbg.npc,
- npc_priv, &npc_defrag_fops);
- if (!npc_dentry)
- return -EFAULT;
+ debugfs_create_file("defrag", 0444, rvu->rvu_dbg.npc,
+ npc_priv, &npc_defrag_fops);
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v5 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 02/10] octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-30 4:10 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule Ratheesh Kannoth
` (7 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Dan Carpenter, Simon Horman
npc_defrag_alloc_free_slots() allocates MCAM indexes in up to two passes on
bank0 then bank1. On failure it rolls back by freeing entries already
placed in save[].
__npc_subbank_alloc() can return a negative errno while only part of the
indexes are valid. The rollback loop used rc for
npc_mcam_idx_2_subbank_idx() as well, so a successful lookup stored zero in
rc and a later __npc_subbank_free() failure could still end with return 0
when the allocation path had also left rc at zero (for example shortfall
after zero return values from the alloc helpers).
Jump to the rollback path immediately when either __npc_subbank_alloc()
call fails, preserving its errno. If both calls succeed but the total
allocated count is still less than cnt, set rc to -ENOSPC before rollback.
Use a separate err variable for npc_mcam_idx_2_subbank_idx() so a
successful lookup no longer clears a non-zero rc from the allocation phase.
Cc: Dan Carpenter <error27@gmail.com>
Fixes: 645c6e3c1999 ("octeontx2-af: npc: cn20k: virtual index support")
Link: https://lore.kernel.org/netdev/adjNJEpILRZATB2N@stanley.mountain/
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../net/ethernet/marvell/octeontx2/af/cn20k/npc.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7170dcf26200..87da43088b67 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -2338,6 +2338,7 @@ static int __npc_subbank_alloc(struct rvu *rvu, struct npc_subbank *sb,
__npc_subbank_mark_free(rvu, sb);
err1:
kfree(save);
+ *alloc_cnt = 0;
return rc;
}
@@ -3515,7 +3516,7 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
{
int alloc_cnt1, alloc_cnt2;
struct npc_subbank *sb;
- int rc, sb_off, i;
+ int rc, sb_off, i, err;
bool deleted;
sb = &npc_priv.sb[f->idx];
@@ -3529,6 +3530,7 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
NPC_MCAM_LOWER_PRIO,
false, cnt, save, cnt, true,
&alloc_cnt1);
+
if (alloc_cnt1 < cnt) {
rc = __npc_subbank_alloc(rvu, sb,
NPC_MCAM_KEY_X2, sb->b1b,
@@ -3544,15 +3546,17 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
dev_err(rvu->dev,
"%s: Failed to alloc cnt=%u alloc_cnt1=%u alloc_cnt2=%u\n",
__func__, cnt, alloc_cnt1, alloc_cnt2);
+ rc = -ENOSPC;
goto fail_free_alloc;
}
+
return 0;
fail_free_alloc:
for (i = 0; i < alloc_cnt1 + alloc_cnt2; i++) {
- rc = npc_mcam_idx_2_subbank_idx(rvu, save[i],
- &sb, &sb_off);
- if (rc) {
+ err = npc_mcam_idx_2_subbank_idx(rvu, save[i],
+ &sb, &sb_off);
+ if (err) {
dev_err(rvu->dev,
"%s: Error to find subbank for mcam idx=%u\n",
__func__, save[i]);
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v5 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
2026-04-29 2:27 ` [PATCH v5 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback Ratheesh Kannoth
@ 2026-04-30 4:10 ` Ratheesh Kannoth
0 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-30 4:10 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Dan Carpenter, Simon Horman
On 2026-04-29 at 07:57:15, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_defrag_alloc_free_slots() allocates MCAM indexes in up to two passes on
> bank0 then bank1. On failure it rolls back by freeing entries already
> placed in save[].
>
> __npc_subbank_alloc() can return a negative errno while only part of the
> indexes are valid. The rollback loop used rc for
> npc_mcam_idx_2_subbank_idx() as well, so a successful lookup stored zero in
> rc and a later __npc_subbank_free() failure could still end with return 0
> when the allocation path had also left rc at zero (for example shortfall
> after zero return values from the alloc helpers).
>
> Jump to the rollback path immediately when either __npc_subbank_alloc()
> call fails, preserving its errno. If both calls succeed but the total
> allocated count is still less than cnt, set rc to -ENOSPC before rollback.
> Use a separate err variable for npc_mcam_idx_2_subbank_idx() so a
> successful lookup no longer clears a non-zero rc from the allocation phase.
>
>>could the commit message be updated, or are there missing checks for the
>>return value of __npc_subbank_alloc() in the code?
We clearly mentioned that if both fails rc is set to -ENOSPC.
> @@ -3529,6 +3530,7 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
> NPC_MCAM_LOWER_PRIO,
> false, cnt, save, cnt, true,
> &alloc_cnt1);
> +
> if (alloc_cnt1 < cnt) {
> rc = __npc_subbank_alloc(rvu, sb,
> NPC_MCAM_KEY_X2, sb->b1b,
>If the first __npc_subbank_alloc() call fails with an error like -ENOMEM,
>alloc_cnt1 is set to 0.
>Would this make the alloc_cnt1 < cnt check evaluate to true, causing the
>code to attempt the second allocation instead of jumping to the rollback
>path immediately?
Roll back is already done inside __npc_subbank_alloc(). So no need to rollback.
> @@ -3544,15 +3546,17 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
> dev_err(rvu->dev,
> "%s: Failed to alloc cnt=%u alloc_cnt1=%u alloc_cnt2=%u\n",
> __func__, cnt, alloc_cnt1, alloc_cnt2);
> + rc = -ENOSPC;
> goto fail_free_alloc;
> }
>If the allocation fails and sets rc to the actual error code, won't this
>block unconditionally overwrite the preserved errno with -ENOSPC before
>jumping to the rollback path?
You are correct that if the first call returns an error, alloc_cnt1 is 0 and we proceed to the second call. This is intentional. The defrag logic
attempts to gather the required total entries (cnt) across multiple sub-banks. If the first bank fails or is full,
we must still try the second bank to see if the combined total can satisfy the request. Since __npc_subbank_alloc()
handles its own internal rollback on failure, there is no leaked state when we 'fall through' to the second attempt.The use of -ENOSPC here is intentional
for the defrag context. Even if a sub-call returned -ENOMEM, the high-level failure at this stage is that the hardware simply does not have
the contiguous space required to perform the defrag move.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v5 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (2 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-30 4:13 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 05/10] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width Ratheesh Kannoth
` (6 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth
npc_defrag_move_vdx_to_free() disables, copies, and enables the MCAM entry
at a new index but previously left entry2target_pffunc[] and the mcam_rules
list still keyed to the old index. Copy the target PF association to the
new slot, clear the old one, and retarget the rule entry so software state
matches the relocated hardware context.
Fixes: 645c6e3c1999 ("octeontx2-af: npc: cn20k: virtual index support")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 87da43088b67..70ce3f49adc1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3602,9 +3602,10 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
struct npc_defrag_node *v,
int cnt, u16 *save)
{
+ u16 new_midx, old_midx, vidx, target_pf;
struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_npc_mcam_rule *rule, *tmp;
int i, vidx_cnt, rc, sb_off;
- u16 new_midx, old_midx, vidx;
struct npc_subbank *sb;
bool deleted;
u16 pcifunc;
@@ -3723,8 +3724,21 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
mcam->entry2pfvf_map[new_midx] = pcifunc;
/* Counter is not preserved */
mcam->entry2cntr_map[new_midx] = new_midx;
+ target_pf = mcam->entry2target_pffunc[old_midx];
+ mcam->entry2target_pffunc[new_midx] = target_pf;
+ mcam->entry2target_pffunc[old_midx] = NPC_MCAM_INVALID_MAP;
+
npc_mcam_set_bit(mcam, new_midx);
+ /* Note: list order is not functionally required for mcam_rules */
+ list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
+ if (rule->entry != old_midx)
+ continue;
+
+ rule->entry = new_midx;
+ break;
+ }
+
/* Mark as invalid */
v->vidx[vidx_cnt - i - 1] = -1;
save[cnt - i - 1] = -1;
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v5 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule
2026-04-29 2:27 ` [PATCH v5 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule Ratheesh Kannoth
@ 2026-04-30 4:13 ` Ratheesh Kannoth
0 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-30 4:13 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev
On 2026-04-29 at 07:57:16, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_defrag_move_vdx_to_free() disables, copies, and enables the MCAM entry
> at a new index but previously left entry2target_pffunc[] and the mcam_rules
> list still keyed to the old index. Copy the target PF association to the
> new slot, clear the old one, and retarget the rule entry so software state
> matches the relocated hardware context.
>
> Fixes: 645c6e3c1999 ("octeontx2-af: npc: cn20k: virtual index support")
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
@@ -3723,8 +3724,21 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
> mcam->entry2pfvf_map[new_midx] = pcifunc;
> /* Counter is not preserved */
> mcam->entry2cntr_map[new_midx] = new_midx;
> + target_pf = mcam->entry2target_pffunc[old_midx];
>Is mcam->entry2target_pffunc always initialized before we read from it here?
>If it was allocated with kmalloc_array() during driver initialization and no
>target PF was explicitly configured for this MCAM entry, could this read
>uninitialized heap memory and copy it to the new index?
The npc_defrag_move_vdx_to_free function only operates on entries that are currently 'in-use' and
being relocated to optimize space. Because the target PF configuration is a prerequisite for an
entry to be considered active in the MCAM pipeline, these fields are guaranteed to be
populated by the time a defrag move is triggered.
> + mcam->entry2target_pffunc[new_midx] = target_pf;
> + mcam->entry2target_pffunc[old_midx] = NPC_MCAM_INVALID_MAP;
> +
> npc_mcam_set_bit(mcam, new_midx);
>
> + /* Note: list order is not functionally required for mcam_rules */
> + list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
> + if (rule->entry != old_midx)
> + continue;
> +
> + rule->entry = new_midx;
>If npc_add_to_pf_maps() fails earlier in this loop, the function returns an
>error without updating these software tracking maps. At that failure point,
>the hardware rule at old_midx has already been disabled and its subbank marked
>as free via __npc_subbank_free().
>Since the hardware subbank is free, could the hardware allocation later
>assign old_midx to a completely new user while our mcam_rules list still
>points to it?
In this specific 'should-never-happen' scenario, attempting a graceful software rewind could mask a critical fault or lead to
further exceptions. My intention with this Smatch fix was to ensure smatch fix, is at least caught and logged rather than silently ignored.
I can address a full transactional rollback mechanism in a separate hardening series for net-next. But issue is gracefull rollback
can also fail as it is kind of another defrag process. or may be we can copy to new entries but not free the existing entries, that would be a
enhancement request for net-next.
>If the old rule's owner later modifies or deletes it, could this cause a
>resource collision and inadvertently destroy the newly allocated rule?
No this wont happen, mbox messages are processed by AF driver sequentially. More than that
mcam->lock mutex is already acquired before all these operations.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v5 net 05/10] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (3 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 06/10] octeontx2-af: npc: cn20k: Fix bank value Ratheesh Kannoth
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Suman Ghosh
Replace the old four-argument CN20K MCAM clear with a per-bank static
helper and npc_cn20k_clear_mcam_entry() that takes a logical MCAM index,
resolves the key width via npc_mcam_idx_2_key_type(), and clears either one
bank (X2) or every bank (X4).
Call it from npc_clear_mcam_entry() on cn20k and log when key-type lookup
fails. Use the per-bank helper from npc_cn20k_config_mcam_entry() for
pre-program clears.
For loopback VFs, use the promisc MCAM index as ucast_idx when copying RSS
action for promisc, matching cn20k default-rule layout.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 37 ++++++++++++++++---
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 3 +-
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 17 ++++++++-
3 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 70ce3f49adc1..112c37c190b1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -842,8 +842,8 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
return 0;
}
-void
-npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index)
+static void
+npc_clear_x2_entry(struct rvu *rvu, int blkaddr, int bank, int index)
{
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 1),
@@ -877,6 +877,33 @@ npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index)
NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, bank), 0);
}
+int
+npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int mcam_idx)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int bank = npc_get_bank(mcam, mcam_idx);
+ u8 kw_type;
+ int index;
+
+ if (npc_mcam_idx_2_key_type(rvu, mcam_idx, &kw_type))
+ return -EINVAL;
+
+ index = mcam_idx & (mcam->banksize - 1);
+
+ if (kw_type == NPC_MCAM_KEY_X2) {
+ npc_clear_x2_entry(rvu, blkaddr, bank, index);
+ return 0;
+ }
+
+ /* For NPC_MCAM_KEY_X4 keys, both the banks
+ * need to be programmed with the same value.
+ */
+ for (bank = 0; bank < mcam->banks_per_entry; bank++)
+ npc_clear_x2_entry(rvu, blkaddr, bank, index);
+
+ return 0;
+}
+
static void npc_cn20k_get_keyword(struct cn20k_mcam_entry *entry, int idx,
u64 *cam0, u64 *cam1)
{
@@ -1071,7 +1098,7 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
*/
if (kw_type == NPC_MCAM_KEY_X2) {
/* Clear mcam entry to avoid writes being suppressed by NPC */
- npc_cn20k_clear_mcam_entry(rvu, blkaddr, bank, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, bank, mcam_idx);
npc_cn20k_config_kw_x2(rvu, mcam, blkaddr,
mcam_idx, intf, entry,
bank, kw_type, kw, req_kw_type);
@@ -1096,8 +1123,8 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
}
/* 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_clear_x2_entry(rvu, blkaddr, 0, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, 1, mcam_idx);
npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
mcam_idx, intf, entry,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 8f3eea9cfb1d..2f761b97f91b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -330,8 +330,7 @@ int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
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_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int index);
int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
u16 npc_cn20k_vidx2idx(u16 index);
u16 npc_cn20k_idx2vidx(u16 idx);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index ecaf0946b852..44ca65efc80f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -261,6 +261,13 @@ static void npc_clear_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int bank = npc_get_bank(mcam, index);
int actbank = bank;
+ if (is_cn20k(rvu->pdev)) {
+ if (npc_cn20k_clear_mcam_entry(rvu, blkaddr, index))
+ dev_err(rvu->dev, "%s Failed to clear mcam %u\n",
+ __func__, index);
+ return;
+ }
+
index &= (mcam->banksize - 1);
for (; bank < (actbank + mcam->banks_per_entry); bank++) {
rvu_write64(rvu, blkaddr,
@@ -755,9 +762,15 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
/* If the corresponding PF's ucast action is RSS,
* use the same action for promisc also
+ * Please note that for lbk(s) "index" and "ucast_idx"
+ * will be same.
*/
- ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
- nixlf, NIXLF_UCAST_ENTRY);
+ if (is_lbk_vf(rvu, pcifunc))
+ ucast_idx = index;
+ else
+ ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+
if (is_mcam_entry_enabled(rvu, mcam, blkaddr, ucast_idx))
*(u64 *)&action = npc_get_mcam_action(rvu, mcam,
blkaddr, ucast_idx);
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v5 net 06/10] octeontx2-af: npc: cn20k: Fix bank value
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (4 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 05/10] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 07/10] octeontx2-af: npc: cn20k: Fix MCAM actions read Ratheesh Kannoth
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Suman Ghosh
For X4 keys its loop reused the bank parameter as the loop counter, so bank
no longer reflected the caller's bank after the loop and the control flow
was hard to follow.
Program NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT directly in
npc_cn20k_config_mcam_entry(): one CFG write for X2 using the computed
bank, and one CFG write per bank inside the X4 action loop. Enable the
entry at the end with npc_cn20k_enable_mcam_entry(..., true) instead of
embedding the enable bit in bank_cfg via the removed helper.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 4e527f1e5c15 ("octeontx2-af: npc: cn20k: Add new mailboxes for CN20K silicon")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 92 ++++++++-----------
1 file changed, 37 insertions(+), 55 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 112c37c190b1..4773277fd409 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -1045,34 +1045,6 @@ static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
kw, req_kw_type);
}
-static void
-npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
- int bank, u8 kw_type, bool enable, u8 hw_prio)
-{
- struct npc_mcam *mcam = &rvu->hw->mcam;
- u64 bank_cfg;
-
- bank_cfg = (u64)hw_prio << 24;
- if (enable)
- bank_cfg |= 0x1;
-
- if (kw_type == NPC_MCAM_KEY_X2) {
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
- bank_cfg);
- return;
- }
-
- /* For NPC_MCAM_KEY_X4 keys, both the banks
- * need to be programmed with the same value.
- */
- for (bank = 0; bank < mcam->banks_per_entry; bank++) {
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
- bank_cfg);
- }
-}
-
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)
@@ -1080,6 +1052,7 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
struct npc_mcam *mcam = &rvu->hw->mcam;
int mcam_idx = index % mcam->banksize;
int bank = index / mcam->banksize;
+ u64 bank_cfg = (u64)hw_prio << 24;
int kw = 0;
u8 kw_type;
@@ -1119,41 +1092,50 @@ int 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);
- goto set_cfg;
- }
- /* Clear mcam entry to avoid writes being suppressed by NPC */
- npc_clear_x2_entry(rvu, blkaddr, 0, mcam_idx);
- npc_clear_x2_entry(rvu, blkaddr, 1, mcam_idx);
-
- npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
- mcam_idx, intf, entry,
- kw_type, req_kw_type);
- for (bank = 0; bank < mcam->banks_per_entry; bank++) {
- /* Set 'action' */
+ /* Set HW priority */
rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
- bank, 0),
- entry->action);
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ bank_cfg);
- /* Set TAG 'action' */
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
- bank, 1),
- entry->vtag_action);
+ } else {
+ /* Clear mcam entry to avoid writes being suppressed by NPC */
+ npc_clear_x2_entry(rvu, blkaddr, 0, mcam_idx);
+ npc_clear_x2_entry(rvu, blkaddr, 1, mcam_idx);
- /* Set 'action2' for inline receive */
- rvu_write64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
- bank, 2),
- entry->action2);
+ npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
+ mcam_idx, intf, entry,
+ kw_type, req_kw_type);
+ for (bank = 0; bank < mcam->banks_per_entry; bank++) {
+ /* Set 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 0),
+ entry->action);
+
+ /* Set TAG 'action' */
+ rvu_write64(rvu, blkaddr,
+ 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 HW priority */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ bank_cfg);
+ }
}
-set_cfg:
/* TODO: */
/* PF installing VF rule */
- npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
- kw_type, enable, hw_prio);
+ if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable))
+ return -EINVAL;
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v5 net 07/10] octeontx2-af: npc: cn20k: Fix MCAM actions read
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (5 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 06/10] octeontx2-af: npc: cn20k: Fix bank value Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 08/10] octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front Ratheesh Kannoth
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Suman Ghosh
npc_cn20k_read_mcam_entry() always reloaded action and vtag_action from
bank 0 after programming the CAM words. Use the bank returned by
npc_get_bank() for the ACTION reads as well, and read those registers once
up front so both X2 and X4 paths share the same metadata.
Return directly from the X2 keyword path now that the action fields are
already populated.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 4773277fd409..bb0a9ac7aab3 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -1219,6 +1219,18 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0));
+ entry->action = cfg;
+
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 1));
+ entry->vtag_action = cfg;
+
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 2));
+ entry->action2 = cfg;
+
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index,
bank, 1)) & 3;
@@ -1268,7 +1280,7 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
bank,
0));
npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
- goto read_action;
+ return 0;
}
for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4) {
@@ -1313,18 +1325,6 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
}
-read_action:
- /* 'action' is set to same value for both bank '0' and '1'.
- * Hence, reading bank '0' should be enough.
- */
- cfg = rvu_read64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 0));
- entry->action = cfg;
-
- cfg = rvu_read64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
- entry->vtag_action = cfg;
-
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v5 net 08/10] octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (6 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 07/10] octeontx2-af: npc: cn20k: Fix MCAM actions read Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free Ratheesh Kannoth
` (2 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth
npc_cn20k_dft_rules_idx_get() wrote USHRT_MAX into individual outputs only
on some error paths (lbk promisc lookup, VF ucast lookup, and the PF rule
walk), which could leave other caller slots stale across retries.
Set every non-NULL bcast/mcast/promisc/ucast pointer to USHRT_MAX once at
entry, then drop the duplicate assignments on failure. Successful lookups
still overwrite the relevant slot before returning.
Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index bb0a9ac7aab3..b3f34b84c114 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4016,6 +4016,13 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
void *val;
int i, j;
+ for (i = 0; i < ARRAY_SIZE(ptr); i++) {
+ if (!ptr[i])
+ continue;
+
+ *ptr[i] = USHRT_MAX;
+ }
+
if (!npc_priv.init_done)
return 0;
@@ -4031,7 +4038,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
pcifunc);
- *ptr[0] = USHRT_MAX;
return -ESRCH;
}
@@ -4051,7 +4057,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
pcifunc);
- *ptr[3] = USHRT_MAX;
return -ESRCH;
}
@@ -4071,7 +4076,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
__func__,
npc_dft_rule_name[i], pcifunc);
- *ptr[j] = USHRT_MAX;
continue;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v5 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (7 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 08/10] octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-30 4:15 ` Ratheesh Kannoth
2026-04-29 2:27 ` [PATCH v5 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices Ratheesh Kannoth
2026-05-01 2:00 ` [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes patchwork-bot+netdevbpf
10 siblings, 1 reply; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth
npc_cn20k_dft_rules_free() used the NPC MCAM mbox "free all" path, which
does not match how cn20k tracks default-rule MCAM slots indexes.
Resolve the default-rule indices, then for each valid slot clear the bitmap
entry, drop the PF/VF map, disable the MCAM line, clear the target
function, and npc_cn20k_idx_free(). Remove any matching software mcam_rules
nodes. On hard failure from idx_free, WARN and stop so the box stays up for
analysis.
In npc_mcam_free_all_entries(), prefetch the same default-rule indices and,
on cn20k, skip bitmap clear and idx_free when the scanned entry is one of
those reserved defaults (they are released by npc_cn20k_dft_rules_free).
Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 51 ++++++++++++----
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 59 +++++++++++++------
2 files changed, 82 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index b3f34b84c114..1129565a01bd 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4178,11 +4178,11 @@ static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
{
- struct npc_mcam_free_entry_req free_req = { 0 };
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u16 ptr[4] = {[0 ... 3] = USHRT_MAX};
+ struct rvu_npc_mcam_rule *rule, *tmp;
unsigned long index;
- struct msg_rsp rsp;
- u16 ptr[4];
- int rc, i;
+ int blkaddr, rc, i;
void *map;
if (!npc_priv.init_done)
@@ -4240,14 +4240,43 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
}
free_rules:
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+ for (int i = 0; i < 4; i++) {
+ if (ptr[i] == USHRT_MAX)
+ continue;
- free_req.hdr.pcifunc = pcifunc;
- free_req.all = 1;
- rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
- if (rc)
- dev_err(rvu->dev,
- "%s: Error deleting default entries (pcifunc=%#x\n",
- __func__, pcifunc);
+ mutex_lock(&mcam->lock);
+ npc_mcam_clear_bit(mcam, ptr[i]);
+ mcam->entry2pfvf_map[ptr[i]] = NPC_MCAM_INVALID_MAP;
+ npc_cn20k_enable_mcam_entry(rvu, blkaddr, ptr[i], false);
+ mcam->entry2target_pffunc[ptr[i]] = 0x0;
+ mutex_unlock(&mcam->lock);
+
+ rc = npc_cn20k_idx_free(rvu, &ptr[i], 1);
+ if (rc) {
+ /* Non recoverable error. Let us WARN and return. Keep system alive to
+ * enable debugging
+ */
+ WARN(1, "%s Error deleting default entries (pcifunc=%#x) mcam_idx=%u\n",
+ __func__, pcifunc, ptr[i]);
+ return;
+ }
+ }
+
+ mutex_lock(&mcam->lock);
+ list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
+ for (int i = 0; i < 4; i++) {
+ if (ptr[i] != rule->entry)
+ continue;
+
+ list_del(&rule->list);
+ kfree(rule);
+ break;
+ }
+ }
+ mutex_unlock(&mcam->lock);
}
int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 44ca65efc80f..5d349d131fdb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -2521,33 +2521,58 @@ void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index)
static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, u16 pcifunc)
{
+ u16 dft_idxs[NPC_DFT_RULE_MAX_ID] = {[0 ... NPC_DFT_RULE_MAX_ID - 1] = USHRT_MAX};
+ bool cn20k_dft_rl;
u16 index, cntr;
int rc;
+ npc_cn20k_dft_rules_idx_get(rvu, pcifunc,
+ &dft_idxs[NPC_DFT_RULE_BCAST_ID],
+ &dft_idxs[NPC_DFT_RULE_MCAST_ID],
+ &dft_idxs[NPC_DFT_RULE_PROMISC_ID],
+ &dft_idxs[NPC_DFT_RULE_UCAST_ID]);
+
/* Scan all MCAM entries and free the ones mapped to 'pcifunc' */
for (index = 0; index < mcam->bmap_entries; index++) {
- if (mcam->entry2pfvf_map[index] == pcifunc) {
+ if (mcam->entry2pfvf_map[index] != pcifunc)
+ continue;
+
+ cn20k_dft_rl = false;
+
+ if (is_cn20k(rvu->pdev)) {
+ if (dft_idxs[NPC_DFT_RULE_BCAST_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_MCAST_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_PROMISC_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_UCAST_ID] == index) {
+ cn20k_dft_rl = true;
+ }
+ }
+
+ /* Disable the entry */
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+
+ if (!cn20k_dft_rl) {
mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
/* Free the entry in bitmap */
npc_mcam_clear_bit(mcam, index);
- /* Disable the entry */
- npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
-
- /* Update entry2counter mapping */
- cntr = mcam->entry2cntr_map[index];
- if (cntr != NPC_MCAM_INVALID_MAP)
- npc_unmap_mcam_entry_and_cntr(rvu, mcam,
- blkaddr, index,
- cntr);
mcam->entry2target_pffunc[index] = 0x0;
- if (is_cn20k(rvu->pdev)) {
- rc = npc_cn20k_idx_free(rvu, &index, 1);
- if (rc)
- dev_err(rvu->dev,
- "Failed to free mcam idx=%u pcifunc=%#x\n",
- index, pcifunc);
- }
}
+
+ /* Update entry2counter mapping */
+ cntr = mcam->entry2cntr_map[index];
+ if (cntr != NPC_MCAM_INVALID_MAP)
+ npc_unmap_mcam_entry_and_cntr(rvu, mcam,
+ blkaddr, index,
+ cntr);
+
+ if (!is_cn20k(rvu->pdev) || cn20k_dft_rl)
+ continue;
+
+ rc = npc_cn20k_idx_free(rvu, &index, 1);
+ if (rc)
+ dev_err(rvu->dev,
+ "Failed to free mcam idx=%u pcifunc=%#x\n",
+ index, pcifunc);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v5 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
2026-04-29 2:27 ` [PATCH v5 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free Ratheesh Kannoth
@ 2026-04-30 4:15 ` Ratheesh Kannoth
0 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-30 4:15 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev
On 2026-04-29 at 07:57:21, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_cn20k_dft_rules_free() used the NPC MCAM mbox "free all" path, which
> does not match how cn20k tracks default-rule MCAM slots indexes.
>
> Resolve the default-rule indices, then for each valid slot clear the bitmap
> entry, drop the PF/VF map, disable the MCAM line, clear the target
> function, and npc_cn20k_idx_free(). Remove any matching software mcam_rules
> nodes. On hard failure from idx_free, WARN and stop so the box stays up for
> analysis.
>
> In npc_mcam_free_all_entries(), prefetch the same default-rule indices and,
> on cn20k, skip bitmap clear and idx_free when the scanned entry is one of
> those reserved defaults (they are released by npc_cn20k_dft_rules_free).
>
> Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Patch 9: [PATCH v5 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
> free_rules:
> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> + if (blkaddr < 0)
> + return;
>Can this lead to a resource leak if blkaddr < 0?
>The tracking entries are removed from xa_pf2dfl_rmap via xa_erase() earlier
>in the function, before validating the block address. If rvu_get_blkaddr()
>fails and returns early, the rules remain allocated but the tracking
>information is permanently lost.
This condition will never fail for NPC block. This condition is there because of legacy coding method where every function
has this check. We need to put an effort to remove all these check from all functions and should have only one check during probe time to
validate this. That should be a candidate for net-next.
> + for (int i = 0; i < 4; i++) {
> + if (ptr[i] == USHRT_MAX)
> + continue;
>
> - free_req.hdr.pcifunc = pcifunc;
> - free_req.all = 1;
> - rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
> - if (rc)
> - dev_err(rvu->dev,
> - "%s: Error deleting default entries (pcifunc=%#x\n",
> - __func__, pcifunc);
> + mutex_lock(&mcam->lock);
> + npc_mcam_clear_bit(mcam, ptr[i]);
> + mcam->entry2pfvf_map[ptr[i]] = NPC_MCAM_INVALID_MAP;
> + npc_cn20k_enable_mcam_entry(rvu, blkaddr, ptr[i], false);
> + mcam->entry2target_pffunc[ptr[i]] = 0x0;
> + mutex_unlock(&mcam->lock);
>Is it possible for another thread to allocate this index before the rules
>list is cleaned up?
>The mcam->lock is released immediately after npc_mcam_clear_bit() is called,
>which makes the index available in the software bitmap. If a concurrent
>thread allocates this same index and adds its own rule to mcam->mcam_rules,
>could the subsequent list_for_each_entry_safe() loop mistakenly delete and
>free the newly allocated rule?
No. These are allocated thru mbox messages and are processed serially by AF driver.
So multiple thread issue wont happen.
> +
> + rc = npc_cn20k_idx_free(rvu, &ptr[i], 1);
> + if (rc) {
> + /* Non recoverable error. Let us WARN and return. Keep system alive to
> + * enable debugging
> + */
> + WARN(1, "%s Error deleting default entries (pcifunc=%#x) mcam_idx=%u\n",
> + __func__, pcifunc, ptr[i]);
> + return;
>Does returning here leak the mcam_rules entries?
>If npc_cn20k_idx_free() fails, the function returns early. This skips the
>trailing list deletion loop, permanently leaking the rule structures for the
>failed index and any previously successful indices. Additionally, because
>npc_mcam_clear_bit() was already called for these indices, they appear
>available in the software bitmap, meaning subsequent allocations might get an
>index while the old rule node is still dangling.
Yes. we need that state to debug the issue if it ever happens than freeing mcam rule entries, as mcam rule entries
debugfs provide more information to debug. so lets keep this way.
> }
> +
> + /* Update entry2counter mapping */
> + cntr = mcam->entry2cntr_map[index];
> + if (cntr != NPC_MCAM_INVALID_MAP)
> + npc_unmap_mcam_entry_and_cntr(rvu, mcam,
> + blkaddr, index,
> + cntr);
>Does this unintentionally disable default rules in hardware?
>The calls to npc_enable_mcam_entry(..., false) and
>npc_unmap_mcam_entry_and_cntr(...) now occur before the cn20k_dft_rl check
>and the if (!cn20k_dft_rl) block. If a VF resets its filters (e.g., via an
>all=1 free request), its default rules (like UCAST or BCAST) appear to be
>permanently disabled in hardware and their counters unmapped, which might
>cause the VF to lose network connectivity until completely reinitialized.
> +
> + if (!is_cn20k(rvu->pdev) || cn20k_dft_rl)
> + continue;
> +
> + rc = npc_cn20k_idx_free(rvu, &index, 1);
> + if (rc)
> + dev_err(rvu->dev,
> + "Failed to free mcam idx=%u pcifunc=%#x\n",
> + index, pcifunc);
> }
> }
VF has only UCAST rules.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v5 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (8 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free Ratheesh Kannoth
@ 2026-04-29 2:27 ` Ratheesh Kannoth
2026-04-30 4:17 ` Ratheesh Kannoth
2026-05-01 2:00 ` [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes patchwork-bot+netdevbpf
10 siblings, 1 reply; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-29 2:27 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Ratheesh Kannoth, Suman Ghosh
When cn20k default L2 rules are not installed,
npc_cn20k_dft_rules_idx_get() leaves broadcast, multicast, promiscuous, and
unicast slots at USHRT_MAX. npc_get_nixlf_mcam_index() previously returned
that sentinel as a valid MCAM index, so callers could program hardware with
an invalid index.
Return -EINVAL from the cn20k branches of npc_get_nixlf_mcam_index() when
the requested slot is still USHRT_MAX. Harden cn20k NPC MCAM entry helpers
to reject out-of-range indices before touching hardware.
Drop the early bounds check in npc_enable_mcam_entry() for cn20k so invalid
indices are validated inside npc_cn20k_enable_mcam_entry() instead of being
silently ignored.
In rvu_npc_update_flowkey_alg_idx(), treat negative MCAM indices like
out-of-range values, and only update RSS actions for promiscuous and
all-multi paths when the resolved index is non-negative.
Cc: Suman Ghosh <sumang@marvell.com>
Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 14 +-
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 1 +
.../ethernet/marvell/octeontx2/af/rvu_nix.c | 3 +
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 137 +++++++++++++++++-
.../marvell/octeontx2/af/rvu_npc_fs.c | 10 +-
5 files changed, 155 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 1129565a01bd..6b3f453fd500 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -808,6 +808,9 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
u64 cfg, hw_prio;
u8 kw_type;
+ if (index < 0 || index >= mcam->total_entries)
+ return -EINVAL;
+
if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
return -EINVAL;
@@ -1056,6 +1059,9 @@ int npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
int kw = 0;
u8 kw_type;
+ if (index < 0 || index >= mcam->total_entries)
+ return -EINVAL;
+
if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
return -EINVAL;
@@ -1148,6 +1154,9 @@ int npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
int bank, i, sb, db;
int dbank, sbank;
+ if (src >= mcam->total_entries || dest >= mcam->total_entries)
+ return -EINVAL;
+
dbank = npc_get_bank(mcam, dest);
sbank = npc_get_bank(mcam, src);
@@ -1213,6 +1222,9 @@ int npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
int kw = 0, bank;
u8 kw_type;
+ if (index >= mcam->total_entries)
+ return -EINVAL;
+
if (npc_mcam_idx_2_key_type(rvu, index, &kw_type))
return -EINVAL;
@@ -4170,7 +4182,7 @@ int rvu_mbox_handler_npc_get_dft_rl_idxs(struct rvu *rvu, struct msg_req *req,
return 0;
}
-static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
+bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
{
return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) ||
is_lbk_vf(rvu, pcifunc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 2f761b97f91b..3d5eb952cc07 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -335,5 +335,6 @@ int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
u16 npc_cn20k_vidx2idx(u16 index);
u16 npc_cn20k_idx2vidx(u16 idx);
int npc_cn20k_defrag(struct rvu *rvu);
+bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc);
#endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index ef5b081162eb..f977734ae712 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -3577,6 +3577,9 @@ static int nix_update_mce_rule(struct rvu *rvu, u16 pcifunc,
mcam_index = npc_get_nixlf_mcam_index(mcam,
pcifunc & ~RVU_PFVF_FUNC_MASK,
nixlf, type);
+ if (mcam_index < 0)
+ return -EINVAL;
+
err = nix_update_mce_list(rvu, pcifunc, mce_list,
mce_idx, mcam_index, add);
return err;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 5d349d131fdb..3c814d157ab9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -163,14 +163,35 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
if (rc)
return -EFAULT;
+ if (is_lbk_vf(rvu, pcifunc)) {
+ if (promisc == USHRT_MAX)
+ return -EINVAL;
+ return promisc;
+ }
+
+ if (is_cgx_vf(rvu, pcifunc)) {
+ if (ucast == USHRT_MAX)
+ return -EINVAL;
+
+ return ucast;
+ }
+
switch (type) {
case NIXLF_BCAST_ENTRY:
+ if (bcast == USHRT_MAX)
+ return -EINVAL;
return bcast;
case NIXLF_ALLMULTI_ENTRY:
+ if (mcast == USHRT_MAX)
+ return -EINVAL;
return mcast;
case NIXLF_PROMISC_ENTRY:
+ if (promisc == USHRT_MAX)
+ return -EINVAL;
return promisc;
case NIXLF_UCAST_ENTRY:
+ if (ucast == USHRT_MAX)
+ return -EINVAL;
return ucast;
default:
return -EINVAL;
@@ -238,9 +259,6 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int actbank = bank;
if (is_cn20k(rvu->pdev)) {
- if (index < 0 || index >= mcam->banksize * mcam->banks)
- return;
-
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);
@@ -434,6 +452,15 @@ static u64 npc_get_default_entry_action(struct rvu *rvu, struct npc_mcam *mcam,
index = npc_get_nixlf_mcam_index(mcam, pf_func, nixlf,
NIXLF_UCAST_ENTRY);
+
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: failed to get ucast entry pcifunc:0x%x\n",
+ __func__, pf_func);
+ /* Action 0 is drop */
+ return 0;
+ }
+
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
@@ -700,6 +727,12 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get ucast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
/* Don't change the action if entry is already enabled
* Otherwise RSS action may get overwritten.
@@ -755,11 +788,21 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_PROMISC_ENTRY);
+ /* In cn20k, default indexes are installed only for CGX mapped
+ * and lbk interfaces
+ */
if (is_cgx_vf(rvu, pcifunc))
index = npc_get_nixlf_mcam_index(mcam,
pcifunc & ~RVU_PFVF_FUNC_MASK,
nixlf, NIXLF_PROMISC_ENTRY);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get promisc entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
+
/* If the corresponding PF's ucast action is RSS,
* use the same action for promisc also
* Please note that for lbk(s) "index" and "ucast_idx"
@@ -770,6 +813,12 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
else
ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
+ if (ucast_idx < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get ucast/promisc entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
if (is_mcam_entry_enabled(rvu, mcam, blkaddr, ucast_idx))
*(u64 *)&action = npc_get_mcam_action(rvu, mcam,
@@ -844,6 +893,14 @@ void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc,
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_PROMISC_ENTRY);
+
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get promisc entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
+
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
}
@@ -884,6 +941,12 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_BCAST_ENTRY);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get bcast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
if (!hw->cap.nix_rx_multicast) {
/* Early silicon doesn't support pkt replication,
@@ -948,12 +1011,25 @@ void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_ALLMULTI_ENTRY);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get mcast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
/* If the corresponding PF's ucast action is RSS,
* use the same action for multicast entry also
*/
ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
+ if (ucast_idx < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get ucast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
+
if (is_mcam_entry_enabled(rvu, mcam, blkaddr, ucast_idx))
*(u64 *)&action = npc_get_mcam_action(rvu, mcam,
blkaddr, ucast_idx);
@@ -1018,6 +1094,13 @@ void rvu_npc_enable_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
NIXLF_ALLMULTI_ENTRY);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get mcast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
+
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
}
@@ -1130,8 +1213,12 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
index = mcam_index;
}
- if (index >= mcam->total_entries)
+ if (index < 0 || index >= mcam->total_entries) {
+ dev_err(rvu->dev,
+ "%s: Invalid mcam index, pcifunc=%#x\n",
+ __func__, pcifunc);
return;
+ }
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
@@ -1175,16 +1262,18 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
/* If PF's promiscuous entry is enabled,
* Set RSS action for that entry as well
*/
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
- blkaddr, alg_idx);
+ if (index >= 0)
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
+ blkaddr, alg_idx);
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_ALLMULTI_ENTRY);
/* If PF's allmulti entry is enabled,
* Set RSS action for that entry as well
*/
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
- blkaddr, alg_idx);
+ if (index >= 0)
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
+ blkaddr, alg_idx);
}
}
@@ -1197,12 +1286,22 @@ void npc_enadis_default_mce_entry(struct rvu *rvu, u16 pcifunc,
int index, blkaddr, mce_idx;
struct rvu_pfvf *pfvf;
+ /* multicast pkt replication is not enabled for AF's VFs & SDP links */
+ if (is_lbk_vf(rvu, pcifunc) || is_sdp_pfvf(rvu, pcifunc))
+ return;
+
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
return;
index = npc_get_nixlf_mcam_index(mcam, pcifunc & ~RVU_PFVF_FUNC_MASK,
nixlf, type);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get entry for pcifunc=%#x, type=%u\n",
+ __func__, pcifunc, type);
+ return;
+ }
/* disable MCAM entry when packet replication is not supported by hw */
if (!hw->cap.nix_rx_multicast && !is_vf(pcifunc)) {
@@ -1231,6 +1330,10 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
struct npc_mcam *mcam = &rvu->hw->mcam;
int index, blkaddr;
+ /* only CGX or LBK interfaces have default entries */
+ if (is_cn20k(rvu->pdev) && !npc_is_cgx_or_lbk(rvu, pcifunc))
+ return;
+
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
return;
@@ -1240,6 +1343,12 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
pfvf->nix_rx_intf)) {
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
+ if (index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get ucast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
}
@@ -3897,6 +4006,12 @@ int rvu_mbox_handler_npc_read_base_steer_rule(struct rvu *rvu,
/* Read the default ucast entry if there is no pkt steering rule */
index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
NIXLF_UCAST_ENTRY);
+ if (index < 0) {
+ mutex_unlock(&mcam->lock);
+ rc = NIX_AF_ERR_AF_LF_INVALID;
+ goto out;
+ }
+
read_entry:
/* Read the mcam entry */
npc_read_mcam_entry(rvu, mcam, blkaddr, index, &rsp->entry, &intf,
@@ -3970,6 +4085,12 @@ void rvu_npc_clear_ucast_entry(struct rvu *rvu, int pcifunc, int nixlf)
ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
+ if (ucast_idx < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get ucast entry for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
npc_enable_mcam_entry(rvu, mcam, blkaddr, ucast_idx, false);
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 fe10554b1f0e..6ae9cdcb608b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -1444,7 +1444,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
struct msg_rsp write_rsp;
struct mcam_entry *entry;
bool new = false;
- u16 entry_index;
+ int entry_index;
int err;
installed_features = req->features;
@@ -1477,6 +1477,14 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
if (req->default_rule) {
entry_index = npc_get_nixlf_mcam_index(mcam, target, nixlf,
NIXLF_UCAST_ENTRY);
+
+ if (entry_index < 0) {
+ dev_err(rvu->dev,
+ "%s: Error to get ucast entry for target=%#x\n",
+ __func__, target);
+ return -EINVAL;
+ }
+
enable = is_mcam_entry_enabled(rvu, mcam, blkaddr, entry_index);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v5 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
2026-04-29 2:27 ` [PATCH v5 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices Ratheesh Kannoth
@ 2026-04-30 4:17 ` Ratheesh Kannoth
0 siblings, 0 replies; 17+ messages in thread
From: Ratheesh Kannoth @ 2026-04-30 4:17 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Suman Ghosh
On 2026-04-29 at 07:57:22, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> When cn20k default L2 rules are not installed,
> npc_cn20k_dft_rules_idx_get() leaves broadcast, multicast, promiscuous, and
> unicast slots at USHRT_MAX. npc_get_nixlf_mcam_index() previously returned
> that sentinel as a valid MCAM index, so callers could program hardware with
> an invalid index.
>
> Return -EINVAL from the cn20k branches of npc_get_nixlf_mcam_index() when
> the requested slot is still USHRT_MAX. Harden cn20k NPC MCAM entry helpers
> to reject out-of-range indices before touching hardware.
>
> Drop the early bounds check in npc_enable_mcam_entry() for cn20k so invalid
> indices are validated inside npc_cn20k_enable_mcam_entry() instead of being
> silently ignored.
>
> In rvu_npc_update_flowkey_alg_idx(), treat negative MCAM indices like
> out-of-range values, and only update RSS actions for promiscuous and
> all-multi paths when the resolved index is non-negative.
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> index 5d349d131fdb..3c814d157ab9 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> @@ -163,14 +163,35 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
> if (rc)
> return -EFAULT;
>
> + if (is_lbk_vf(rvu, pcifunc)) {
> + if (promisc == USHRT_MAX)
> + return -EINVAL;
> + return promisc;
> + }
> +
[ ... ]
> @@ -3897,6 +4006,12 @@ int rvu_mbox_handler_npc_read_base_steer_rule(struct rvu *rvu,
> /* Read the default ucast entry if there is no pkt steering rule */
> index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
> NIXLF_UCAST_ENTRY);
> + if (index < 0) {
> + mutex_unlock(&mcam->lock);
> + rc = NIX_AF_ERR_AF_LF_INVALID;
> + goto out;
> + }
> +
>Could this change cause a regression in the cn20k-specific base steer rule
>handler?
>While this generic handler correctly returns an explicit error when
>npc_get_nixlf_mcam_index() returns a negative value, it looks like
>rvu_mbox_handler_npc_cn20k_read_base_steer_rule() in
>drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c was missed.
>In that function, rc is 0 from the preceding successful call to
>nix_get_nixlf():
This is not an issue introduced by this fix patch. I agree that this is an issue, but should
be addressed as another net patch as fix.
>While this generic handler correctly returns an explicit error when
>npc_get_nixlf_mcam_index() returns a negative value, it looks like
>rvu_mbox_handler_npc_cn20k_read_base_steer_rule() in
>drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c was missed.
>In that function, rc is 0 from the preceding successful call to
>nix_get_nixlf():
>drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c:
>rvu_mbox_handler_npc_cn20k_read_base_steer_rule() {
...
rc = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
if (rc < 0) {
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, rl_type);
if (index < 0) {
mutex_unlock(&mcam->lock);
goto out;
}
...
out:
return rc;
}
>Does this now silently return 0 (Success) instead of propagating the error
>when index < 0? This seems like it could leak an uninitialized or zeroed
>rsp->entry payload back to the VF.
This is not an issue introduced by this fix patch. I agree that this is an issue, but should
be addressed as another net patch as fix.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes
2026-04-29 2:27 [PATCH v5 net 00/10] octeontx2-af: npc: cn20k: MCAM fixes Ratheesh Kannoth
` (9 preceding siblings ...)
2026-04-29 2:27 ` [PATCH v5 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices Ratheesh Kannoth
@ 2026-05-01 2:00 ` patchwork-bot+netdevbpf
10 siblings, 0 replies; 17+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-05-01 2:00 UTC (permalink / raw)
To: Ratheesh Kannoth
Cc: netdev, linux-kernel, sgoutham, davem, edumazet, kuba, pabeni,
andrew+netdev
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 29 Apr 2026 07:57:12 +0530 you wrote:
> This series tightens Marvell OcteonTX2 AF NPC support for CN20K silicon
> around MCAM key typing, optional debugfs setup, defrag allocation rollback,
> defrag entry relocation bookkeeping, logical MCAM clear and programming,
> default-rule index handling with explicit teardown, and NIXLF reserved-slot
> lookup when default rules are missing.
>
> Patches 1 through 3 focus on AF error handling: propagate
> npc_mcam_idx_2_key_type() failures through cn20k MCAM enable, config, copy,
> and read paths; treat cn20k NPC debugfs nodes as optional so probe does not
> fail when debugfs is unavailable; and fix defrag MCAM allocation rollback
> so allocation errno is not overwritten during subbank index resolution.
>
> [...]
Here is the summary with links:
- [v5,net,01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
https://git.kernel.org/netdev/net/c/aaadccde312f
- [v5,net,02/10] octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init
https://git.kernel.org/netdev/net/c/1100af13fd14
- [v5,net,03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
https://git.kernel.org/netdev/net/c/adb5ff41efbc
- [v5,net,04/10] octeontx2-af: npc: cn20k: Fix target map and rule
https://git.kernel.org/netdev/net/c/d7e5940c4c50
- [v5,net,05/10] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
https://git.kernel.org/netdev/net/c/d2dabf09632c
- [v5,net,06/10] octeontx2-af: npc: cn20k: Fix bank value
https://git.kernel.org/netdev/net/c/2b6d6bb7282c
- [v5,net,07/10] octeontx2-af: npc: cn20k: Fix MCAM actions read
https://git.kernel.org/netdev/net/c/f6803eb070bf
- [v5,net,08/10] octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front
https://git.kernel.org/netdev/net/c/afb474bd4ffc
- [v5,net,09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
https://git.kernel.org/netdev/net/c/013717353c03
- [v5,net,10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
https://git.kernel.org/netdev/net/c/bc968f61bf0a
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 17+ messages in thread