Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v3 net 06/11] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
From: Ratheesh Kannoth @ 2026-04-27  3:44 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Suman Ghosh
In-Reply-To: <20260423104317.2707923-7-rkannoth@marvell.com>

On 2026-04-23 at 16:13:12, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> 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,

https://sashiko.dev/#/patchset/20260423104317.2707923-1-rkannoth%40marvell.com

> @@ -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);
> +
Should this LBK VF handling also be applied to rvu_npc_install_allmulti_entry()
and rvu_npc_update_flowkey_alg_idx()?
It looks like rvu_npc_install_allmulti_entry() tries to skip LBK VFs but uses
an impossible condition:
if (is_lbk_vf(...) && is_sdp_vf(...))
Since a VF cannot be both simultaneously, LBK VFs proceed and call
npc_get_nixlf_mcam_index() for NIXLF_ALLMULTI_ENTRY and NIXLF_UCAST_ENTRY.
For LBK VFs, npc_cn20k_dft_rules_idx_get() only populates the promisc pointer
and returns 0, leaving the stack variables for mcast and ucast uninitialized.
These uninitialized values might then be used to read and write hardware
rules via rvu_mbox_handler_npc_install_flow(), potentially corrupting MCAM
rules.

Agree, but this bug is introduced by a different commit. But the change
"Patch 6: [PATCH v3 net 06/11] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width"
is a bug fix and is for another issue. So dont want to club it with this and will be addressed
in a followup patch; that will be posted once this patch series is merged.

Similarly, rvu_npc_update_flowkey_alg_idx() retrieves NIXLF_UCAST_ENTRY
without checking for LBK VFs, which might lead to the same uninitialized read.
Even if later commits in this series initialize these variables to zero, could
that just cause deterministic corruption of MCAM index 0 instead of random
memory corruption, unless LBK VFs are properly handled or skipped in these
functions as well?

Agree, but this bug is introduced by a different commit. But the change
"Patch 6: [PATCH v3 net 06/11] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width"
is a bug fix and is for another issue. So dont want to club it with this and will be addressed
in a followup patch; that will be posted once this patch series is merged.

^ permalink raw reply

* Re: [PATCH v3 net 10/11] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
From: Ratheesh Kannoth @ 2026-04-27  3:53 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev
In-Reply-To: <20260423104317.2707923-11-rkannoth@marvell.com>

On 2026-04-23 at 16:13:16, 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). Still disable the entry and tear down counter
> mapping for every matching index.
>
> Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>

>> octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
>[ ... ]
>> 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.
>The commit message says "WARN and stop", but looking at the code below,
>there doesn't appear to be a stop.

ACK. will add a "return" from here. This issue indicates fundemental error in mcam allocation
algorithm. There is no point in graceful handling of error. Returning from here would allow the
debugger to understand the current state of the system and debug the issue.

>> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
>> index 6d3166960a3f2a..54a25d9c55053e 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
>> @@ -4228,14 +4228,47 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
>[ ... ]
>> +	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]);
>Can this lead to a double-free of the default rules?
>If an unprivileged VF manually frees its default rule by sending an
>NPC_MCAM_FREE_ENTRY mailbox message,

default entiries are always allocated by Kernel; not by an unprivileged VF manually.

>the single-entry free handler
>(rvu_mbox_handler_npc_mcam_free_entry) frees the hardware index and clears
>the software bitmap, but it does not remove the index from the AF's internal
>xa_pf2dfl_rmap xarray.
>When the VF is later detached, this code fetches the same index from the
>xarray and unconditionally calls npc_mcam_clear_bit(), which increments
>mcam->bmap_fcnt++ and artificially inflates the free count.
>> +		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);
>Since the subbank bitmap was already cleared by the single-entry free
>handler, wouldn't npc_cn20k_idx_free() return -EINVAL for the already
>freed index?
>> +		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]);
>Does this allow an unprivileged VF to trigger kernel warnings (causing a DoS
>if panic_on_warn is enabled) by freeing its default rules before detaching?

default entiries are always allocated by Kernel; not by an unprivileged VF manually.

>Also, the inline comment says "Let us WARN and return", but there is no
>return or break statement here. Does this just continue the loop instead of
>stopping as intended?

>> +
>> +			/* Clear entries from mcam_rules, whose indexes are successfully freed
>> +			 * by npc_cn20k_idx_free().
>> +			 */
>> +			ptr[i] = USHRT_MAX;
>> +		}
>> +	}

^ permalink raw reply

* Re: [PATCH v3 net 11/11] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
From: Ratheesh Kannoth @ 2026-04-27  4:18 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Suman Ghosh
In-Reply-To: <20260423104317.2707923-12-rkannoth@marvell.com>

On 2026-04-23 at 16:13:17, 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.
>
> 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   | 138 +++++++++++++++++-
>  .../marvell/octeontx2/af/rvu_npc_fs.c         |  10 +-
>  .../marvell/octeontx2/af/rvu_npc_hash.c       |  19 ++-
>  .../marvell/octeontx2/nic/otx2_flows.c        |   1 +
>  7 files changed, 172 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> index 54a25d9c5505..1b3f2421ea32 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;
>
> @@ -4158,7 +4170,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..611cd7fce245 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,13 @@ 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) {
> +		dev_err(rvu->dev,
> +			"%s: Error to get ucast entry for pcifunc=%#x\n",
> +			__func__, pcifunc);
> +		goto out;
> +	}
> +
>  read_entry:
>  	/* Read the mcam entry */
>  	npc_read_mcam_entry(rvu, mcam, blkaddr, index, &rsp->entry, &intf,
> @@ -3970,6 +4086,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 dd5d50d52964..d20eb0e47d7d 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);
>  	}
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
> index 03bb485a1aca..59c1a105faad 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
> @@ -1753,7 +1753,7 @@ int rvu_npc_exact_mac_addr_set(struct rvu *rvu, struct cgx_mac_addr_set_or_get *
>  	u32 seq_id = req->index;
>  	struct rvu_pfvf *pfvf;
>  	u8 cgx_id, lmac_id;
> -	u32 mcam_idx = -1;
> +	int mcam_idx = -1;
>  	int rc, nixlf;
>
>  	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
> @@ -1783,9 +1783,20 @@ int rvu_npc_exact_mac_addr_set(struct rvu *rvu, struct cgx_mac_addr_set_or_get *
>
>  	/* find mcam entry if exist */
>  	rc = nix_get_nixlf(rvu, req->hdr.pcifunc, &nixlf, NULL);
> -	if (!rc) {
> -		mcam_idx = npc_get_nixlf_mcam_index(&rvu->hw->mcam, req->hdr.pcifunc,
> -						    nixlf, NIXLF_UCAST_ENTRY);
> +	if (rc) {
> +		dev_err(rvu->dev,
> +			"%s: Error to get nixlf pcifunc=%#x\n",
> +			__func__, req->hdr.pcifunc);
> +		return LMAC_AF_ERR_PERM_DENIED;
> +	}
> +
> +	mcam_idx = npc_get_nixlf_mcam_index(&rvu->hw->mcam, req->hdr.pcifunc,
> +					    nixlf, NIXLF_UCAST_ENTRY);
> +	if (mcam_idx < 0) {
> +		dev_err(rvu->dev,
> +			"%s: Error to get ucast entry for pcifunc=%#x\n",
> +			__func__, req->hdr.pcifunc);
> +		return LMAC_AF_ERR_INVALID_PARAM;
>  	}
>
>  	rc = rvu_npc_exact_add_table_entry(rvu, cgx_id, lmac_id, req->mac_addr,
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> index 5dd0591fed99..b2d777b5cb59 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
> @@ -340,6 +340,7 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
>  	req->kw_type = NPC_MCAM_KEY_X2;
>  	if (is_cn20k(pfvf->pdev) && kw_type == NPC_MCAM_KEY_X4) {
>  		req->kw_type = NPC_MCAM_KEY_X4;
> +		/* In X4 profile, x4_slots is equal to bank depth */
>  		ref &= (x4_slots - 1);
>  	}
>  	req->contig = false;
> --
> 2.43.0
>

> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
>> index 03bb485a1aca18..59c1a105faad5f 100644
>> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
>> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
>[ ... ]
>> @@ -1783,9 +1783,20 @@ int rvu_npc_exact_mac_addr_set(struct rvu *rvu, struct cgx_mac_addr_set_or_get *
>>
>>  	/* find mcam entry if exist */
>>  	rc = nix_get_nixlf(rvu, req->hdr.pcifunc, &nixlf, NULL);
>> -	if (!rc) {
>> -		mcam_idx = npc_get_nixlf_mcam_index(&rvu->hw->mcam, req->hdr.pcifunc,
>> -						    nixlf, NIXLF_UCAST_ENTRY);
>> +	if (rc) {
>> +		dev_err(rvu->dev,
>> +			"%s: Error to get nixlf pcifunc=%#x\n",
>> +			__func__, req->hdr.pcifunc);
>> +		return LMAC_AF_ERR_PERM_DENIED;
>> +	}
>> +
>> +	mcam_idx = npc_get_nixlf_mcam_index(&rvu->hw->mcam, req->hdr.pcifunc,
>> +					    nixlf, NIXLF_UCAST_ENTRY);
>Does returning LMAC_AF_ERR_PERM_DENIED here prevent configuring the MAC address
>when the interface is down?
>Previously, if nix_get_nixlf() failed (which happens when the interface is
>down and no NIXLF is attached), the code simply skipped fetching the MCAM
>index and left mcam_idx as -1, but continued successfully to register the MAC
>address via rvu_npc_exact_add_table_entry().

ACK. Will revert this change. There is no issue even if mcam_idx is -1 when added to list

^ permalink raw reply

* [PATCH net-next] net: enc28j60: use of_get_ethdev_address
From: Rosen Penev @ 2026-04-27  5:25 UTC (permalink / raw)
  To: netdev
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, open list

Since this is an OF only driver, of_ instead of device_ allows nvmem to
be used to specify the MAC address.

Add EPROBE_DEFER handling for NVMEM.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/net/ethernet/microchip/enc28j60.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c
index d6c9491537e4..2b9b4163e419 100644
--- a/drivers/net/ethernet/microchip/enc28j60.c
+++ b/drivers/net/ethernet/microchip/enc28j60.c
@@ -24,6 +24,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/spi/spi.h>
+#include <linux/of_net.h>
 
 #include "enc28j60_hw.h"
 
@@ -1554,7 +1555,10 @@ static int enc28j60_probe(struct spi_device *spi)
 		goto error_irq;
 	}
 
-	if (device_get_ethdev_address(&spi->dev, dev))
+	ret = of_get_ethdev_address(spi->dev.of_node, dev);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+	if (ret)
 		eth_hw_addr_random(dev);
 	enc28j60_set_hw_macaddr(dev);
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH] net: nixge: fix skb leak and missing bail on DMA mapping error
From: kernelcoredev @ 2026-04-27  6:00 UTC (permalink / raw)
  To: netdev; +Cc: andrew, andrew+netdev, davem, edumazet, kuba, pabeni,
	kernelcoredev

When dma_mapping_error() fires during RX buffer refill in nixge_recv(),
the skb allocated by netdev_alloc_skb_ip_align() is never freed, and
execution continues writing a corrupt physical address into the hardware
descriptor ring.

Fix by freeing the skb with dev_kfree_skb() and returning early.

Fixes: 492caffa8a1a ("net: ethernet: nixge: Add support for National Instruments XGE netdev")

Signed-off-by: Bentley Blacketer <sonionwhat@gmail.com>
---
 drivers/net/ethernet/ni/nixge.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 230d5ff99..b64e2f355 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -645,8 +645,9 @@ static int nixge_recv(struct net_device *ndev, int budget)
 					  NIXGE_MAX_JUMBO_FRAME_SIZE,
 					  DMA_FROM_DEVICE);
 		if (dma_mapping_error(ndev->dev.parent, cur_phys)) {
-			/* FIXME: bail out and clean up */
-			netdev_err(ndev, "Failed to map ...\n");
+			netdev_err(ndev, "Failed to map RX buffer\n");
+			dev_kfree_skb(new_skb);
+			return packets;
 		}
 		nixge_hw_dma_bd_set_phys(cur_p, cur_phys);
 		cur_p->cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE;
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH net v2] ipv6: Implement limits on extension header parsing
From: Ido Schimmel @ 2026-04-27  6:01 UTC (permalink / raw)
  To: Justin Iurman
  Cc: Daniel Borkmann, tom, kuba, edumazet, dsahern,
	willemdebruijn.kernel, pabeni, netdev
In-Reply-To: <dca69fa4-2284-4251-a569-8b26ab9fca07@gmail.com>

On Sun, Apr 26, 2026 at 05:47:38PM +0200, Justin Iurman wrote:
> Ido, Daniel,
> 
> As I said, my vote would definitely go to the solution without a sysctl for
> the very reason Ido mentioned. Note that an upper bound of 32 is kind of
> unrealistic, although super (SUPER!) safe. Sending more than 8 Extension
> Headers (assuming a different type for each) is not standard behavior and
> would make you non-RFC-compliant anyway. But I'm happy with 32, as long as
> we don't define a sysctl for that.

OK, so given that:

1. 32 is super safe and solves the issue.

2. We will likely have to maintain a sysctl forever.

3. A sysctl has the potential to be incompatible with the upcoming
"enforce_ext_hdr_order" sysctl.

I believe we can just go with the simplest solution of hard coding 32 as
a limit and drop the sysctl.

^ permalink raw reply

* [PATCH v4 net 0/10] octeontx2-af: npc: cn20k: MCAM fixes
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth

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
configuration, default-rule index handling and 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 files as optional so probe
does not fail when debugfs is unavailable; and fix defrag MCAM
allocation rollback so allocation errno is not overwritten by subbank
index resolution.

Patch 4 fixes npc_defrag_move_vdx_to_free(): when an MCAM line is moved
to a new physical index, copy entry2target_pffunc[] to the new slot,
clear the old slot, and update the matching mcam_rules entry so
software state matches hardware after defrag.

Patches 5 through 7 refine cn20k MCAM programming: clear entries by
logical index and resolved key width, fix bank and CFG sequencing in
npc_cn20k_config_mcam_entry(), and read action metadata from the correct
bank in npc_cn20k_read_mcam_entry().

Patches 8 through 10 complete default-rule lifecycle handling:
initialize all default-rule index outputs up front, tear down default
MCAM rules explicitly (coordinated with npc_mcam_free_all_entries()),
and reject USHRT_MAX sentinel indices in npc_get_nixlf_mcam_index() for
cn20k.

Ratheesh Kannoth (10):
  octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
  octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init
  octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
  octeontx2-af: npc: cn20k: Fix target map and rule index while defrag
  octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
  octeontx2-af: npc: cn20k: Fix bank value.
  octeontx2-af: npc: cn20k: Fix MCAM actions read
  octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front
  octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
  octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>

--
v3 -> v4:
  - Add patch fixing entry2target_pffunc[] and mcam_rules when defrag
    relocates an MCAM entry (npc_defrag_move_vdx_to_free()).
  - Drop the standalone default-entry x4 preference and x2-profile
    flow-install rejection patches from this series (10 patches total).
  https://lore.kernel.org/netdev/20260420023442.3295891-1-rkannoth@marvell.com/

v2 -> v3: Addresses simon, paolo comments.
	https://lore.kernel.org/netdev/20260420023442.3295891-1-rkannoth@marvell.com/

v1 -> v2: Addressed simon comments. Added more patch fixes to this series.
  Link: https://lore.kernel.org/netdev/20260418162013.GG280379@horms.kernel.org/

2.43.0

^ permalink raw reply

* [PATCH v4 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Suman Ghosh, Dan Carpenter
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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 | 109 ++++++++++++------
 .../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, 111 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..8d5cee833af7 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;
 }
@@ -1415,14 +1435,14 @@ 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);
 
 	rsp->entry = entry_rsp.entry;
-	return 0;
+	return rc;
 }
 
 static int rvu_npc_get_base_steer_rule_type(struct rvu *rvu, u16 pcifunc)
@@ -1480,9 +1500,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 +3627,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

* [PATCH v4 net 02/10] octeontx2-af: npc: cn20k: Drop debugfs_create_file() error checks in init
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Dan Carpenter, Simon Horman
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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().
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

* [PATCH v4 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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 c831585424df..020496c82806 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3588,9 +3588,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;
@@ -3709,8 +3710,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] = 0;
+
 		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

* [PATCH v4 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Dan Carpenter, Simon Horman
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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>
---
 drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c | 11 +++++++----
 1 file changed, 7 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 8d5cee833af7..c831585424df 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -2325,6 +2325,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;
 }
 
@@ -3502,7 +3503,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];
@@ -3516,6 +3517,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,
@@ -3533,13 +3535,14 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
 			__func__, cnt, alloc_cnt1, alloc_cnt2);
 		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

* [PATCH v4 net 05/10] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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 020496c82806..28ea9c508846 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

* [PATCH v4 net 07/10] octeontx2-af: npc: cn20k: Fix MCAM actions read
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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 ba43f71b92d1..369771c90256 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

* [PATCH v4 net 06/10] octeontx2-af: npc: cn20k: Fix bank value.
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

or 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 28ea9c508846..ba43f71b92d1 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

* [PATCH v4 net 08/10] octeontx2-af: npc: cn20k: Initialize default-rule index outputs up front
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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 369771c90256..3cc7a2339c78 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4002,6 +4002,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;
 
@@ -4017,7 +4024,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;
 		}
 
@@ -4037,7 +4043,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;
 		}
 
@@ -4057,7 +4062,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

* [PATCH v4 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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). Still disable the entry and tear down counter
mapping for every matching index.

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 3cc7a2339c78..15f468a86a46 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -4164,11 +4164,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)
@@ -4226,14 +4226,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

* [PATCH v4 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
From: Ratheesh Kannoth @ 2026-04-27  6:32 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
	Ratheesh Kannoth, Suman Ghosh
In-Reply-To: <20260427063213.3937451-1-rkannoth@marvell.com>

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   | 139 +++++++++++++++++-
 .../marvell/octeontx2/af/rvu_npc_fs.c         |  10 +-
 5 files changed, 157 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 15f468a86a46..dfc03ac2bbcc 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;
 
@@ -4156,7 +4168,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..9e6c79d6fadf 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,14 @@ 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);
+		dev_err(rvu->dev,
+			"%s: Error to get ucast entry for pcifunc=%#x\n",
+			__func__, pcifunc);
+		goto out;
+	}
+
 read_entry:
 	/* Read the mcam entry */
 	npc_read_mcam_entry(rvu, mcam, blkaddr, index, &rsp->entry, &intf,
@@ -3970,6 +4087,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

* RE: [RFC Patch net-next v1 5/9] r8169: add support for msix
From: Javen @ 2026-04-27  6:40 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <6345109a-3e87-476a-9abe-b8828e0fe9b6@gmail.com>

>On 20.04.2026 04:19, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> This patch add support for msix. But we still use MSI here. And we
>> force nvecs to 1. We will modify it in rss patch.
>
>This description is wrong. Also as of today r8169 supports MSIX.
>Reason likely is that you're copying code from vendor driver.
>
>>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>> ---
>>  drivers/net/ethernet/realtek/r8169_main.c | 162
>> ++++++++++++++++++++--
>>  1 file changed, 151 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>> b/drivers/net/ethernet/realtek/r8169_main.c
>> index 52e690eba644..7d493342ab4b 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -1764,26 +1764,40 @@ static u32 rtl_get_events(struct
>> rtl8169_private *tp)
>>
>>  static void rtl_ack_events(struct rtl8169_private *tp, u32 bits)  {
>> -     if (rtl_is_8125(tp))
>> +     if (rtl_is_8125(tp)) {
>>               RTL_W32(tp, IntrStatus_8125, bits);
>> -     else
>> +             if (tp->features & RTL_FEATURE_MSIX) {
>> +                     RTL_W32(tp, ISR_V2_8125, 0xffffffff);
>> +                     RTL_W32(tp, ISR_V4_L2_8125, 0xffffffff);
>> +             }
>> +     } else {
>>               RTL_W16(tp, IntrStatus, bits);
>> +     }
>>  }
>>
>>  static void rtl_irq_disable(struct rtl8169_private *tp)  {
>> -     if (rtl_is_8125(tp))
>> +     if (rtl_is_8125(tp)) {
>>               RTL_W32(tp, IntrMask_8125, 0);
>> -     else
>> +             if (tp->features & RTL_FEATURE_MSIX) {
>> +                     RTL_W32(tp, IMR_V2_CLEAR_REG_8125, 0xffffffff);
>> +                     RTL_W32(tp, IMR_V4_L2_CLEAR_REG_8125, 0xffffffff);
>> +             }
>> +     } else {
>>               RTL_W16(tp, IntrMask, 0);
>> +     }
>>  }
>>
>>  static void rtl_irq_enable(struct rtl8169_private *tp)  {
>> -     if (rtl_is_8125(tp))
>> -             RTL_W32(tp, IntrMask_8125, tp->irq_mask);
>> -     else
>> +     if (rtl_is_8125(tp)) {
>> +             if (tp->features & RTL_FEATURE_MSIX)
>> +                     RTL_W32(tp, IMR_V2_SET_REG_8125, tp->irq_mask);
>> +             else
>> +                     RTL_W32(tp, IntrMask_8125, tp->irq_mask);
>> +     } else {
>>               RTL_W16(tp, IntrMask, tp->irq_mask);
>> +     }
>>  }
>>
>>  static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) @@
>> -2894,6 +2908,10 @@ static void rtl_software_parameter_initialize(struct
>rtl8169_private *tp)
>>       tp->InitRxDescType = RX_DESC_RING_TYPE_DEAFULT;
>>       tp->HwCurrIsrVer = tp->HwSuppIsrVer;
>>
>> +     /* This just force nvecs, and will be remove in the following patch*/
>> +     tp->min_irq_nvecs = 1;
>> +     tp->max_irq_nvecs = 1;
>> +
>>       rtl_setup_mqs_reg(tp);
>>       rtl_set_ring_size(tp, NUM_RX_DESC, NUM_TX_DESC);  } @@ -5321,6
>> +5339,44 @@ static void rtl8169_free_irq(struct rtl8169_private *tp)
>>       }
>>  }
>>
>> +static void rtl8169_disable_hw_interrupt_msix(struct rtl8169_private
>> +*tp, int message_id) {
>> +     RTL_W32(tp, IMR_V2_CLEAR_REG_8125, BIT(message_id)); }
>> +
>> +static void rtl8169_clear_hw_isr(struct rtl8169_private *tp, int
>> +message_id) {
>> +     RTL_W32(tp, ISR_V2_8125, BIT(message_id)); }
>> +
>> +static void rtl8169_enable_hw_interrupt_msix(struct rtl8169_private
>> +*tp, int message_id) {
>> +     RTL_W32(tp, IMR_V2_SET_REG_8125, BIT(message_id)); }
>> +
>> +static irqreturn_t rtl8169_interrupt_msix(int irq, void
>> +*dev_instance) {
>> +     struct rtl8169_napi *napi = dev_instance;
>> +     struct rtl8169_private *tp = napi->priv;
>> +     int message_id = napi->index;
>> +
>> +     rtl8169_disable_hw_interrupt_msix(tp, message_id);
>> +
>> +     rtl8169_clear_hw_isr(tp, message_id);
>> +
>> +     if (message_id == MSIX_ID_V4_LINKCHG) {
>> +             phy_mac_interrupt(tp->phydev);
>> +             rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +             return IRQ_HANDLED;
>> +     }
>> +
>> +     tp->recheck_desc_ownbit = true;
>> +
>> +     napi_schedule(&napi->napi);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>>  static int rtl8169_request_irq(struct rtl8169_private *tp)  {
>>       struct net_device *dev = tp->dev; @@ -5331,10 +5387,14 @@ static
>> int rtl8169_request_irq(struct rtl8169_private *tp)
>>
>>       for (int i = 0; i < tp->irq_nvecs; i++) {
>>               irq = &tp->irq_tbl[i];
>> +             if (tp->features & RTL_FEATURE_MSIX && tp->HwCurrIsrVer > 1)
>> +                     irq->handler = rtl8169_interrupt_msix;
>> +             else
>> +                     irq->handler = rtl8169_interrupt;
>>
>>               napi = &tp->r8169napi[i];
>>               snprintf(irq->name, len, "%s-%d", dev->name, i);
>> -             rc = pci_request_irq(tp->pci_dev, i, rtl8169_interrupt, NULL, napi,
>irq->name);
>> +             rc = pci_request_irq(tp->pci_dev, i, irq->handler, NULL,
>> + napi, irq->name);
>>
>>               if (rc)
>>                       break;
>> @@ -5786,10 +5846,18 @@ static const struct net_device_ops
>> rtl_netdev_ops = {
>>
>>  static void rtl_set_irq_mask(struct rtl8169_private *tp)  {
>> -     tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
>> +     if (tp->features & RTL_FEATURE_MSIX) {
>> +             tp->irq_mask = ISRIMR_V6_LINKCHG;
>> +             for (int i = 0; i < tp->num_tx_rings; i++)
>> +                     tp->irq_mask |= ISRIMR_V6_TOK_Q0 << i;
>> +             for (int i = 0; i < tp->num_rx_rings; i++)
>> +                     tp->irq_mask |= ISRIMR_V6_ROK_Q0 << i;
>> +     } else {
>> +             tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
>>
>> -     if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
>> -             tp->irq_mask |= SYSErr | RxFIFOOver;
>> +             if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
>> +                     tp->irq_mask |= SYSErr | RxFIFOOver;
>> +     }
>>  }
>>
>>  static int rtl_alloc_irq(struct rtl8169_private *tp) @@ -5817,6
>> +5885,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
>>       if (nvecs < 0)
>>               nvecs = pci_alloc_irq_vectors(pdev, 1, 1,
>> PCI_IRQ_ALL_TYPES);
>>
>> +     tp->features &= ~(RTL_FEATURE_MSIX | RTL_FEATURE_MSI);
>> +
>> +     if (nvecs > 0) {
>> +             tp->irq_nvecs = nvecs;
>> +             tp->irq = pci_irq_vector(pdev, 0);
>> +             if (nvecs > 1)
>> +                     tp->features |= RTL_FEATURE_MSIX;
>> +             else if (pci_dev_msi_enabled(pdev))
>> +                     tp->features |= RTL_FEATURE_MSI;
>> +             return 0;
>
>Such feature flags, especially for MSI/MSIX, are ugly.
>Why don't you leave the interrupt type selection to PCI core?
>This needs at least an explanation.

I completely agree that it is misleading and ugly. 
The reason why I used tp-> features here is that I want to distinguish new interrupt mapping and old interrupt mapping. For RTL8127 with rss enabled, 8 rx queues refer to interrupt 0-7. For other chip with rss disabled, all tx/rx queues share the same interrupt. The specific differences are in function rtl8169_request_irq().
And I will rename the flag more appropriately to indicate the mapping method.

>
>> +     }
>> +
>>       tp->irq = pdev->irq;
>>       tp->irq_nvecs = 1;
>>
>> @@ -6087,6 +6167,52 @@ static bool rtl_aspm_is_safe(struct
>rtl8169_private *tp)
>>       return false;
>>  }
>>
>> +static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget)
>> +{
>> +     struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi,
>napi);
>> +     struct rtl8169_private *tp = r8169_napi->priv;
>> +     struct net_device *dev = tp->dev;
>> +     const int message_id = r8169_napi->index;
>> +     int work_done = 0;
>> +
>> +     if (message_id < tp->num_rx_rings)
>> +             work_done += rtl_rx(dev, tp, &tp->rx_ring[message_id],
>> + budget);
>> +
>> +     if (work_done < budget && napi_complete_done(napi, work_done))
>> +             rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +
>> +     return work_done;
>> +}
>> +
>> +static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget)
>> +{
>> +     struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi,
>napi);
>> +     struct rtl8169_private *tp = r8169_napi->priv;
>> +     struct net_device *dev = tp->dev;
>> +     unsigned int work_done = 0;
>> +     const int message_id = r8169_napi->index;
>> +     int tx_ring_idx = message_id - 8;
>> +
>> +     if (tx_ring_idx >= 0 && tx_ring_idx < tp->num_tx_rings)
>> +             work_done += rtl_tx(dev, tp, &tp->tx_ring[tx_ring_idx],
>> + budget);
>> +
>> +     if (work_done < budget && napi_complete_done(napi, work_done))
>> +             rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +
>> +     return work_done;
>> +}
>> +
>> +static int rtl8169_poll_msix_other(struct napi_struct *napi, int
>> +budget) {
>> +     struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi,
>napi);
>> +     struct rtl8169_private *tp = r8169_napi->priv;
>> +     const int message_id = r8169_napi->index;
>> +
>> +     napi_complete_done(napi, budget);
>> +     rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +
>> +     return 1;
>> +}
>>
>>  static void r8169_init_napi(struct rtl8169_private *tp)  { @@ -6095,6
>> +6221,20 @@ static void r8169_init_napi(struct rtl8169_private *tp)
>>               int (*poll)(struct napi_struct *napi, int budget);
>>
>>               poll = rtl8169_poll;
>> +             if (tp->features & RTL_FEATURE_MSIX) {
>> +                     switch (tp->HwCurrIsrVer) {
>> +                     case 6:
>> +                             if (i < R8127_MAX_RX_QUEUES)
>> +                                     poll = rtl8169_poll_msix_rx;
>> +                             else if (i > 7 && i < 16)
>> +                                     poll = rtl8169_poll_msix_tx;
>> +                             else
>> +                                     poll = rtl8169_poll_msix_other;
>> +                             break;
>> +                     default:
>> +                             break;
>> +                     }
>> +             }
>>               netif_napi_add(tp->dev, &r8169napi->napi, poll);
>>               r8169napi->priv = tp;
>>               r8169napi->index = i;


^ permalink raw reply

* RE: [RFC Patch net-next v1 1/9] r8169: add some register definitions
From: Javen @ 2026-04-27  6:41 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <546ff9b7-68b0-46ff-9db4-5fcde421f7df@gmail.com>

>On 20.04.2026 04:19, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> To support rss, this patch adds some macro definitions and register
>> definitions.
>>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>> ---
>>  drivers/net/ethernet/realtek/r8169_main.c | 75
>> +++++++++++++++++++++++
>>  1 file changed, 75 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>> b/drivers/net/ethernet/realtek/r8169_main.c
>> index 791277e750ba..0fbec27e4a0d 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -77,6 +77,23 @@
>>  #define R8169_RX_RING_BYTES  (NUM_RX_DESC * sizeof(struct RxDesc))
>>  #define R8169_TX_STOP_THRS   (MAX_SKB_FRAGS + 1)
>>  #define R8169_TX_START_THRS  (2 * R8169_TX_STOP_THRS)
>> +#define R8169_MAX_RX_QUEUES  8
>> +#define R8169_MAX_TX_QUEUES  1
>> +#define R8169_MAX_MSIX_VEC   32
>> +#define R8127_MAX_TX_QUEUES  1
>
>Then why multi tx queue support?
>
>> +#define R8127_MAX_RX_QUEUES  8
>> +#define R8127_MAX_IRQ                32
>> +#define R8127_MIN_IRQ                30
>
>This isn't self-explanatory. What do min and max refer to here?

The hardware actually reserves a 64-bit interrupt status space for the new mapping in RTL8127. Although I don't think it is reasonable, its hardware design.
- Vector 0-7 (from reg 0x0d04): Rx queues
- Vector 8-15 (from reg 0x0d04): Tx queues
- Vector 29 (from reg 0x0d06): Link Status Change (LSC)
As the Link Status Change interrupt is fixed at vector index 29, we are forced to request a minimum of 30 MSI-X vectors from the PCI core.

>
>> +#define RTL8127_RSS_KEY_SIZE 40
>> +#define RSS_CPU_NUM_OFFSET   16
>> +#define RSS_MASK_BITS_OFFSET 8
>> +#define RTL8127_MAX_INDIRECTION_TABLE_ENTRIES 128 #define
>> +RXS_8125B_RSS_UDP_V4 BIT(27) #define RXS_8125_RSS_IPV4_V4 BIT(28)
>> +#define RXS_8125_RSS_IPV6_V4 BIT(29) #define RXS_8125_RSS_TCP_V4
>> +BIT(30) #define RTL8127_RXS_RSS_L3_TYPE_MASK_V4
>(RXS_8125_RSS_IPV4_V4
>> +| RXS_8125_RSS_IPV6_V4) #define RTL8127_RXS_RSS_L4_TYPE_MASK_V4
>> +(RXS_8125_RSS_TCP_V4 | RXS_8125B_RSS_UDP_V4)
>>
>>  #define OCP_STD_PHY_BASE     0xa400
>>
>> @@ -435,6 +452,8 @@ enum rtl8125_registers {
>>  #define INT_CFG0_CLKREQEN            BIT(3)
>>       IntrMask_8125           = 0x38,
>>       IntrStatus_8125         = 0x3c,
>> +     IntrMask1_8125          = 0x800,
>> +     IntrStatus1_8125        = 0x802,
>>       INT_CFG1_8125           = 0x7a,
>>       LEDSEL2                 = 0x84,
>>       LEDSEL1                 = 0x86,
>> @@ -444,6 +463,36 @@ enum rtl8125_registers {
>>       RSS_CTRL_8125           = 0x4500,
>>       Q_NUM_CTRL_8125         = 0x4800,
>>       EEE_TXIDLE_TIMER_8125   = 0x6048,
>> +     TNPDS_Q1_LOW            = 0x2100,
>> +     RDSAR_Q1_LOW            = 0x4000,
>> +     IMR_V2_SET_REG_8125     = 0x0d0c,
>> +     IMR_V2_CLEAR_REG_8125   = 0x0d00,
>> +     IMR_V4_L2_CLEAR_REG_8125 = 0x0d10,
>> +     ISR_V2_8125             = 0x0d04,
>> +     ISR_V4_L2_8125          = 0x0d14,
>> +};
>> +
>> +enum rtl8127_msix_id {
>> +     MSIX_ID_V4_LINKCHG      = 29,
>> +};
>> +
>> +enum rtl8127_rss_register_content {
>> +     RSS_CTRL_TCP_IPV4_SUPP          = (1 << 0),
>> +     RSS_CTRL_IPV4_SUPP              = (1 << 1),
>> +     RSS_CTRL_TCP_IPV6_SUPP          = (1 << 2),
>> +     RSS_CTRL_IPV6_SUPP              = (1 << 3),
>> +     RSS_CTRL_IPV6_EXT_SUPP          = (1 << 4),
>> +     RSS_CTRL_TCP_IPV6_EXT_SUPP      = (1 << 5),
>> +     RSS_CTRL_UDP_IPV4_SUPP          = (1 << 11),
>> +     RSS_CTRL_UDP_IPV6_SUPP          = (1 << 12),
>> +     RSS_CTRL_UDP_IPV6_EXT_SUPP      = (1 << 13),
>> +     RSS_INDIRECTION_TBL_8125_V2     = 0x4700,
>> +     RSS_KEY_8125                    = 0x4600,
>> +};
>> +
>> +enum rtl8127_rss_flag {
>> +     RTL_8125_RSS_FLAG_HASH_UDP_IPV4  = (1 << 0),
>> +     RTL_8125_RSS_FLAG_HASH_UDP_IPV6  = (1 << 1),
>>  };
>>
>>  #define LEDSEL_MASK_8125     0x23f
>> @@ -474,6 +523,10 @@ enum rtl_register_content {
>>       RxRUNT  = (1 << 20),
>>       RxCRC   = (1 << 19),
>>
>> +     RxRES_RSS       = (1 << 22),
>> +     RxRUNT_RSS      = (1 << 21),
>> +     RxCRC_RSS       = (1 << 20),
>> +
>>       /* ChipCmdBits */
>>       StopReq         = 0x80,
>>       CmdReset        = 0x10,
>> @@ -576,6 +629,9 @@ enum rtl_register_content {
>>
>>       /* magic enable v2 */
>>       MagicPacket_v2  = (1 << 16),    /* Wake up when receives a Magic Packet
>*/
>> +     ISRIMR_V6_LINKCHG       = (1 << 29),
>> +     ISRIMR_V6_TOK_Q0        = (1 << 8),
>> +     ISRIMR_V6_ROK_Q0        = (1 << 0),
>>  };
>>
>>  enum rtl_desc_bit {
>> @@ -633,6 +689,11 @@ enum rtl_rx_desc_bit {
>>  #define RxProtoIP    (PID1 | PID0)
>>  #define RxProtoMask  RxProtoIP
>>
>> +     RxUDPT_v4       = (1 << 19),
>> +     RxTCPT_v4       = (1 << 18),
>> +     RxUDPF_v4       = (1 << 16), /* UDP/IP checksum failed */
>> +     RxTCPF_v4       = (1 << 15), /* TCP/IP checksum failed */
>> +
>>       IPFail          = (1 << 16), /* IP checksum failed */
>>       UDPFail         = (1 << 15), /* UDP/IP checksum failed */
>>       TCPFail         = (1 << 14), /* TCP/IP checksum failed */
>> @@ -659,6 +720,11 @@ struct RxDesc {
>>       __le64 addr;
>>  };
>>
>> +enum features {
>> +     RTL_FEATURE_MSI         = (1 << 1),
>> +     RTL_FEATURE_MSIX        = (1 << 2),
>> +};
>> +
>>  struct ring_info {
>>       struct sk_buff  *skb;
>>       u32             len;
>> @@ -728,6 +794,13 @@ enum rtl_dash_type {
>>       RTL_DASH_25_BP,
>>  };
>>
>> +enum rx_desc_ring_type {
>> +     RX_DESC_RING_TYPE_UNKNOWN = 0,
>> +     RX_DESC_RING_TYPE_DEAFULT,
>> +     RX_DESC_RING_TYPE_RSS,
>> +     RX_DESC_RING_TYPE_MAX
>> +};
>> +
>>  struct rtl8169_private {
>>       void __iomem *mmio_addr;        /* memory map physical address */
>>       struct pci_dev *pci_dev;
>> @@ -763,6 +836,8 @@ struct rtl8169_private {
>>       unsigned aspm_manageable:1;
>>       unsigned dash_enabled:1;
>>       bool sfp_mode:1;
>> +     bool rss_support:1;
>> +     bool rss_enable:1;
>>       dma_addr_t counters_phys_addr;
>>       struct rtl8169_counters *counters;
>>       struct rtl8169_tc_offsets tc_offset;


^ permalink raw reply

* RE: [RFC Patch net-next v1 1/9] r8169: add some register definitions
From: Javen @ 2026-04-27  6:42 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <59c06e34-2782-438e-bfd7-a8d475f34f95@gmail.com>

>On 20.04.2026 04:19, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> To support rss, this patch adds some macro definitions and register
>> definitions.
>>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>> ---
>>  drivers/net/ethernet/realtek/r8169_main.c | 75
>> +++++++++++++++++++++++
>>  1 file changed, 75 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>> b/drivers/net/ethernet/realtek/r8169_main.c
>> index 791277e750ba..0fbec27e4a0d 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -77,6 +77,23 @@
>>  #define R8169_RX_RING_BYTES  (NUM_RX_DESC * sizeof(struct RxDesc))
>>  #define R8169_TX_STOP_THRS   (MAX_SKB_FRAGS + 1)
>>  #define R8169_TX_START_THRS  (2 * R8169_TX_STOP_THRS)
>> +#define R8169_MAX_RX_QUEUES  8
>> +#define R8169_MAX_TX_QUEUES  1
>> +#define R8169_MAX_MSIX_VEC   32
>> +#define R8127_MAX_TX_QUEUES  1
>> +#define R8127_MAX_RX_QUEUES  8
>> +#define R8127_MAX_IRQ                32
>> +#define R8127_MIN_IRQ                30
>
>Why do you need at least 30 irq vecs?

The hardware actually reserves a 64-bit interrupt status space for the new mapping in RTL8127. 
- Vector 0-7 (from reg 0x0d04): Rx queues
- Vector 8-15 (from reg 0x0d04): Tx queues
- Vector 29 (from reg 0x0d06): Link Status Change (LSC)
As the Link Status Change interrupt is fixed at vector index 29, we are forced to request a minimum of 30 MSI-X vectors from the PCI core.

>
>> +#define RTL8127_RSS_KEY_SIZE 40
>> +#define RSS_CPU_NUM_OFFSET   16
>> +#define RSS_MASK_BITS_OFFSET 8
>> +#define RTL8127_MAX_INDIRECTION_TABLE_ENTRIES 128 #define
>> +RXS_8125B_RSS_UDP_V4 BIT(27)
>
>This register naming is unfortunate. What stands 8125B for, and what V4?
>Does V4 stand for a global version of the Realtek RSS IP block?
>Then the 8125B would be redundant.

The name here is directly ported from vendor driver, which may carry some confusing.
V4 actually refers to the type of rx descriptor, not the version of RSS IP block. Since RTL8127  exclusively uses this V4 descriptor format (and not the older v2/v3 formats), V4 is indeed unnecessary. 8125B is from older chips that share the same descriptor format, which is also unnecessary.

I will rename these macros more clearly.

>
>> +#define RXS_8125_RSS_IPV4_V4 BIT(28)
>> +#define RXS_8125_RSS_IPV6_V4 BIT(29)
>> +#define RXS_8125_RSS_TCP_V4 BIT(30)
>> +#define RTL8127_RXS_RSS_L3_TYPE_MASK_V4 (RXS_8125_RSS_IPV4_V4 |
>> +RXS_8125_RSS_IPV6_V4) #define RTL8127_RXS_RSS_L4_TYPE_MASK_V4
>> +(RXS_8125_RSS_TCP_V4 | RXS_8125B_RSS_UDP_V4)
>>
>>  #define OCP_STD_PHY_BASE     0xa400
>>
>> @@ -435,6 +452,8 @@ enum rtl8125_registers {
>>  #define INT_CFG0_CLKREQEN            BIT(3)
>>       IntrMask_8125           = 0x38,
>>       IntrStatus_8125         = 0x3c,
>> +     IntrMask1_8125          = 0x800,
>
>The driver has camel case for historic reasons. Camel case shouldn't be used
>for new constants. Checkpatch would have warned. There are several other
>places in the series where checkpatch would complain.
>Therefore, use checkpatch and fix all warnings/errors.
>
>> +     IntrStatus1_8125        = 0x802,
>>       INT_CFG1_8125           = 0x7a,
>>       LEDSEL2                 = 0x84,
>>       LEDSEL1                 = 0x86,
>> @@ -444,6 +463,36 @@ enum rtl8125_registers {
>>       RSS_CTRL_8125           = 0x4500,
>>       Q_NUM_CTRL_8125         = 0x4800,
>>       EEE_TXIDLE_TIMER_8125   = 0x6048,
>> +     TNPDS_Q1_LOW            = 0x2100,
>> +     RDSAR_Q1_LOW            = 0x4000,
>> +     IMR_V2_SET_REG_8125     = 0x0d0c,
>> +     IMR_V2_CLEAR_REG_8125   = 0x0d00,
>> +     IMR_V4_L2_CLEAR_REG_8125 = 0x0d10,
>> +     ISR_V2_8125             = 0x0d04,
>> +     ISR_V4_L2_8125          = 0x0d14,
>
>There are registers with at least V2, V4, V6.
>And like in a previous comment: Which benefit has the
>8125 here (at least if the versioning is global)?
>
>> +};
>> +
>> +enum rtl8127_msix_id {
>> +     MSIX_ID_V4_LINKCHG      = 29,
>> +};
>> +
>> +enum rtl8127_rss_register_content {
>> +     RSS_CTRL_TCP_IPV4_SUPP          = (1 << 0),
>
>BIT() macro can be used. And any specific reasons (except historic ones) why
>you define an enum that is never used instead of defines?

This is another remnant from the vendor driver.
I will drop the enum and convert these to standard #define using the BIT() macro.

>
>> +     RSS_CTRL_IPV4_SUPP              = (1 << 1),
>> +     RSS_CTRL_TCP_IPV6_SUPP          = (1 << 2),
>> +     RSS_CTRL_IPV6_SUPP              = (1 << 3),
>> +     RSS_CTRL_IPV6_EXT_SUPP          = (1 << 4),
>> +     RSS_CTRL_TCP_IPV6_EXT_SUPP      = (1 << 5),
>> +     RSS_CTRL_UDP_IPV4_SUPP          = (1 << 11),
>> +     RSS_CTRL_UDP_IPV6_SUPP          = (1 << 12),
>> +     RSS_CTRL_UDP_IPV6_EXT_SUPP      = (1 << 13),
>> +     RSS_INDIRECTION_TBL_8125_V2     = 0x4700,
>> +     RSS_KEY_8125                    = 0x4600,
>> +};
>> +
>> +enum rtl8127_rss_flag {
>> +     RTL_8125_RSS_FLAG_HASH_UDP_IPV4  = (1 << 0),
>> +     RTL_8125_RSS_FLAG_HASH_UDP_IPV6  = (1 << 1),
>>  };
>>
>>  #define LEDSEL_MASK_8125     0x23f
>> @@ -474,6 +523,10 @@ enum rtl_register_content {
>>       RxRUNT  = (1 << 20),
>>       RxCRC   = (1 << 19),
>>
>> +     RxRES_RSS       = (1 << 22),
>> +     RxRUNT_RSS      = (1 << 21),
>> +     RxCRC_RSS       = (1 << 20),
>> +
>>       /* ChipCmdBits */
>>       StopReq         = 0x80,
>>       CmdReset        = 0x10,
>> @@ -576,6 +629,9 @@ enum rtl_register_content {
>>
>>       /* magic enable v2 */
>>       MagicPacket_v2  = (1 << 16),    /* Wake up when receives a Magic Packet
>*/
>> +     ISRIMR_V6_LINKCHG       = (1 << 29),
>> +     ISRIMR_V6_TOK_Q0        = (1 << 8),
>> +     ISRIMR_V6_ROK_Q0        = (1 << 0),
>>  };
>>
>>  enum rtl_desc_bit {
>> @@ -633,6 +689,11 @@ enum rtl_rx_desc_bit {
>>  #define RxProtoIP    (PID1 | PID0)
>>  #define RxProtoMask  RxProtoIP
>>
>> +     RxUDPT_v4       = (1 << 19),
>> +     RxTCPT_v4       = (1 << 18),
>> +     RxUDPF_v4       = (1 << 16), /* UDP/IP checksum failed */
>> +     RxTCPF_v4       = (1 << 15), /* TCP/IP checksum failed */
>> +
>>       IPFail          = (1 << 16), /* IP checksum failed */
>>       UDPFail         = (1 << 15), /* UDP/IP checksum failed */
>>       TCPFail         = (1 << 14), /* TCP/IP checksum failed */
>> @@ -659,6 +720,11 @@ struct RxDesc {
>>       __le64 addr;
>>  };
>>
>> +enum features {
>> +     RTL_FEATURE_MSI         = (1 << 1),
>> +     RTL_FEATURE_MSIX        = (1 << 2),
>> +};
>> +
>>  struct ring_info {
>>       struct sk_buff  *skb;
>>       u32             len;
>> @@ -728,6 +794,13 @@ enum rtl_dash_type {
>>       RTL_DASH_25_BP,
>>  };
>>
>> +enum rx_desc_ring_type {
>> +     RX_DESC_RING_TYPE_UNKNOWN = 0,
>> +     RX_DESC_RING_TYPE_DEAFULT,
>> +     RX_DESC_RING_TYPE_RSS,
>> +     RX_DESC_RING_TYPE_MAX
>> +};
>> +
>>  struct rtl8169_private {
>>       void __iomem *mmio_addr;        /* memory map physical address */
>>       struct pci_dev *pci_dev;
>> @@ -763,6 +836,8 @@ struct rtl8169_private {
>>       unsigned aspm_manageable:1;
>>       unsigned dash_enabled:1;
>>       bool sfp_mode:1;
>> +     bool rss_support:1;
>> +     bool rss_enable:1;
>>       dma_addr_t counters_phys_addr;
>>       struct rtl8169_counters *counters;
>>       struct rtl8169_tc_offsets tc_offset;


^ permalink raw reply

* [PATCH net v2 1/2] batman-adv: reject new tp_meter sessions during teardown
From: Ren Wei @ 2026-04-27  6:43 UTC (permalink / raw)
  To: b.a.t.m.a.n, netdev
  Cc: marek.lindner, sw, antonio, sven, davem, edumazet, kuba, pabeni,
	horms, yuantan098, yifanwucs, tomapufckgml, bird, tr0jan,
	wangjiexun2025, n05ec

From: Jiexun Wang <wangjiexun2025@gmail.com>

Prevent tp_meter from starting new sender or receiver sessions after
mesh_state has left BATADV_MESH_ACTIVE.

Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Co-developed-by: Luxing Yin <tr0jan@lzu.edu.cn>
Signed-off-by: Luxing Yin <tr0jan@lzu.edu.cn>
Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
Changes in v2:
- Split the original fix into setup-side and teardown-side patches

 net/batman-adv/tp_meter.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 2e42f6b348c8..d9a80e459c2e 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -947,6 +947,13 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
 
 	/* look for an already existing test towards this node */
 	spin_lock_bh(&bat_priv->tp_list_lock);
+	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) {
+		spin_unlock_bh(&bat_priv->tp_list_lock);
+		batadv_tp_batctl_error_notify(BATADV_TP_REASON_DST_UNREACHABLE,
+					      dst, bat_priv, session_cookie);
+		return;
+	}
+
 	tp_vars = batadv_tp_list_find(bat_priv, dst);
 	if (tp_vars) {
 		spin_unlock_bh(&bat_priv->tp_list_lock);
@@ -1329,9 +1336,12 @@ static struct batadv_tp_vars *
 batadv_tp_init_recv(struct batadv_priv *bat_priv,
 		    const struct batadv_icmp_tp_packet *icmp)
 {
-	struct batadv_tp_vars *tp_vars;
+	struct batadv_tp_vars *tp_vars = NULL;
 
 	spin_lock_bh(&bat_priv->tp_list_lock);
+	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+		goto out_unlock;
+
 	tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
 					      icmp->session);
 	if (tp_vars)
@@ -1464,6 +1474,9 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
 {
 	struct batadv_icmp_tp_packet *icmp;
 
+	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+		goto out;
+
 	icmp = (struct batadv_icmp_tp_packet *)skb->data;
 
 	switch (icmp->subtype) {
@@ -1478,6 +1491,8 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
 			   "Received unknown TP Metric packet type %u\n",
 			   icmp->subtype);
 	}
+
+out:
 	consume_skb(skb);
 }
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH net v2 2/2] batman-adv: stop tp_meter sessions during mesh teardown
From: Ren Wei @ 2026-04-27  6:43 UTC (permalink / raw)
  To: b.a.t.m.a.n, netdev
  Cc: marek.lindner, sw, antonio, sven, davem, edumazet, kuba, pabeni,
	horms, yuantan098, yifanwucs, tomapufckgml, bird, tr0jan,
	wangjiexun2025, n05ec
In-Reply-To: <20260427064338.1526762-1-n05ec@lzu.edu.cn>

From: Jiexun Wang <wangjiexun2025@gmail.com>

TP meter sessions remain linked on bat_priv->tp_list after the netlink
request has already finished. When the mesh interface is removed,
batadv_mesh_free() currently tears down the mesh without first draining
these sessions.

A running sender thread or a late incoming tp_meter packet can then keep
processing against a mesh instance which is already shutting down.
Synchronize tp_meter with the mesh lifetime by stopping all active
sessions from batadv_mesh_free() and waiting for sender threads to exit
before teardown continues.

Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Co-developed-by: Luxing Yin <tr0jan@lzu.edu.cn>
Signed-off-by: Luxing Yin <tr0jan@lzu.edu.cn>
Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
Changes in v2:
- Split the original fix and keep only teardown-side session draining here
- Change batadv_tp_stop_all() loop indices to size_t
- Restore blank lines unintentionally removed in v1

 net/batman-adv/main.c     |  1 +
 net/batman-adv/tp_meter.c | 93 +++++++++++++++++++++++++++++++--------
 net/batman-adv/tp_meter.h |  1 +
 net/batman-adv/types.h    |  4 ++
 4 files changed, 81 insertions(+), 18 deletions(-)

diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 3a35aadd8b41..a4d33ee0fda5 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -249,6 +249,7 @@ void batadv_mesh_free(struct net_device *mesh_iface)
 	atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
 
 	batadv_purge_outstanding_packets(bat_priv, NULL);
+	batadv_tp_stop_all(bat_priv);
 
 	batadv_gw_node_free(bat_priv);
 
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index d9a80e459c2e..99dcf9431ad9 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -365,23 +365,38 @@ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
 }
 
 /**
- * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
- * @bat_priv: the bat priv with all the mesh interface information
- * @tp_vars: the private data of the current TP meter session to cleanup
+ * batadv_tp_list_detach() - remove tp session from mesh session list once
+ * @tp_vars: the private data of the current TP meter session
  */
-static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv,
-				     struct batadv_tp_vars *tp_vars)
+static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
 {
-	cancel_delayed_work(&tp_vars->finish_work);
+	bool detached = false;
 
 	spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
-	hlist_del_rcu(&tp_vars->list);
+	if (!hlist_unhashed(&tp_vars->list)) {
+		hlist_del_init_rcu(&tp_vars->list);
+		detached = true;
+	}
 	spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
 
+	if (!detached)
+		return;
+
+	atomic_dec(&tp_vars->bat_priv->tp_num);
+
 	/* drop list reference */
 	batadv_tp_vars_put(tp_vars);
+}
 
-	atomic_dec(&tp_vars->bat_priv->tp_num);
+/**
+ * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
+ * @tp_vars: the private data of the current TP meter session to cleanup
+ */
+static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
+{
+	cancel_delayed_work_sync(&tp_vars->finish_work);
+
+	batadv_tp_list_detach(tp_vars);
 
 	/* kill the timer and remove its reference */
 	timer_delete_sync(&tp_vars->timer);
@@ -886,7 +901,8 @@ static int batadv_tp_send(void *arg)
 	batadv_orig_node_put(orig_node);
 
 	batadv_tp_sender_end(bat_priv, tp_vars);
-	batadv_tp_sender_cleanup(bat_priv, tp_vars);
+	batadv_tp_sender_cleanup(tp_vars);
+	complete(&tp_vars->finished);
 
 	batadv_tp_vars_put(tp_vars);
 
@@ -918,7 +934,8 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
 		batadv_tp_vars_put(tp_vars);
 
 		/* cleanup of failed tp meter variables */
-		batadv_tp_sender_cleanup(bat_priv, tp_vars);
+		batadv_tp_sender_cleanup(tp_vars);
+		complete(&tp_vars->finished);
 		return;
 	}
 
@@ -1024,6 +1041,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
 	tp_vars->start_time = jiffies;
 
 	init_waitqueue_head(&tp_vars->more_bytes);
+	init_completion(&tp_vars->finished);
 
 	spin_lock_init(&tp_vars->unacked_lock);
 	INIT_LIST_HEAD(&tp_vars->unacked_list);
@@ -1126,14 +1144,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
 		   "Shutting down for inactivity (more than %dms) from %pM\n",
 		   BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
 
-	spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
-	hlist_del_rcu(&tp_vars->list);
-	spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
-
-	/* drop list reference */
-	batadv_tp_vars_put(tp_vars);
-
-	atomic_dec(&bat_priv->tp_num);
+	batadv_tp_list_detach(tp_vars);
 
 	spin_lock_bh(&tp_vars->unacked_lock);
 	list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
@@ -1496,6 +1507,52 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
 	consume_skb(skb);
 }
 
+/**
+ * batadv_tp_stop_all() - stop all currently running tp meter sessions
+ * @bat_priv: the bat priv with all the mesh interface information
+ */
+void batadv_tp_stop_all(struct batadv_priv *bat_priv)
+{
+	struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM];
+	struct batadv_tp_vars *tp_var;
+	size_t count = 0;
+	size_t i;
+
+	spin_lock_bh(&bat_priv->tp_list_lock);
+	hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) {
+		if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM))
+			break;
+
+		if (!kref_get_unless_zero(&tp_var->refcount))
+			continue;
+
+		tp_vars[count++] = tp_var;
+	}
+	spin_unlock_bh(&bat_priv->tp_list_lock);
+
+	for (i = 0; i < count; i++) {
+		tp_var = tp_vars[i];
+
+		switch (tp_var->role) {
+		case BATADV_TP_SENDER:
+			batadv_tp_sender_shutdown(tp_var,
+						  BATADV_TP_REASON_CANCEL);
+			wake_up(&tp_var->more_bytes);
+			wait_for_completion(&tp_var->finished);
+			break;
+		case BATADV_TP_RECEIVER:
+			batadv_tp_list_detach(tp_var);
+			if (timer_shutdown_sync(&tp_var->timer))
+				batadv_tp_vars_put(tp_var);
+			break;
+		}
+
+		batadv_tp_vars_put(tp_var);
+	}
+
+	synchronize_net();
+}
+
 /**
  * batadv_tp_meter_init() - initialize global tp_meter structures
  */
diff --git a/net/batman-adv/tp_meter.h b/net/batman-adv/tp_meter.h
index f0046d366eac..4e97cd10cd02 100644
--- a/net/batman-adv/tp_meter.h
+++ b/net/batman-adv/tp_meter.h
@@ -17,6 +17,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
 		     u32 test_length, u32 *cookie);
 void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
 		    u8 return_value);
+void batadv_tp_stop_all(struct batadv_priv *bat_priv);
 void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb);
 
 #endif /* _NET_BATMAN_ADV_TP_METER_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 8fc5fe0e9b05..daa06f421154 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -14,6 +14,7 @@
 #include <linux/average.h>
 #include <linux/bitops.h>
 #include <linux/compiler.h>
+#include <linux/completion.h>
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/kref.h>
@@ -1328,6 +1329,9 @@ struct batadv_tp_vars {
 	/** @finish_work: work item for the finishing procedure */
 	struct delayed_work finish_work;
 
+	/** @finished: completion signaled when a sender thread exits */
+	struct completion finished;
+
 	/** @test_length: test length in milliseconds */
 	u32 test_length;
 
-- 
2.34.1


^ permalink raw reply related

* RE: [RFC Patch net-next v1 0/9] r8169: add RSS support for RTL8127
From: Javen @ 2026-04-27  6:55 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <39a35232-479f-4390-9957-dbafc3f3c468@gmail.com>

>On 20.04.2026 04:19, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> This series patch adds RSS support for RTL8127 in the r8169 driver.
>>
>> Currently, without RSS support, a single CPU core handles all incoming
>> traffic. Under heavy loads, this single core becomes a bottleneck,
>> causing high softirq usage and leading to unstable and degraded network
>throughput.
>>
>> As a result, we add rss support for RTL8127. This RFC patch is just
>> for discussing. And we do some experiments on AMD platform. Below is
>> the result.
>>
>> Platform: AMD Ryzen Embedded R2514 with Radeon Graphics(4 Cores/8
>> Threads)
>
>An older embedded CPU (AFAICS from 2019, refreshed in 2022) in reality is
>unlikely to be used with sustained 10GBit traffic. It would be too weak to
>handle userspace apps making use of this high throughput. This hw edge case
>IMO isn't really an argument for adding 1.000 LoC, blowing up driver structs,
>and adding the complexity of dealing with a register layout changing every two
>chip versions.
>
>It's really a problem that Realtek frequently changes register layout and/or
>register semantics in a not backward-compatible way (and doesn't provide
>documentation), resulting in ugly versioned stuff like the following.
>
>IMR_V2_SET_REG_8125     = 0x0d0c,
>IMR_V2_CLEAR_REG_8125   = 0x0d00,
>IMR_V4_L2_CLEAR_REG_8125 = 0x0d10,
>ISR_V2_8125             = 0x0d04,
>ISR_V4_L2_8125          = 0x0d14,
>
>case RTL_GIGA_MAC_VER_80:
>        tp->HwSuppIsrVer = 6;
>default:
>        tp->HwSuppIsrVer = 1;
>
>This messy hw design makes it hard to develop maintainable drivers.
>This is underlined by the fact that Realtek has separate r8125, r8126,
>r8127 drivers, even though they share most of the code.
>
>> Arch: x86_64
>> Test command:
>>   Server: iperf3 -s
>>   Client: iperf3 -c 192.168.2.1 -P 20 -t 3600
>> Monitor: mpstat -P ALL 1
>>
>> Before this patch (Without RSS):
>>   Throughput: Unstable, fluctuating between 3.76 Gbits/sec and
>>   8.2 Gbits/sec.
>>   CPU Usage: A single CPU core is fully occupied with softirq reaching
>>   up to 96%.
>>
>> After this patch (With RSS enabled):
>>   Throughput: Stable at 9.42 Gbits/sec.
>>   CPU Usage: The traffic load is evenly distributed across multiple CPU
>>   cores. The maximum softirq on a single core dropped to 63%.
>>
>> Patch summary:
>>   Patch 1: Adds necessary macro and register definitions for RSS.
>>   Patch 2-4: Support NAPI and multi RX/TX queues.
>
>Driver supports NAPI already.
>
>>   Patch 5-6: Support MSI-X and enables it specifically for RTL8127.
>
>Also MSI-X is used already.
>
>>   Patch 7: Enables RSS for RTL8127.
>>   Patch 8-9: Adds ethtool support to configure the number of RX queues.
>>
>> Javen Xu (9):
>>   r8169: add some register definitions
>>   r8169: add napi and irq support
>>   r8169: add support for multi tx queues
>>   r8169: add support for multi rx queues
>>   r8169: add support for msix
>>   r8169: enable msix for RTL8127
>>   r8169: add support and enable rss
>>   r8169: move struct ethtool_ops
>>   r8169: add support for ethtool
>>
>>  drivers/net/ethernet/realtek/r8169_main.c | 1437
>> ++++++++++++++++++---
>>  1 file changed, 1238 insertions(+), 199 deletions(-)
>>
>
>Series includes functions like rtl8169_desc_quirk() indicating a need to work
>around hw errata. Would be helpful to add comments describing the hw
>erratum, best with a link to documentation.

This is a workaround for a hardware erratum on RTL8127.
The hardware cannot guarantee that the descriptor OwnBit is fully written to host memory before interrupt is triggered. If the CPU handles the interrupt very quickly, it might read stale descriptor data where DescOwn is still set, causing it to incorrectly skip the packet.
The recheck_desc_ownbit flag and the subsequent rtl8127_desc_quirk() are introduced to wait for the descriptor write to complete and check it one last time.


Thanks for your review and suggestions.

Summary of changes in upcoming v2:
- remove multi tx queue patch
- rename some macro definitions, such as RXS_8125B_RSS_UDP_V4
- convert enum rtl8127_rss_register_content to #define and use BIT() macro
- run checkpatch, explain the usage of dma_wmb() etc.
- fix typo errors (e.g., DEAFULT)

BRs,
Javen


^ permalink raw reply

* [PATCH net-next] net: Unify user-visible "Qualcomm" name
From: Krzysztof Kozlowski @ 2026-04-27  6:59 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, linux-arm-msm, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Loic Poulain, Sergey Ryazanov, Johannes Berg, netdev,
	linux-kernel
  Cc: Krzysztof Kozlowski

Various names for Qualcomm as a company are used in user-visible config
options: QCOM, Qualcomm and Qualcomm Technologies.  Switch to unified
"Qualcomm" so it will be easier for users to identify the options when
for example running menuconfig.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

---

And "Qualcomm Technologies" has even variations over the tree:
Qualcomm Technologies
Qualcomm Technologies Inc.
Qualcomm Technologies, Inc.

I am doing this tree wide:
https://lore.kernel.org/all/?q=f%3Akrzysztof+s%3A%22Unify+user-visible%22+s%3AQualcomm
---
 drivers/net/ethernet/qualcomm/Kconfig | 4 ++--
 drivers/net/wwan/Kconfig              | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index ba7efb108637..57e1984d20ee 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -48,7 +48,7 @@ config QCA7000_UART
 	  will be called qcauart.
 
 config QCOM_EMAC
-	tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support"
+	tristate "Qualcomm EMAC Gigabit Ethernet support"
 	depends on HAS_DMA && HAS_IOMEM
 	select CRC32
 	select PHYLIB
@@ -61,7 +61,7 @@ config QCOM_EMAC
 	  Precision Clock Synchronization Protocol.
 
 config QCOM_PPE
-	tristate "Qualcomm Technologies, Inc. PPE Ethernet support"
+	tristate "Qualcomm PPE Ethernet support"
 	depends on COMMON_CLK && HAS_IOMEM && OF
 	depends on ARCH_QCOM || COMPILE_TEST
 	select REGMAP_MMIO
diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
index 88df55d78d90..958dbc7347fa 100644
--- a/drivers/net/wwan/Kconfig
+++ b/drivers/net/wwan/Kconfig
@@ -38,7 +38,7 @@ config WWAN_HWSIM
 	  called wwan_hwsim.  If unsure, say N.
 
 config MHI_WWAN_CTRL
-	tristate "MHI WWAN control driver for QCOM-based PCIe modems"
+	tristate "MHI WWAN control driver for Qualcomm-based PCIe modems"
 	depends on MHI_BUS
 	help
 	  MHI WWAN CTRL allows QCOM-based PCIe modems to expose different modem
@@ -51,7 +51,7 @@ config MHI_WWAN_CTRL
 	  called mhi_wwan_ctrl.
 
 config MHI_WWAN_MBIM
-        tristate "MHI WWAN MBIM network driver for QCOM-based PCIe modems"
+        tristate "MHI WWAN MBIM network driver for Qualcomm-based PCIe modems"
         depends on MHI_BUS
         help
           MHI WWAN MBIM is a WWAN network driver for QCOM-based PCIe modems.
-- 
2.51.0


^ permalink raw reply related

* [PATCH] net: Unify user-visible "Qualcomm" name
From: Krzysztof Kozlowski @ 2026-04-27  7:01 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Loic Poulain, Sergey Ryazanov, Johannes Berg, netdev,
	linux-kernel
  Cc: =Bjorn Andersson, Konrad Dybcio, linux-arm-msm,
	Krzysztof Kozlowski

Various names for Qualcomm as a company are used in user-visible config
options: QCOM, Qualcomm and Qualcomm Technologies.  Switch to unified
"Qualcomm" so it will be easier for users to identify the options when
for example running menuconfig.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

---

And "Qualcomm Technologies" has even variations over the tree:
Qualcomm Technologies
Qualcomm Technologies Inc.
Qualcomm Technologies, Inc.

I am doing this tree wide:
https://lore.kernel.org/all/?q=f%3Akrzysztof+s%3A%22Unify+user-visible%22+s%3AQualcomm
---
 drivers/net/ethernet/qualcomm/Kconfig | 4 ++--
 drivers/net/wwan/Kconfig              | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index ba7efb108637..57e1984d20ee 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -48,7 +48,7 @@ config QCA7000_UART
 	  will be called qcauart.
 
 config QCOM_EMAC
-	tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support"
+	tristate "Qualcomm EMAC Gigabit Ethernet support"
 	depends on HAS_DMA && HAS_IOMEM
 	select CRC32
 	select PHYLIB
@@ -61,7 +61,7 @@ config QCOM_EMAC
 	  Precision Clock Synchronization Protocol.
 
 config QCOM_PPE
-	tristate "Qualcomm Technologies, Inc. PPE Ethernet support"
+	tristate "Qualcomm PPE Ethernet support"
 	depends on COMMON_CLK && HAS_IOMEM && OF
 	depends on ARCH_QCOM || COMPILE_TEST
 	select REGMAP_MMIO
diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
index 88df55d78d90..958dbc7347fa 100644
--- a/drivers/net/wwan/Kconfig
+++ b/drivers/net/wwan/Kconfig
@@ -38,7 +38,7 @@ config WWAN_HWSIM
 	  called wwan_hwsim.  If unsure, say N.
 
 config MHI_WWAN_CTRL
-	tristate "MHI WWAN control driver for QCOM-based PCIe modems"
+	tristate "MHI WWAN control driver for Qualcomm-based PCIe modems"
 	depends on MHI_BUS
 	help
 	  MHI WWAN CTRL allows QCOM-based PCIe modems to expose different modem
@@ -51,7 +51,7 @@ config MHI_WWAN_CTRL
 	  called mhi_wwan_ctrl.
 
 config MHI_WWAN_MBIM
-        tristate "MHI WWAN MBIM network driver for QCOM-based PCIe modems"
+        tristate "MHI WWAN MBIM network driver for Qualcomm-based PCIe modems"
         depends on MHI_BUS
         help
           MHI WWAN MBIM is a WWAN network driver for QCOM-based PCIe modems.
-- 
2.51.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox