Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next v2 2/3] gve: make nic clock reads thread safe
From: Jordan Rhee @ 2026-03-30  4:06 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: hramamurthy, netdev, joshwash, andrew+netdev, davem, edumazet,
	pabeni, richardcochran, willemb, nktgrg, jfraker, ziweixiao,
	maolson, thostet, jefrogers, alok.a.tiwari, yyd, linux-kernel,
	namangulati
In-Reply-To: <20260329211958.2875749-1-kuba@kernel.org>

On Sun, Mar 29, 2026 at 2:20 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> gve: make nic clock reads thread safe
>
> This commit adds a mutex to protect the shared DMA buffer used for receiving
> NIC timestamp reports. The lock is needed to synchronize the periodic worker
> and the upcoming gettimex64 ioctl.
>
> > diff --git a/drivers/net/ethernet/google/gve/gve_ptp.c b/drivers/net/ethernet/google/gve/gve_ptp.c
> > index 06b1cf4a5efc..140b8fbce4f4 100644
> > --- a/drivers/net/ethernet/google/gve/gve_ptp.c
> > +++ b/drivers/net/ethernet/google/gve/gve_ptp.c
>
> [ ... ]
>
> > @@ -109,6 +114,7 @@ static void gve_ptp_release(struct gve_priv *priv)
> >
> >  int gve_init_clock(struct gve_priv *priv)
> >  {
> > +     u64 nic_raw;
> >       int err;
> >
> >       err = gve_ptp_init(priv);
>
> [ ... ]
>
> > @@ -125,17 +131,20 @@ int gve_init_clock(struct gve_priv *priv)
> >               err = -ENOMEM;
> >               goto release_ptp;
> >       }
> > -     err = gve_clock_nic_ts_read(priv);
> > +     mutex_init(&priv->nic_ts_read_lock);
> > +     err = gve_clock_nic_ts_read(priv, &nic_raw);
>
> Could this lead to a race condition with userspace?
>
> If gve_ptp_init() registers the PTP clock via ptp_clock_register(), the
> device is exposed to userspace immediately. If a userspace process opens the
> device and calls the gettimex64 ioctl before the mutex and DMA buffer are
> initialized here, it could cause a NULL pointer dereference or operate on an
> uninitialized mutex.

Ack, will fix.

>
> >       if (err) {
> >               dev_err(&priv->pdev->dev, "failed to read NIC clock %d\n", err);
> >               goto release_nic_ts_report;
> >       }
> > +     WRITE_ONCE(priv->last_sync_nic_counter, nic_raw);
> >       ptp_schedule_worker(priv->ptp->clock,
> >                           msecs_to_jiffies(GVE_NIC_TS_SYNC_INTERVAL_MS));
> >
> >       return 0;
> >
> >  release_nic_ts_report:
> > +     mutex_destroy(&priv->nic_ts_read_lock);
> >       dma_free_coherent(&priv->pdev->dev,
> >                         sizeof(struct gve_nic_ts_report),
> >                         priv->nic_ts_report, priv->nic_ts_report_bus);
>
> Is it safe to destroy the mutex and free the DMA buffer before calling
> gve_ptp_release() here?
>
> If the PTP clock is already registered and exposed to userspace by
> gve_ptp_init(), this error path frees resources while the clock is still
> active. A concurrent userspace ioctl could access the destroyed mutex or
> freed buffer before gve_ptp_release() unregisters the clock.
>
> Should all resource allocation and initialization strictly precede
> ptp_clock_register(), and the error path unregister the clock before tearing
> down the resources?

Ack, will fix.

> --
> pw-bot: cr

^ permalink raw reply

* Re: [PATCH v2] selftests/bpf: Reject malformed IPv4/IPv6 skb test input
From: sun jian @ 2026-03-30  4:23 UTC (permalink / raw)
  To: ast, daniel, andrii
  Cc: martin.lau, eddyz87, song, yonghong.song, john.fastabend, kpsingh,
	sdf, haoluo, jolsa, davem, edumazet, kuba, pabeni, horms, bpf,
	netdev, linux-kernel, syzbot+619b9ef527f510a57cfc
In-Reply-To: <20260329161751.1914272-1-sun.jian.kdev@gmail.com>

Hi,

Syzbot has tested v2 and the reproducer did not trigger the issue.
Tested-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com

On Mon, Mar 30, 2026 at 12:18 AM Sun Jian <sun.jian.kdev@gmail.com> wrote:
>
> bpf_prog_test_run_skb() derives skb->protocol from the Ethernet header
> through eth_type_trans(), but it does not verify that the provided
> linear input is long enough to contain the corresponding L3 base header.

^ permalink raw reply

* Re: [PATCH net-next v2 3/3] gve: implement PTP gettimex64
From: Jordan Rhee @ 2026-03-30  4:31 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: hramamurthy, netdev, joshwash, andrew+netdev, davem, edumazet,
	pabeni, richardcochran, willemb, nktgrg, jfraker, ziweixiao,
	maolson, thostet, jefrogers, alok.a.tiwari, yyd, linux-kernel,
	namangulati
In-Reply-To: <20260329212002.2875815-1-kuba@kernel.org>

On Sun, Mar 29, 2026 at 2:20 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> Subject: gve: implement PTP gettimex64
>
> This commit implements the PTP gettimex64 function to enable chrony and
> phc2sys to synchronize the system clock to the NIC clock. It reads the
> NIC timestamp along with pre and post system cycle counters to minimize
> the uncertainty window.
>
> > diff --git a/drivers/net/ethernet/google/gve/gve_ptp.c b/drivers/net/ethernet/google/gve/gve_ptp.c
> > index 140b8fbce4f4..bea794541f30 100644
> > --- a/drivers/net/ethernet/google/gve/gve_ptp.c
> > +++ b/drivers/net/ethernet/google/gve/gve_ptp.c
> > @@ -10,28 +10,203 @@
>
> [ ... ]
>
> > +static int gve_adminq_read_timestamp(struct gve_priv *priv,
> > +                                  cycles_t *pre_cycles,
> > +                                  cycles_t *post_cycles)
> > +{
> > +     unsigned long delay_us = 1000;
> > +     int retry_count = 0;
> > +     int err;
> > +
> > +     lockdep_assert_held(&priv->nic_ts_read_lock);
> > +
> > +     do {
> > +             *pre_cycles = get_cycles();
> > +             err = gve_adminq_report_nic_ts(priv, priv->nic_ts_report_bus);
> > +
> > +             /* Ensure cycle counter is sampled after AdminQ cmd returns */
> > +             rmb();
> > +             *post_cycles = get_cycles();
>
> Are execution barriers needed around get_cycles() here? rmb() orders
> memory accesses, but the CPU might still speculatively execute the cycle
> counter reads out of order with respect to the AdminQ commands.
>
> Could this speculative reordering cause the strict bounds validation in
> gve_ptp_gettimex64() to fail spuriously?

I will add mb() barriers to be totally safe.

> [ ... ]
>
> >  static int gve_ptp_gettimex64(struct ptp_clock_info *info,
> >                             struct timespec64 *ts,
> >                             struct ptp_system_timestamp *sts)
> >  {
> > -     return -EOPNOTSUPP;
> > +     struct gve_ptp *ptp = container_of(info, struct gve_ptp, info);
> > +     struct gve_sysclock_sample sysclock = {0};
> > +     struct gve_priv *priv = ptp->priv;
> > +     struct system_time_snapshot snap;
> > +     u64 nic_ts;
> > +     int err;
> > +
> > +     /* Take system clock snapshot before sampling cycle counters */
> > +     if (sts)
> > +             ktime_get_snapshot(&snap);
> > +
> > +     err = gve_clock_nic_ts_read(priv, &nic_ts, &sysclock);
>
> Could the system time snapshot become stale here?
>
> If priv->nic_ts_read_lock is contended, or if gve_adminq_read_timestamp()
> retries and sleeps, the snapshot might be taken significantly before the
> actual hardware read.
>
> Would it be more accurate to take the snapshot immediately before reading the
> hardware, inside the mutex?

Ack, will fix.

>
> > +     if (err)
> > +             return err;
> > +
> > +     if (sts) {
> > +             /* Reject samples with out of order system clock values */
> > +             if (!(sysclock.host_pre_cycles <= sysclock.nic_pre_cycles &&
> > +                   sysclock.nic_pre_cycles  <= sysclock.nic_post_cycles &&
> > +                   sysclock.nic_post_cycles <= sysclock.host_post_cycles)) {
> > +                     dev_err_ratelimited(&priv->pdev->dev,
> > +                                         "AdminQ system clock cycle counts out of order. Expecting %llu <= %llu <= %llu <= %llu\n",
> > +                                         (u64)sysclock.host_pre_cycles,
> > +                                         sysclock.nic_pre_cycles,
> > +                                         sysclock.nic_post_cycles,
> > +                                         (u64)sysclock.host_post_cycles);
> > +                     return -EBADMSG;
>
> How does this behave on architectures where get_cycles() is not implemented
> and returns 0, or with older firmware that leaves nic_pre_cycles and
> nic_post_cycles as 0?

Firmware is not allowed to return 0. 0 should trigger the check.

> It looks like the bounds check would unconditionally fail and return -EBADMSG.
> Since userspace tools like chrony usually expect -EOPNOTSUPP for unsupported
> extended ioctls to fall back to basic PTP ioctls, will returning -EBADMSG
> cause a hard failure for clock synchronization?

Will fix. GVE is only supported on x86_64 and arm64, and will fail on
other architectures with -EOPNOTSUPP due to the check in
gve_cycles_to_clock_fn(). However, if an architecture returns
get_cycles() as 0, it will fail here first with -EBADMSG. I will add
an explicit check for x86 || arm64 earlier in this function.

>
> [ ... ]
>
> > @@ -132,7 +307,7 @@ int gve_init_clock(struct gve_priv *priv)
> >               goto release_ptp;
> >       }
> >       mutex_init(&priv->nic_ts_read_lock);
> > -     err = gve_clock_nic_ts_read(priv, &nic_raw);
> > +     err = gve_clock_nic_ts_read(priv, &nic_raw, NULL);
> >       if (err) {
> >               dev_err(&priv->pdev->dev, "failed to read NIC clock %d\n", err);
> >               goto release_nic_ts_report;
>
> Is there a race condition exposing the PTP device to userspace before its
> resources are fully initialized?
>
> Looking at gve_init_clock(), gve_ptp_init() is called before allocating
> nic_ts_report and initializing nic_ts_read_lock:
>
>     err = gve_ptp_init(priv);
>     if (err)
>         return err;
>
>     priv->nic_ts_report = dma_alloc_coherent(...);
>     ...
>     mutex_init(&priv->nic_ts_read_lock);
>
> If a concurrent userspace process immediately invokes the
> PTP_SYS_OFFSET_EXTENDED ioctl after gve_ptp_init() registers the /dev/ptpX
> device, could it call gve_ptp_gettimex64() and attempt to lock the
> uninitialized mutex or dereference the NULL nic_ts_report pointer?
>
> Additionally, in the error path for gve_init_clock():
>
>     release_nic_ts_report:
>         mutex_destroy(&priv->nic_ts_read_lock);
>         dma_free_coherent(...);
>         priv->nic_ts_report = NULL;
>     release_ptp:
>         gve_ptp_release(priv);
>
> Could destroying the mutex and freeing the memory before gve_ptp_release()
> create a use-after-free window if an ioctl is currently running?

Will be fixed in the previous patch in the series.

^ permalink raw reply

* Re: [PATCH v8 net-next 6/6] octeontx2-af: npc: Support for custom KPU profile from filesystem
From: Ratheesh Kannoth @ 2026-03-30  4:59 UTC (permalink / raw)
  To: Simon Horman
  Cc: netdev, linux-kernel, sgoutham, davem, edumazet, kuba, pabeni,
	donald.hunter, jiri, chuck.lever, matttbe, cjubran, shshitrit,
	dtatulea, tariqt
In-Reply-To: <20260327133036.GE567789@horms.kernel.org>

On 2026-03-27 at 19:00:36, Simon Horman (horms@kernel.org) wrote:
> > +void npc_load_kpu_profile(struct rvu *rvu)
> > +{
> > +	/* Order of preceedence for load loading NPC profile (high to low)
> > +	 * Firmware binary in filesystem.
> > +	 * Firmware database method.
> > +	 * Default KPU profile.
> > +	 */
> >  	npc_prepare_default_kpu(rvu, profile);
>
> Is this call to npc_prepare_default_kpu() still needed?
Yes. If both filesystem and FW database method fails, default KPU profile is loaded.
>
> ...

^ permalink raw reply

* Re: [PATCH bpf-next 1/3] bpf: Disallow freplace on XDP with mismatched xdp_has_frags values
From: Leon Hwang @ 2026-03-30  5:20 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: bpf, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan, David S . Miller, Jesper Dangaard Brouer,
	Toke Hoiland-Jorgensen, Lorenzo Bianconi, linux-kernel,
	linux-kselftest, netdev, kernel-patches-bot
In-Reply-To: <20260327171220.6d10d710@kernel.org>

On 28/3/26 08:12, Jakub Kicinski wrote:
> On Fri, 27 Mar 2026 14:42:19 +0800 Leon Hwang wrote:
>>> It may be worth adding a selftest to
>>> tools/testing/selftests/drivers/net/xdp.py
>>> which sets MTU to 9k, tries to attach a non-frag-capable prog
>>> if that fails attaches a frag-capable prog and then checks if
>>> replacing the capable prog with non-capable fails.
>>> Drivers may be buggy in this regard.  
>>
>> Do you mean adding these two tests to xdp.py?
>>
>> 1. Verify the failure of attaching non-frag-capable prog to mtu=9k
>>    driver.
>> 2. Verify the failure of updating frag-capable prog with non-frag-
>>    capable prog via libbpf.c::bpf_link__update_program().
> 
> Not directly via libbpf just ip -f link, it uses libbpf internally
> but testing with  ip link is simpler. Also - there are already XDP
> progs which return XDP_PASS in frag-capable and non-capable mode,
> so just use those.
> 

Yep, I see these XDP progs in xdp_dummy.bpf.c.

I think the option of ip cmd to update XDP prog is -force.

# ip l set dev eth0 mtu 9000
# ip l set dev eth0 xdpdrv obj xdp_dummy.bpf.o sec xdp.frags
# ip l
6: eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 9000 xdp qdisc mq
master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether 3a:39:5f:35:17:6c brd ff:ff:ff:ff:ff:ff permaddr
e0:9d:73:c6:7a:d6
    prog/xdp id 72 name xdp_dummy_prog_ tag 614b434cd8324ecc jited
# ip -force l set dev eth0 xdpdrv obj xdp_dummy.bpf.o sec xdp.frags
# ip l
6: eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 9000 xdp qdisc mq
master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether 3a:39:5f:35:17:6c brd ff:ff:ff:ff:ff:ff permaddr
e0:9d:73:c6:7a:d6
    prog/xdp id 76 name xdp_dummy_prog_ tag 614b434cd8324ecc jited
# ip l set dev eth0 mtu 1500 xdpdrv off

I'd like to post an RFC to net-next later.

Thanks,
Leon


^ permalink raw reply

* [PATCH v9 net-next 1/6] octeontx2-af: npc: cn20k: debugfs enhancements
From: Ratheesh Kannoth @ 2026-03-30  5:31 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260330053105.2722453-1-rkannoth@marvell.com>

Improve MCAM visibility and field debugging for CN20K NPC.

- Extend "mcam_layout" to show enabled (+) or disabled state per entry
  so status can be verified without parsing the full "mcam_entry" dump.
- Add "dstats" debugfs entry: reports recently hit MCAM indices with
  packet counts; stats are cleared on read so each read shows deltas.
- Add "mismatch" debugfs entry: lists MCAM entries that are enabled
  but not explicitly allocated, helping diagnose allocation/field issues.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 .../marvell/octeontx2/af/cn20k/debugfs.c      | 126 +++++++++++++++++-
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c |  16 ++-
 .../ethernet/marvell/octeontx2/af/cn20k/npc.h |   7 +
 3 files changed, 135 insertions(+), 14 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..e8f85ed5ead7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
@@ -13,6 +13,7 @@
 #include "struct.h"
 #include "rvu.h"
 #include "debugfs.h"
+#include "cn20k/reg.h"
 #include "cn20k/npc.h"
 
 static int npc_mcam_layout_show(struct seq_file *s, void *unused)
@@ -58,7 +59,8 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
 						 "v:%u", vidx0);
 				}
 
-				seq_printf(s, "\t%u(%#x) %s\n", idx0, pf1,
+				seq_printf(s, "\t%u(%#x)%c %s\n", idx0, pf1,
+					   test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
 					   map ? buf0 : " ");
 			}
 			goto next;
@@ -101,9 +103,13 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
 						 vidx1);
 				}
 
-				seq_printf(s, "%05u(%#x) %s\t\t%05u(%#x) %s\n",
-					   idx1, pf2, v1 ? buf1 : "       ",
-					   idx0, pf1, v0 ? buf0 : "       ");
+				seq_printf(s, "%05u(%#x)%c %s\t\t%05u(%#x)%c %s\n",
+					   idx1, pf2,
+					   test_bit(idx1, npc_priv->en_map) ? '+' : ' ',
+					   v1 ? buf1 : "       ",
+					   idx0, pf1,
+					   test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
+					   v0 ? buf0 : "       ");
 
 				continue;
 			}
@@ -120,8 +126,9 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
 						 vidx0);
 				}
 
-				seq_printf(s, "\t\t   \t\t%05u(%#x) %s\n", idx0,
-					   pf1, map ? buf0 : " ");
+				seq_printf(s, "\t\t   \t\t%05u(%#x)%c %s\n", idx0, pf1,
+					   test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
+					   map ? buf0 : " ");
 				continue;
 			}
 
@@ -134,7 +141,8 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
 				snprintf(buf1, sizeof(buf1), "v:%05u", vidx1);
 			}
 
-			seq_printf(s, "%05u(%#x) %s\n", idx1, pf1,
+			seq_printf(s, "%05u(%#x)%c %s\n", idx1, pf1,
+				   test_bit(idx1, npc_priv->en_map) ? '+' : ' ',
 				   map ? buf1 : " ");
 		}
 next:
@@ -145,6 +153,100 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
 
 DEFINE_SHOW_ATTRIBUTE(npc_mcam_layout);
 
+static u64 dstats[MAX_NUM_BANKS][MAX_SUBBANK_DEPTH * MAX_NUM_SUB_BANKS] = {};
+static int npc_mcam_dstats_show(struct seq_file *s, void *unused)
+{
+	struct npc_priv_t *npc_priv;
+	int blkaddr, pf, mcam_idx;
+	u64 stats, delta;
+	struct rvu *rvu;
+	u8 key_type;
+	void *map;
+
+	npc_priv = npc_priv_get();
+	rvu = s->private;
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+	if (blkaddr < 0)
+		return 0;
+
+	seq_puts(s, "idx\tpfunc\tstats\n");
+	for (int bank = npc_priv->num_banks - 1; bank >= 0; bank--) {
+		for (int idx = npc_priv->bank_depth - 1; idx >= 0; idx--) {
+			mcam_idx = bank * npc_priv->bank_depth + idx;
+
+			npc_mcam_idx_2_key_type(rvu, mcam_idx, &key_type);
+			if (key_type == NPC_MCAM_KEY_X4 && bank != 0)
+				continue;
+
+			if (!test_bit(mcam_idx, npc_priv->en_map))
+				continue;
+
+			stats = rvu_read64(rvu, blkaddr,
+					   NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(idx, bank));
+			if (!stats)
+				continue;
+			if (stats == dstats[bank][idx])
+				continue;
+
+			if (stats < dstats[bank][idx])
+				dstats[bank][idx] = 0;
+
+			pf = 0xFFFF;
+			map = xa_load(&npc_priv->xa_idx2pf_map, mcam_idx);
+			if (map)
+				pf = xa_to_value(map);
+
+			if (stats > dstats[bank][idx])
+				delta = stats - dstats[bank][idx];
+			else
+				delta = stats;
+
+			seq_printf(s, "%u\t%#04x\t%llu\n",
+				   mcam_idx, pf, delta);
+			dstats[bank][idx] = stats;
+		}
+	}
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(npc_mcam_dstats);
+
+static int npc_mcam_mismatch_show(struct seq_file *s, void *unused)
+{
+	struct npc_priv_t *npc_priv;
+	struct npc_subbank *sb;
+	int mcam_idx, sb_off;
+	struct rvu *rvu;
+	void *map;
+	int rc;
+
+	npc_priv = npc_priv_get();
+	rvu = s->private;
+
+	seq_puts(s, "index\tsb idx\tkw type\n");
+	for (int bank = npc_priv->num_banks - 1; bank >= 0; bank--) {
+		for (int idx = npc_priv->bank_depth - 1; idx >= 0; idx--) {
+			mcam_idx = bank * npc_priv->bank_depth + idx;
+
+			if (!test_bit(mcam_idx, npc_priv->en_map))
+				continue;
+
+			map = xa_load(&npc_priv->xa_idx2pf_map, mcam_idx);
+			if (map)
+				continue;
+
+			rc = npc_mcam_idx_2_subbank_idx(rvu, mcam_idx,
+							&sb, &sb_off);
+			if (rc)
+				continue;
+
+			seq_printf(s, "%u\t%d\t%u\n", mcam_idx, sb->idx,
+				   sb->key_type);
+		}
+	}
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(npc_mcam_mismatch);
+
 static int npc_mcam_default_show(struct seq_file *s, void *unused)
 {
 	struct npc_priv_t *npc_priv;
@@ -257,6 +359,16 @@ int npc_cn20k_debugfs_init(struct rvu *rvu)
 	if (!npc_dentry)
 		return -EFAULT;
 
+	npc_dentry = debugfs_create_file("dstats", 0444, rvu->rvu_dbg.npc, rvu,
+					 &npc_mcam_dstats_fops);
+	if (!npc_dentry)
+		return -EFAULT;
+
+	npc_dentry = debugfs_create_file("mismatch", 0444, rvu->rvu_dbg.npc, rvu,
+					 &npc_mcam_mismatch_fops);
+	if (!npc_dentry)
+		return -EFAULT;
+
 	npc_dentry = debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
 					 rvu, &npc_mcam_default_fops);
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7291fdb89b03..e854b85ced9e 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;
 
+	enable ? set_bit(index, npc_priv.en_map) :
+		clear_bit(index, npc_priv.en_map);
+
 	npc_mcam_idx_2_key_type(rvu, index, &kw_type);
 	if (kw_type == NPC_MCAM_KEY_X2) {
 		cfg = rvu_read64(rvu, blkaddr,
@@ -1016,14 +1019,12 @@ static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
 
 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)
+			    int bank, u8 kw_type, 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,
@@ -1119,7 +1120,8 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
 	/* TODO: */
 	/* PF installing VF rule */
 	npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
-				    kw_type, enable, hw_prio);
+				    kw_type, hw_prio);
+	npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
 }
 
 void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
@@ -1735,9 +1737,9 @@ static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
 	return 0;
 }
 
-static int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
-				      struct npc_subbank **sb,
-				      int *sb_off)
+int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
+			       struct npc_subbank **sb,
+			       int *sb_off)
 {
 	int bank_off, sb_id;
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 815d0b257a7e..004a556c7b90 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -170,6 +170,7 @@ struct npc_defrag_show_node {
  * @num_banks:		Number of banks.
  * @num_subbanks:	Number of subbanks.
  * @subbank_depth:	Depth of subbank.
+ * @en_map:		Enable/disable status.
  * @kw:			Kex configured key type.
  * @sb:			Subbank array.
  * @xa_sb_used:		Array of used subbanks.
@@ -193,6 +194,9 @@ struct npc_priv_t {
 	const int num_banks;
 	int num_subbanks;
 	int subbank_depth;
+	DECLARE_BITMAP(en_map, MAX_NUM_BANKS *
+		       MAX_NUM_SUB_BANKS *
+		       MAX_SUBBANK_DEPTH);
 	u8 kw;
 	struct npc_subbank *sb;
 	struct xarray xa_sb_used;
@@ -336,5 +340,8 @@ 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);
+int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
+			       struct npc_subbank **sb,
+			       int *sb_off);
 
 #endif /* NPC_CN20K_H */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 net-next 0/6] octeontx2-af: npc: Enhancements.
From: Ratheesh Kannoth @ 2026-03-30  5:30 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth

This series extends Marvell octeontx2-af support for CN20K NPC (MCAM
debuggability, allocation policy, default-rule lifetime, and optional
KPU profiles from firmware files) and adds a devlink mechanism for
multi-value parameters, with a small mlx5 follow-up to keep stack usage
within -Wframe-larger-than limits once union devlink_param_value grows.

Patch 1 improves CN20K MCAM visibility in debugfs: mcam_layout marks
enabled entries, dstats reports per-entry hit deltas, and mismatch lists
enabled entries without a PF mapping. MCAM enable state is tracked in a
bitmap updated from the CN20K enable path.

Patch 2 heap-allocates the temporary devlink param value array in
mlx5e_pcie_cong_get_thresh_config() so a larger union devlink_param_value
does not overflow the stack (patch 3).

Patch 3 (Saeed) introduces DEVLINK_PARAM_TYPE_U64_ARRAY and nested
DEVLINK_ATTR_PARAM_VALUE_DATA attributes so drivers and user space can
exchange bounded u64 arrays; devlink_nl_param_fill() moves large locals
to the heap as well.

Patch 4 adds a runtime devlink parameter npc_srch_order (U64 array) to
reorder CN20K subbank search during MCAM allocation.

Patch 5 ties default MCAM entries (broadcast, multicast, promisc, ucast)
to NIX LF alloc/free on CN20K, adds NIX_LF_DONT_FREE_DFT_IDXS for kernel
PF suspend-style teardown, and adjusts free-all and default-entry paths
so default rules are not freed as ordinary user rules.

Patch 6 allows loading a custom KPU profile from /lib/firmware/kpu via
module parameter kpu_profile on non-CN20K paths, with cam2/ptype support
and shared helpers for firmware-sourced vs filesystem-sourced profiles;
CN20K continues to use its existing custom KPU apply path.

The mlx5 change is placed immediately before the devlink union growth
so the series applies cleanly and stays warning-free when built
incrementally.

Ratheesh Kannoth (5):
  octeontx2-af: npc: cn20k: debugfs enhancements
  net/mlx5e: heap-allocate devlink param values
  octeontx2-af: npc: cn20k: add subbank search order control
  octeontx2-af: npc: cn20k: dynamically allocate and free default MCAM
    entries
  octeontx2-af: npc: Support for custom KPU profile from filesystem

Saeed Mahameed (1):
  devlink: Implement devlink param multi attribute nested data values

 Documentation/netlink/specs/devlink.yaml      |   4 +
 .../marvell/octeontx2/af/cn20k/debugfs.c      | 126 ++++-
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 255 +++++++--
 .../ethernet/marvell/octeontx2/af/cn20k/npc.h |  10 +
 .../net/ethernet/marvell/octeontx2/af/mbox.h  |   1 +
 .../net/ethernet/marvell/octeontx2/af/npc.h   |  17 +
 .../net/ethernet/marvell/octeontx2/af/rvu.h   |   6 +-
 .../marvell/octeontx2/af/rvu_devlink.c        |  92 +++-
 .../ethernet/marvell/octeontx2/af/rvu_nix.c   |  16 +-
 .../ethernet/marvell/octeontx2/af/rvu_npc.c   | 521 ++++++++++++++----
 .../ethernet/marvell/octeontx2/af/rvu_npc.h   |  17 +
 .../ethernet/marvell/octeontx2/af/rvu_reg.h   |   1 +
 .../ethernet/marvell/octeontx2/nic/otx2_pf.c  |   6 +-
 .../mellanox/mlx5/core/en/pcie_cong_event.c   |  11 +-
 include/net/devlink.h                         |   8 +
 include/uapi/linux/devlink.h                  |   1 +
 net/devlink/netlink_gen.c                     |   2 +
 net/devlink/param.c                           |  91 ++-
 18 files changed, 979 insertions(+), 206 deletions(-)

--

v8 -> v9: Addressed Simon comments
	https://lore.kernel.org/netdev/20260325072159.1126964-1-rkannoth@marvell.com/

v7 -> v8: Addressed Simon comments
	https://lore.kernel.org/netdev/20260323035110.3908741-1-rkannoth@marvell.com/T/#t

v6 -> v7: Addressed Simon comments
	https://lore.kernel.org/netdev/20260320165432.98832-1-horms@kernel.org/

v5 -> v6: Addressed Jakub,Jiri comments
	https://lore.kernel.org/netdev/20260317045623.250187-1-rkannoth@marvell.com/

v4 -> v5: Addressed Jakub comments
	https://lore.kernel.org/netdev/20260312022754.2029595-6-rkannoth@marvell.com/

v3 -> v4: Addressed Simon comments
	https://lore.kernel.org/netdev/abDeXLpMMxp7G1v3@rkannoth-OptiPlex-7090/#t

v2 -> v3: Addressed Simon comments.
	https://lore.kernel.org/netdev/20260304043032.3661647-1-rkannoth@marvell.com/
v1 -> v2: Addressed Jakub comments.
	https://lore.kernel.org/netdev/20260302085803.2449828-1-rkannoth@marvell.com/#t

2.43.0

^ permalink raw reply

* [PATCH v9 net-next 3/6] devlink: Implement devlink param multi attribute nested data values
From: Ratheesh Kannoth @ 2026-03-30  5:31 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260330053105.2722453-1-rkannoth@marvell.com>

From: Saeed Mahameed <saeedm@nvidia.com>

Devlink param value attribute is not defined since devlink is handling
the value validating and parsing internally, this allows us to implement
multi attribute values without breaking any policies.

Devlink param multi-attribute values are considered to be dynamically
sized arrays of u64 values, by introducing a new devlink param type
DEVLINK_PARAM_TYPE_U64_ARRAY, driver and user space can set a variable
count of u32 values into the DEVLINK_ATTR_PARAM_VALUE_DATA attribute.

Implement get/set parsing and add to the internal value structure passed
to drivers.

This is useful for devices that need to configure a list of values for
a specific configuration.

example:
$ devlink dev param show pci/... name multi-value-param
name multi-value-param type driver-specific
values:
cmode permanent value: 0,1,2,3,4,5,6,7

$ devlink dev param set pci/... name multi-value-param \
		value 4,5,6,7,0,1,2,3 cmode permanent

Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 Documentation/netlink/specs/devlink.yaml |  4 ++
 include/net/devlink.h                    |  8 +++
 include/uapi/linux/devlink.h             |  1 +
 net/devlink/netlink_gen.c                |  2 +
 net/devlink/param.c                      | 91 +++++++++++++++++++-----
 5 files changed, 89 insertions(+), 17 deletions(-)

diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index b495d56b9137..b619de4fe08a 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -226,6 +226,10 @@ definitions:
         value: 10
       -
         name: binary
+      -
+        name: u64-array
+        value: 129
+
   -
     name: rate-tc-index-max
     type: const
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 3038af6ec017..3a355fea8189 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -432,6 +432,13 @@ enum devlink_param_type {
 	DEVLINK_PARAM_TYPE_U64 = DEVLINK_VAR_ATTR_TYPE_U64,
 	DEVLINK_PARAM_TYPE_STRING = DEVLINK_VAR_ATTR_TYPE_STRING,
 	DEVLINK_PARAM_TYPE_BOOL = DEVLINK_VAR_ATTR_TYPE_FLAG,
+	DEVLINK_PARAM_TYPE_U64_ARRAY = DEVLINK_VAR_ATTR_TYPE_U64_ARRAY,
+};
+
+#define __DEVLINK_PARAM_MAX_ARRAY_SIZE 32
+struct devlink_param_u64_array {
+	u64 size;
+	u64 val[__DEVLINK_PARAM_MAX_ARRAY_SIZE];
 };
 
 union devlink_param_value {
@@ -441,6 +448,7 @@ union devlink_param_value {
 	u64 vu64;
 	char vstr[__DEVLINK_PARAM_MAX_STRING_VALUE];
 	bool vbool;
+	struct devlink_param_u64_array u64arr;
 };
 
 struct devlink_param_gset_ctx {
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 7de2d8cc862f..5332223dd6d0 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -406,6 +406,7 @@ enum devlink_var_attr_type {
 	DEVLINK_VAR_ATTR_TYPE_BINARY,
 	__DEVLINK_VAR_ATTR_TYPE_CUSTOM_BASE = 0x80,
 	/* Any possible custom types, unrelated to NLA_* values go below */
+	DEVLINK_VAR_ATTR_TYPE_U64_ARRAY,
 };
 
 enum devlink_attr {
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index eb35e80e01d1..7aaf462f27ee 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -37,6 +37,8 @@ devlink_attr_param_type_validate(const struct nlattr *attr,
 	case DEVLINK_VAR_ATTR_TYPE_NUL_STRING:
 		fallthrough;
 	case DEVLINK_VAR_ATTR_TYPE_BINARY:
+		fallthrough;
+	case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
 		return 0;
 	}
 	NL_SET_ERR_MSG_ATTR(extack, attr, "invalid enum value");
diff --git a/net/devlink/param.c b/net/devlink/param.c
index cf95268da5b0..2ec85dffd8ac 100644
--- a/net/devlink/param.c
+++ b/net/devlink/param.c
@@ -252,6 +252,14 @@ devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
 				return -EMSGSIZE;
 		}
 		break;
+	case DEVLINK_PARAM_TYPE_U64_ARRAY:
+		if (val.u64arr.size > __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+			return -EMSGSIZE;
+
+		for (int i = 0; i < val.u64arr.size; i++)
+			if (nla_put_uint(msg, nla_type, val.u64arr.val[i]))
+				return -EMSGSIZE;
+		break;
 	}
 	return 0;
 }
@@ -304,56 +312,78 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
 				 u32 portid, u32 seq, int flags,
 				 struct netlink_ext_ack *extack)
 {
-	union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
-	union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
 	bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
 	bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
 	const struct devlink_param *param = param_item->param;
-	struct devlink_param_gset_ctx ctx;
+	union devlink_param_value *default_value;
+	union devlink_param_value *param_value;
+	struct devlink_param_gset_ctx *ctx;
 	struct nlattr *param_values_list;
 	struct nlattr *param_attr;
 	void *hdr;
 	int err;
 	int i;
 
+	default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+				sizeof(*default_value), GFP_KERNEL);
+	if (!default_value)
+		return -ENOMEM;
+
+	param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+			      sizeof(*param_value), GFP_KERNEL);
+	if (!param_value) {
+		kfree(default_value);
+		return -ENOMEM;
+	}
+
+	ctx = kmalloc_obj(*ctx);
+	if (!ctx) {
+		kfree(param_value);
+		kfree(default_value);
+		return -ENOMEM;
+	}
+
 	/* Get value from driver part to driverinit configuration mode */
 	for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
 		if (!devlink_param_cmode_is_supported(param, i))
 			continue;
 		if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
-			if (param_item->driverinit_value_new_valid)
+			if (param_item->driverinit_value_new_valid) {
 				param_value[i] = param_item->driverinit_value_new;
-			else if (param_item->driverinit_value_valid)
+			} else if (param_item->driverinit_value_valid) {
 				param_value[i] = param_item->driverinit_value;
-			else
-				return -EOPNOTSUPP;
+			} else {
+				err = -EOPNOTSUPP;
+				goto get_put_fail;
+			}
 
 			if (param_item->driverinit_value_valid) {
 				default_value[i] = param_item->driverinit_default;
 				default_value_set[i] = true;
 			}
 		} else {
-			ctx.cmode = i;
-			err = devlink_param_get(devlink, param, &ctx, extack);
+			ctx->cmode = i;
+			err = devlink_param_get(devlink, param, ctx, extack);
 			if (err)
-				return err;
-			param_value[i] = ctx.val;
+				goto get_put_fail;
+			param_value[i] = ctx->val;
 
-			err = devlink_param_get_default(devlink, param, &ctx,
+			err = devlink_param_get_default(devlink, param, ctx,
 							extack);
 			if (!err) {
-				default_value[i] = ctx.val;
+				default_value[i] = ctx->val;
 				default_value_set[i] = true;
 			} else if (err != -EOPNOTSUPP) {
-				return err;
+				goto get_put_fail;
 			}
 		}
 		param_value_set[i] = true;
 	}
 
+	err = -EMSGSIZE;
 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
 	if (!hdr)
-		return -EMSGSIZE;
+		goto get_put_fail;
 
 	if (devlink_nl_put_handle(msg, devlink))
 		goto genlmsg_cancel;
@@ -393,6 +423,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
 	nla_nest_end(msg, param_values_list);
 	nla_nest_end(msg, param_attr);
 	genlmsg_end(msg, hdr);
+	kfree(default_value);
+	kfree(param_value);
+	kfree(ctx);
 	return 0;
 
 values_list_nest_cancel:
@@ -401,7 +434,11 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
 	nla_nest_cancel(msg, param_attr);
 genlmsg_cancel:
 	genlmsg_cancel(msg, hdr);
-	return -EMSGSIZE;
+get_put_fail:
+	kfree(default_value);
+	kfree(param_value);
+	kfree(ctx);
+	return err;
 }
 
 static void devlink_param_notify(struct devlink *devlink,
@@ -507,7 +544,7 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
 				  union devlink_param_value *value)
 {
 	struct nlattr *param_data;
-	int len;
+	int len, cnt, rem;
 
 	param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
 
@@ -547,6 +584,26 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
 			return -EINVAL;
 		value->vbool = nla_get_flag(param_data);
 		break;
+
+	case DEVLINK_PARAM_TYPE_U64_ARRAY:
+		cnt = 0;
+		nla_for_each_attr_type(param_data,
+				       DEVLINK_ATTR_PARAM_VALUE_DATA,
+				       genlmsg_data(info->genlhdr),
+				       genlmsg_len(info->genlhdr), rem) {
+			if (cnt >= __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+				return -EMSGSIZE;
+
+			if ((nla_len(param_data) != sizeof(u64)) &&
+			    (nla_len(param_data) != sizeof(u32)))
+				return -EINVAL;
+
+			value->u64arr.val[cnt] = (u64)nla_get_uint(param_data);
+			cnt++;
+		}
+
+		value->u64arr.size = cnt;
+		break;
 	}
 	return 0;
 }
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 net-next 2/6] net/mlx5e: heap-allocate devlink param values
From: Ratheesh Kannoth @ 2026-03-30  5:31 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260330053105.2722453-1-rkannoth@marvell.com>

union devlink_param_value grows when U64 array params
are added to devlink. Keeping a four-element array of that
union on the stack in mlx5e_pcie_cong_get_thresh_config()
then trips -Wframe-larger-than=1280. Allocate the temporary
values with kcalloc() and free them on success and
error paths.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 .../ethernet/mellanox/mlx5/core/en/pcie_cong_event.c  | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c b/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c
index 2eb666a46f39..f02995552129 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c
@@ -259,15 +259,21 @@ mlx5e_pcie_cong_get_thresh_config(struct mlx5_core_dev *dev,
 		MLX5_DEVLINK_PARAM_ID_PCIE_CONG_OUT_HIGH,
 	};
 	struct devlink *devlink = priv_to_devlink(dev);
-	union devlink_param_value val[4];
+	union devlink_param_value *val;
+
+	val = kcalloc(4, sizeof(*val), GFP_KERNEL);
+	if (!val)
+		return -ENOMEM;
 
 	for (int i = 0; i < 4; i++) {
 		u32 id = ids[i];
 		int err;
 
 		err = devl_param_driverinit_value_get(devlink, id, &val[i]);
-		if (err)
+		if (err) {
+			kfree(val);
 			return err;
+		}
 	}
 
 	config->inbound_low = val[0].vu16;
@@ -275,6 +281,7 @@ mlx5e_pcie_cong_get_thresh_config(struct mlx5_core_dev *dev,
 	config->outbound_low = val[2].vu16;
 	config->outbound_high = val[3].vu16;
 
+	kfree(val);
 	return 0;
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 net-next 5/6] octeontx2-af: npc: cn20k: dynamically allocate and free default MCAM entries
From: Ratheesh Kannoth @ 2026-03-30  5:31 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260330053105.2722453-1-rkannoth@marvell.com>

Improve MCAM utilization by tying default (broadcast, multicast,
promisc, ucast) entry lifetime to NIX LF usage.

- On NIX LF alloc (e.g. kernel or DPDK), allocate default MCAM entries
  if missing; on NIX LF free, release them so they return to the pool.
- Add NIX_LF_DONT_FREE_DFT_IDXS so the kernel PF driver can free the
  NIX LF without releasing default entries (e.g. across suspend/resume).
- When NIX LF is used by DPDK, default entries are allocated on first
  use and freed when the LF is released if NIX_LF_DONT_FREE_DFT_IDXS is
  not set

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 108 ++++++++++-----
 .../ethernet/marvell/octeontx2/af/cn20k/npc.h |   1 +
 .../net/ethernet/marvell/octeontx2/af/mbox.h  |   1 +
 .../ethernet/marvell/octeontx2/af/rvu_nix.c   |  57 +++++---
 .../ethernet/marvell/octeontx2/af/rvu_npc.c   | 125 +++++++++++++-----
 .../ethernet/marvell/octeontx2/nic/otx2_pf.c  |   4 +-
 6 files changed, 209 insertions(+), 87 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 153765b3e504..69439ff76e10 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -808,6 +808,11 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
 	u64 cfg, hw_prio;
 	u8 kw_type;
 
+	if (index < 0 || index >= mcam->total_entries) {
+		WARN(1, "Wrong mcam index %d\n", index);
+		return;
+	}
+
 	enable ? set_bit(index, npc_priv.en_map) :
 		clear_bit(index, npc_priv.en_map);
 
@@ -1053,6 +1058,11 @@ void 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) {
+		WARN(1, "Wrong mcam index %d\n", index);
+		return;
+	}
+
 	/* Disable before mcam entry update */
 	npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false);
 
@@ -1132,6 +1142,11 @@ void 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) {
+		WARN(1, "Wrong mcam index src=%u dest=%u\n", src, dest);
+		return;
+	}
+
 	dbank = npc_get_bank(mcam, dest);
 	sbank = npc_get_bank(mcam, src);
 	npc_mcam_idx_2_key_type(rvu, src, &src_kwtype);
@@ -1190,11 +1205,24 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
 	int kw = 0, bank;
 	u8 kw_type;
 
+	if (index >= mcam->total_entries) {
+		WARN(1, "Wrong mcam index %u\n", index);
+		return;
+	}
+
 	npc_mcam_idx_2_key_type(rvu, index, &kw_type);
 
 	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_CAMX_INTF_EXT(index,
 								 bank, 1)) & 3;
@@ -1244,7 +1272,7 @@ void 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;
 	}
 
 	for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4) {
@@ -1289,17 +1317,6 @@ void 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;
 }
 
 int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
@@ -1671,8 +1688,8 @@ int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type)
 
 	/* mcam_idx should be less than (2 * bank depth) */
 	if (mcam_idx >= npc_priv.bank_depth * 2) {
-		dev_err(rvu->dev, "%s: bad params\n",
-			__func__);
+		dev_err(rvu->dev, "%s: bad params mcam_idx=%u\n",
+			__func__, mcam_idx);
 		return -EINVAL;
 	}
 
@@ -4024,6 +4041,13 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
 	void *val;
 	int i, j;
 
+	for (int i = 0; i < ARRAY_SIZE(ptr); i++) {
+		if (!ptr[i])
+			continue;
+
+		*ptr[i] = USHRT_MAX;
+	}
+
 	if (!npc_priv.init_done)
 		return 0;
 
@@ -4039,7 +4063,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;
 		}
 
@@ -4059,7 +4082,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;
 		}
 
@@ -4079,7 +4101,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;
 		}
 
@@ -4174,7 +4195,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);
@@ -4182,9 +4203,10 @@ 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;
+	struct rvu_npc_mcam_rule *rule, *tmp;
 	unsigned long index;
-	struct msg_rsp rsp;
+	int blkaddr;
 	u16 ptr[4];
 	int rc, i;
 	void *map;
@@ -4209,7 +4231,7 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
 		index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID);
 		map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
 		if (!map)
-			dev_dbg(rvu->dev,
+			dev_err(rvu->dev,
 				"%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
 				__func__,
 				npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
@@ -4223,7 +4245,7 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
 		index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID);
 		map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
 		if (!map)
-			dev_dbg(rvu->dev,
+			dev_err(rvu->dev,
 				"%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
 				__func__,
 				npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
@@ -4237,21 +4259,47 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
 		index = NPC_DFT_RULE_ID_MK(pcifunc, i);
 		map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
 		if (!map)
-			dev_dbg(rvu->dev,
+			dev_err(rvu->dev,
 				"%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
 				__func__, npc_dft_rule_name[i],
 				pcifunc);
 	}
 
 free_rules:
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+	if (blkaddr < 0)
+		return;
 
-	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);
+	for (int i = 0; i < 4; i++) {
+		if (ptr[i] == USHRT_MAX)
+			continue;
+
+		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)
+			dev_err(rvu->dev,
+				"%s:%d Error deleting default entries (pcifunc=%#x) mcam_idx=%u\n",
+				__func__, __LINE__, pcifunc, ptr[i]);
+	}
+
+	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/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 6f9f796940f3..1b4b4a6fa378 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -345,5 +345,6 @@ int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
 			       int *sb_off);
 const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz);
 int npc_cn20k_search_order_set(struct rvu *rvu, u64 arr[32], int cnt);
+bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc);
 
 #endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index dc42c81c0942..e07fbf842b94 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -1009,6 +1009,7 @@ struct nix_lf_free_req {
 	struct mbox_msghdr hdr;
 #define NIX_LF_DISABLE_FLOWS		BIT_ULL(0)
 #define NIX_LF_DONT_FREE_TX_VTAG	BIT_ULL(1)
+#define NIX_LF_DONT_FREE_DFT_IDXS	BIT_ULL(2)
 	u64 flags;
 };
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index ef5b081162eb..1f2128c61ade 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -16,6 +16,7 @@
 #include "cgx.h"
 #include "lmac_common.h"
 #include "rvu_npc_hash.h"
+#include "cn20k/npc.h"
 
 static void nix_free_tx_vtag_entries(struct rvu *rvu, u16 pcifunc);
 static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
@@ -1499,7 +1500,7 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 				  struct nix_lf_alloc_req *req,
 				  struct nix_lf_alloc_rsp *rsp)
 {
-	int nixlf, qints, hwctx_size, intf, err, rc = 0;
+	int nixlf, qints, hwctx_size, intf, rc = 0;
 	struct rvu_hwinfo *hw = rvu->hw;
 	u16 pcifunc = req->hdr.pcifunc;
 	struct rvu_block *block;
@@ -1555,8 +1556,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 		return NIX_AF_ERR_RSS_GRPS_INVALID;
 
 	/* Reset this NIX LF */
-	err = rvu_lf_reset(rvu, block, nixlf);
-	if (err) {
+	rc = rvu_lf_reset(rvu, block, nixlf);
+	if (rc) {
 		dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n",
 			block->addr - BLKADDR_NIX0, nixlf);
 		return NIX_AF_ERR_LF_RESET;
@@ -1566,8 +1567,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 
 	/* Alloc NIX RQ HW context memory and config the base */
 	hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
-	err = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size);
-	if (err)
+	rc = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size);
+	if (rc)
 		goto free_mem;
 
 	pfvf->rq_bmap = kcalloc(req->rq_cnt, sizeof(long), GFP_KERNEL);
@@ -1583,8 +1584,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 
 	/* Alloc NIX SQ HW context memory and config the base */
 	hwctx_size = 1UL << (ctx_cfg & 0xF);
-	err = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size);
-	if (err)
+	rc = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size);
+	if (rc)
 		goto free_mem;
 
 	pfvf->sq_bmap = kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL);
@@ -1599,8 +1600,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 
 	/* Alloc NIX CQ HW context memory and config the base */
 	hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF);
-	err = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size);
-	if (err)
+	rc = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size);
+	if (rc)
 		goto free_mem;
 
 	pfvf->cq_bmap = kcalloc(req->cq_cnt, sizeof(long), GFP_KERNEL);
@@ -1615,18 +1616,18 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 
 	/* Initialize receive side scaling (RSS) */
 	hwctx_size = 1UL << ((ctx_cfg >> 12) & 0xF);
-	err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, req->rss_sz,
-				 req->rss_grps, hwctx_size, req->way_mask,
-				 !!(req->flags & NIX_LF_RSS_TAG_LSB_AS_ADDER));
-	if (err)
+	rc = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, req->rss_sz,
+				req->rss_grps, hwctx_size, req->way_mask,
+				!!(req->flags & NIX_LF_RSS_TAG_LSB_AS_ADDER));
+	if (rc)
 		goto free_mem;
 
 	/* Alloc memory for CQINT's HW contexts */
 	cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
 	qints = (cfg >> 24) & 0xFFF;
 	hwctx_size = 1UL << ((ctx_cfg >> 24) & 0xF);
-	err = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size);
-	if (err)
+	rc = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size);
+	if (rc)
 		goto free_mem;
 
 	rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf),
@@ -1639,8 +1640,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 	cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
 	qints = (cfg >> 12) & 0xFFF;
 	hwctx_size = 1UL << ((ctx_cfg >> 20) & 0xF);
-	err = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size);
-	if (err)
+	rc = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size);
+	if (rc)
 		goto free_mem;
 
 	rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf),
@@ -1684,10 +1685,16 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 	if (is_sdp_pfvf(rvu, pcifunc))
 		intf = NIX_INTF_TYPE_SDP;
 
-	err = nix_interface_init(rvu, pcifunc, intf, nixlf, rsp,
-				 !!(req->flags & NIX_LF_LBK_BLK_SEL));
-	if (err)
-		goto free_mem;
+	if (is_cn20k(rvu->pdev)) {
+		rc = npc_cn20k_dft_rules_alloc(rvu, pcifunc);
+		if (rc)
+			goto free_mem;
+	}
+
+	rc = nix_interface_init(rvu, pcifunc, intf, nixlf, rsp,
+				!!(req->flags & NIX_LF_LBK_BLK_SEL));
+	if (rc)
+		goto free_dft;
 
 	/* Disable NPC entries as NIXLF's contexts are not initialized yet */
 	rvu_npc_disable_default_entries(rvu, pcifunc, nixlf);
@@ -1699,9 +1706,12 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 
 	goto exit;
 
+free_dft:
+	if (is_cn20k(rvu->pdev))
+		npc_cn20k_dft_rules_free(rvu, pcifunc);
+
 free_mem:
 	nix_ctx_free(rvu, pfvf);
-	rc = -ENOMEM;
 
 exit:
 	/* Set macaddr of this PF/VF */
@@ -1775,6 +1785,9 @@ int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct nix_lf_free_req *req,
 
 	nix_ctx_free(rvu, pfvf);
 
+	if (is_cn20k(rvu->pdev) && !(req->flags & NIX_LF_DONT_FREE_DFT_IDXS))
+		npc_cn20k_dft_rules_free(rvu, pcifunc);
+
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c2ca5ed1d028..8d260bcfbf38 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -165,12 +165,20 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
 
 		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;
@@ -237,12 +245,8 @@ void npc_enable_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 (index < 0 || index >= mcam->banksize * mcam->banks)
-			return;
-
+	if (is_cn20k(rvu->pdev))
 		return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
-	}
 
 	index &= (mcam->banksize - 1);
 	for (; bank < (actbank + mcam->banks_per_entry); bank++) {
@@ -1113,7 +1117,7 @@ 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)
 		return;
 
 	bank = npc_get_bank(mcam, index);
@@ -1158,16 +1162,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);
 	}
 }
 
@@ -1212,8 +1218,13 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
 {
 	struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
 	struct npc_mcam *mcam = &rvu->hw->mcam;
+	int type = NIXLF_UCAST_ENTRY;
 	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;
@@ -1221,8 +1232,11 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
 	/* Ucast MCAM match entry of this PF/VF */
 	if (npc_is_feature_supported(rvu, BIT_ULL(NPC_DMAC),
 				     pfvf->nix_rx_intf)) {
+		if (is_cn20k(rvu->pdev) && is_lbk_vf(rvu, pcifunc))
+			type = NIXLF_PROMISC_ENTRY;
+
 		index = npc_get_nixlf_mcam_index(mcam, pcifunc,
-						 nixlf, NIXLF_UCAST_ENTRY);
+						 nixlf, type);
 		npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
 	}
 
@@ -1232,9 +1246,13 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
 	if ((pcifunc & RVU_PFVF_FUNC_MASK) && !rvu->hw->cap.nix_rx_multicast)
 		return;
 
+	type = NIXLF_BCAST_ENTRY;
+	if (is_cn20k(rvu->pdev) && is_lbk_vf(rvu, pcifunc))
+		type = NIXLF_PROMISC_ENTRY;
+
 	/* add/delete pf_func to broadcast MCE list */
 	npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
-				     NIXLF_BCAST_ENTRY, enable);
+				     type, enable);
 }
 
 void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
@@ -1244,6 +1262,9 @@ void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
 
 	npc_enadis_default_entries(rvu, pcifunc, nixlf, false);
 
+	if (is_cn20k(rvu->pdev) && is_vf(pcifunc))
+		return;
+
 	/* Delete multicast and promisc MCAM entries */
 	npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
 				     NIXLF_ALLMULTI_ENTRY, false);
@@ -1301,6 +1322,10 @@ void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
 	if (blkaddr < 0)
 		return;
 
+	/* only CGX or LBK interfaces have default entries */
+	if (is_cn20k(rvu->pdev) && !npc_is_cgx_or_lbk(rvu, pcifunc))
+		return;
+
 	mutex_lock(&mcam->lock);
 
 	/* Disable MCAM entries directing traffic to this 'pcifunc' */
@@ -2504,33 +2529,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};
 	u16 index, cntr;
+	bool dft_rl;
 	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) {
-			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);
+		if (mcam->entry2pfvf_map[index] != pcifunc)
+			continue;
+
+		mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
+
+		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) {
+				dft_rl = true;
 			}
 		}
+
+		/* Free the entry in bitmap.*/
+		if (!dft_rl)
+			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)) {
+			if (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);
+		}
 	}
 }
 
@@ -3917,13 +3967,22 @@ void rvu_npc_clear_ucast_entry(struct rvu *rvu, int pcifunc, int nixlf)
 	struct npc_mcam *mcam = &rvu->hw->mcam;
 	struct rvu_npc_mcam_rule *rule;
 	int ucast_idx, blkaddr;
+	u8 type;
 
 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
 	if (blkaddr < 0)
 		return;
 
+	type = NIXLF_UCAST_ENTRY;
+	if (is_cn20k(rvu->pdev) && is_lbk_vf(rvu, pcifunc))
+		type = NIXLF_PROMISC_ENTRY;
+
 	ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
-					     nixlf, NIXLF_UCAST_ENTRY);
+					     nixlf, type);
+
+	/* In cn20k, default rules are freed before detach rsrc */
+	if (ucast_idx < 0)
+		return;
 
 	npc_enable_mcam_entry(rvu, mcam, blkaddr, ucast_idx, false);
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index ee623476e5ff..366850742862 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1729,7 +1729,7 @@ int otx2_init_hw_resources(struct otx2_nic *pf)
 	mutex_lock(&mbox->lock);
 	free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
 	if (free_req) {
-		free_req->flags = NIX_LF_DISABLE_FLOWS;
+		free_req->flags = NIX_LF_DISABLE_FLOWS | NIX_LF_DONT_FREE_DFT_IDXS;
 		if (otx2_sync_mbox_msg(mbox))
 			dev_err(pf->dev, "%s failed to free nixlf\n", __func__);
 	}
@@ -1803,7 +1803,7 @@ void otx2_free_hw_resources(struct otx2_nic *pf)
 	/* Reset NIX LF */
 	free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
 	if (free_req) {
-		free_req->flags = NIX_LF_DISABLE_FLOWS;
+		free_req->flags = NIX_LF_DISABLE_FLOWS | NIX_LF_DONT_FREE_DFT_IDXS;
 		if (!(pf->flags & OTX2_FLAG_PF_SHUTDOWN))
 			free_req->flags |= NIX_LF_DONT_FREE_TX_VTAG;
 		if (otx2_sync_mbox_msg(mbox))
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 net-next 4/6] octeontx2-af: npc: cn20k: add subbank search order control
From: Ratheesh Kannoth @ 2026-03-30  5:31 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260330053105.2722453-1-rkannoth@marvell.com>

CN20K NPC MCAM is split into 32 subbanks that are searched in a
predefined order during allocation. Lower-numbered subbanks have
higher priority than higher-numbered ones.

Add a runtime devlink parameter "srch_order" (
DEVLINK_PARAM_TYPE_U32_ARRAY) to control the order in which
subbanks are searched during MCAM allocation.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c | 91 +++++++++++++++++-
 .../ethernet/marvell/octeontx2/af/cn20k/npc.h |  2 +
 .../marvell/octeontx2/af/rvu_devlink.c        | 92 +++++++++++++++++--
 3 files changed, 173 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index e854b85ced9e..153765b3e504 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3317,7 +3317,7 @@ rvu_mbox_handler_npc_cn20k_get_kex_cfg(struct rvu *rvu,
 	return 0;
 }
 
-static int *subbank_srch_order;
+static u32 *subbank_srch_order;
 
 static void npc_populate_restricted_idxs(int num_subbanks)
 {
@@ -3329,7 +3329,7 @@ static int npc_create_srch_order(int cnt)
 {
 	int val = 0;
 
-	subbank_srch_order = kcalloc(cnt, sizeof(int),
+	subbank_srch_order = kcalloc(cnt, sizeof(u32),
 				     GFP_KERNEL);
 	if (!subbank_srch_order)
 		return -ENOMEM;
@@ -3809,6 +3809,93 @@ static void npc_unlock_all_subbank(void)
 		mutex_unlock(&npc_priv.sb[i].lock);
 }
 
+int npc_cn20k_search_order_set(struct rvu *rvu,
+			       u64 arr[MAX_NUM_SUB_BANKS], int cnt)
+{
+	struct npc_mcam *mcam = &rvu->hw->mcam;
+	u32 fslots[MAX_NUM_SUB_BANKS][2];
+	u32 uslots[MAX_NUM_SUB_BANKS][2];
+	int fcnt = 0, ucnt = 0;
+	struct npc_subbank *sb;
+	int idx, val, rc = 0;
+
+	unsigned long index;
+	void *v;
+
+	if (cnt != npc_priv.num_subbanks) {
+		dev_err(rvu->dev, "Number of entries(%u) != %u\n",
+			cnt, npc_priv.num_subbanks);
+		return -EINVAL;
+	}
+
+	mutex_lock(&mcam->lock);
+	npc_lock_all_subbank();
+	restrict_valid = false;
+
+	for (int i = 0; i < cnt; i++)
+		subbank_srch_order[i] = (u32)arr[i];
+
+	xa_for_each(&npc_priv.xa_sb_used, index, v) {
+		val = xa_to_value(v);
+		uslots[ucnt][0] = index;
+		uslots[ucnt][1] = val;
+		xa_erase(&npc_priv.xa_sb_used, index);
+		ucnt++;
+	}
+
+	xa_for_each(&npc_priv.xa_sb_free, index, v) {
+		val = xa_to_value(v);
+		fslots[fcnt][0] = index;
+		fslots[fcnt][1] = val;
+		xa_erase(&npc_priv.xa_sb_free, index);
+		fcnt++;
+	}
+
+	/* xa_store() is done under lock. If xa_store fails
+	 * ,no rollback is planned as it might also fail.
+	 */
+	for (int i = 0; i < ucnt; i++) {
+		idx  = uslots[i][1];
+		sb = &npc_priv.sb[idx];
+		sb->arr_idx = subbank_srch_order[sb->idx];
+		rc = xa_err(xa_store(&npc_priv.xa_sb_used, sb->arr_idx,
+				     xa_mk_value(sb->idx), GFP_KERNEL));
+		if (rc) {
+			dev_err(rvu->dev,
+				"Error to insert index to used list %u\n",
+				sb->idx);
+			goto fail_used;
+		}
+	}
+
+	for (int i = 0; i < fcnt; i++) {
+		idx  = fslots[i][1];
+		sb = &npc_priv.sb[idx];
+		sb->arr_idx = subbank_srch_order[sb->idx];
+		rc = xa_err(xa_store(&npc_priv.xa_sb_free, sb->arr_idx,
+				     xa_mk_value(sb->idx), GFP_KERNEL));
+		if (rc) {
+			dev_err(rvu->dev,
+				"Error to insert index to free list %u\n",
+				sb->idx);
+			goto fail_used;
+		}
+	}
+
+fail_used:
+	npc_unlock_all_subbank();
+	mutex_unlock(&mcam->lock);
+
+	return rc;
+}
+
+const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz)
+{
+	*restricted_order = restrict_valid;
+	*sz = npc_priv.num_subbanks;
+	return subbank_srch_order;
+}
+
 /* Only non-ref non-contigous mcam indexes
  * are picked for defrag process
  */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 004a556c7b90..6f9f796940f3 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -343,5 +343,7 @@ int npc_cn20k_defrag(struct rvu *rvu);
 int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
 			       struct npc_subbank **sb,
 			       int *sb_off);
+const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz);
+int npc_cn20k_search_order_set(struct rvu *rvu, u64 arr[32], int cnt);
 
 #endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index 6494a9ee2f0d..0e8e33c836c9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -1258,6 +1258,7 @@ enum rvu_af_dl_param_id {
 	RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
 	RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE,
 	RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
+	RVU_AF_DEVLINK_PARAM_ID_NPC_SRCH_ORDER,
 	RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
 };
 
@@ -1619,12 +1620,83 @@ static int rvu_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
 	return 0;
 }
 
+static int rvu_af_dl_npc_srch_order_set(struct devlink *devlink, u32 id,
+					struct devlink_param_gset_ctx *ctx,
+					struct netlink_ext_ack *extack)
+{
+	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+	struct rvu *rvu = rvu_dl->rvu;
+
+	return npc_cn20k_search_order_set(rvu,
+					  ctx->val.u64arr.val,
+					  ctx->val.u64arr.size);
+}
+
+static int rvu_af_dl_npc_srch_order_get(struct devlink *devlink, u32 id,
+					struct devlink_param_gset_ctx *ctx,
+					struct netlink_ext_ack *extack)
+{
+	bool restricted_order;
+	const u32 *order;
+	u32 sz;
+
+	order = npc_cn20k_search_order_get(&restricted_order, &sz);
+	ctx->val.u64arr.size = sz;
+	for (int i = 0; i < sz; i++)
+		ctx->val.u64arr.val[i] = order[i];
+
+	return 0;
+}
+
+static int rvu_af_dl_npc_srch_order_validate(struct devlink *devlink, u32 id,
+					     union devlink_param_value val,
+					     struct netlink_ext_ack *extack)
+{
+	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+	struct rvu *rvu = rvu_dl->rvu;
+	bool restricted_order;
+	unsigned long w = 0;
+	u64 *arr;
+	u32 sz;
+
+	npc_cn20k_search_order_get(&restricted_order, &sz);
+	if (sz != val.u64arr.size) {
+		dev_err(rvu->dev,
+			"Wrong size %llu, should be %u\n",
+			val.u64arr.size, sz);
+		return -EINVAL;
+	}
+
+	arr = val.u64arr.val;
+	for (int i = 0; i < sz; i++) {
+		if (arr[i] >= sz)
+			return -EINVAL;
+
+		w |= BIT_ULL(arr[i]);
+	}
+
+	if (bitmap_weight(&w, sz) != sz) {
+		dev_err(rvu->dev,
+			"Duplicate or out-of-range subbank index. %lu\n",
+			find_first_zero_bit(&w, sz));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static const struct devlink_ops rvu_devlink_ops = {
 	.eswitch_mode_get = rvu_devlink_eswitch_mode_get,
 	.eswitch_mode_set = rvu_devlink_eswitch_mode_set,
 };
 
-static const struct devlink_param rvu_af_dl_param_defrag[] = {
+static const struct devlink_param rvu_af_dl_cn20k_params[] = {
+	DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_SRCH_ORDER,
+			     "npc_srch_order", DEVLINK_PARAM_TYPE_U64_ARRAY,
+			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+			     rvu_af_dl_npc_srch_order_get,
+			     rvu_af_dl_npc_srch_order_set,
+			     rvu_af_dl_npc_srch_order_validate),
 	DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
 			     "npc_defrag", DEVLINK_PARAM_TYPE_STRING,
 			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
@@ -1666,13 +1738,13 @@ int rvu_register_dl(struct rvu *rvu)
 	}
 
 	if (is_cn20k(rvu->pdev)) {
-		err = devlink_params_register(dl, rvu_af_dl_param_defrag,
-					      ARRAY_SIZE(rvu_af_dl_param_defrag));
+		err = devlink_params_register(dl, rvu_af_dl_cn20k_params,
+					      ARRAY_SIZE(rvu_af_dl_cn20k_params));
 		if (err) {
 			dev_err(rvu->dev,
-				"devlink defrag params register failed with error %d",
+				"devlink cn20k params register failed with error %d",
 				err);
-			goto err_dl_defrag;
+			goto err_dl_cn20k_params;
 		}
 	}
 
@@ -1695,10 +1767,10 @@ int rvu_register_dl(struct rvu *rvu)
 
 err_dl_exact_match:
 	if (is_cn20k(rvu->pdev))
-		devlink_params_unregister(dl, rvu_af_dl_param_defrag,
-					  ARRAY_SIZE(rvu_af_dl_param_defrag));
+		devlink_params_unregister(dl, rvu_af_dl_cn20k_params,
+					  ARRAY_SIZE(rvu_af_dl_cn20k_params));
 
-err_dl_defrag:
+err_dl_cn20k_params:
 	devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
 
 err_dl_health:
@@ -1717,8 +1789,8 @@ void rvu_unregister_dl(struct rvu *rvu)
 	devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
 
 	if (is_cn20k(rvu->pdev))
-		devlink_params_unregister(dl, rvu_af_dl_param_defrag,
-					  ARRAY_SIZE(rvu_af_dl_param_defrag));
+		devlink_params_unregister(dl, rvu_af_dl_cn20k_params,
+					  ARRAY_SIZE(rvu_af_dl_cn20k_params));
 
 	/* Unregister exact match devlink only for CN10K-B */
 	if (rvu_npc_exact_has_match_table(rvu))
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 net-next 6/6] octeontx2-af: npc: Support for custom KPU profile from filesystem
From: Ratheesh Kannoth @ 2026-03-30  5:31 UTC (permalink / raw)
  To: netdev, linux-kernel, linux-rdma
  Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
	donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
	leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260330053105.2722453-1-rkannoth@marvell.com>

Flashing updated firmware on deployed devices is cumbersome. Provide a
mechanism to load a custom KPU (Key Parse Unit) profile directly from
the filesystem at module load time.

When the rvu_af module is loaded with the kpu_profile parameter, the
specified profile is read from /lib/firmware/kpu and programmed into
the KPU registers. Add npc_kpu_profile_cam2 for the extended cam format
used by filesystem-loaded profiles and support ptype/ptype_mask in
npc_config_kpucam when profile->from_fs is set.

Usage:
  1. Copy the KPU profile file to /lib/firmware/kpu.
  2. Build OCTEONTX2_AF as a module.
  3. Load: insmod rvu_af.ko kpu_profile=<profile_name>

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 .../ethernet/marvell/octeontx2/af/cn20k/npc.c |  54 ++-
 .../net/ethernet/marvell/octeontx2/af/npc.h   |  17 +
 .../net/ethernet/marvell/octeontx2/af/rvu.h   |  12 +-
 .../ethernet/marvell/octeontx2/af/rvu_npc.c   | 421 ++++++++++++++----
 .../ethernet/marvell/octeontx2/af/rvu_npc.h   |  17 +
 .../ethernet/marvell/octeontx2/af/rvu_reg.h   |   1 +
 6 files changed, 408 insertions(+), 114 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 69439ff76e10..ee3c3d37a07f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -521,13 +521,17 @@ npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,
 			       int kpm, int start_entry,
 			       const struct npc_kpu_profile *profile)
 {
+	int num_cam_entries, num_action_entries;
 	int entry, num_entries, max_entries;
 	u64 idx;
 
-	if (profile->cam_entries != profile->action_entries) {
+	num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile);
+	num_action_entries = npc_get_num_kpu_action_entries(rvu, profile);
+
+	if (num_cam_entries != num_action_entries) {
 		dev_err(rvu->dev,
 			"kpm%d: CAM and action entries [%d != %d] not equal\n",
-			kpm, profile->cam_entries, profile->action_entries);
+			kpm, num_cam_entries, num_action_entries);
 
 		WARN(1, "Fatal error\n");
 		return;
@@ -536,16 +540,18 @@ npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,
 	max_entries = rvu->hw->npc_kpu_entries / 2;
 	entry = start_entry;
 	/* Program CAM match entries for previous kpm extracted data */
-	num_entries = min_t(int, profile->cam_entries, max_entries);
+	num_entries = min_t(int, num_cam_entries, max_entries);
 	for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
-		npc_config_kpmcam(rvu, blkaddr, &profile->cam[idx],
+		npc_config_kpmcam(rvu, blkaddr,
+				  npc_get_kpu_cam_nth_entry(rvu, profile, idx),
 				  kpm, entry);
 
 	entry = start_entry;
 	/* Program this kpm's actions */
-	num_entries = min_t(int, profile->action_entries, max_entries);
+	num_entries = min_t(int, num_action_entries, max_entries);
 	for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
-		npc_config_kpmaction(rvu, blkaddr, &profile->action[idx],
+		npc_config_kpmaction(rvu, blkaddr,
+				     npc_get_kpu_action_nth_entry(rvu, profile, idx),
 				     kpm, entry, false);
 }
 
@@ -611,20 +617,23 @@ npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int kpm, int num_entries)
 static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)
 {
 	const struct npc_kpu_profile *profile1, *profile2;
+	int pfl1_num_cam_entries, pfl2_num_cam_entries;
 	int idx, total_cam_entries;
 
 	for (idx = 0; idx < num_kpms; idx++) {
 		profile1 = &rvu->kpu.kpu[idx];
+		pfl1_num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile1);
 		npc_program_single_kpm_profile(rvu, blkaddr, idx, 0, profile1);
 		profile2 = &rvu->kpu.kpu[idx + KPU_OFFSET];
+		pfl2_num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile2);
+
 		npc_program_single_kpm_profile(rvu, blkaddr, idx,
-					       profile1->cam_entries,
+					       pfl1_num_cam_entries,
 					       profile2);
-		total_cam_entries = profile1->cam_entries +
-			profile2->cam_entries;
+		total_cam_entries = pfl1_num_cam_entries + pfl2_num_cam_entries;
 		npc_enable_kpm_entry(rvu, blkaddr, idx, total_cam_entries);
 		rvu_write64(rvu, blkaddr, NPC_AF_KPMX_PASS2_OFFSET(idx),
-			    profile1->cam_entries);
+			    pfl1_num_cam_entries);
 		/* Enable the KPUs associated with this KPM */
 		rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x01);
 		rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx + KPU_OFFSET),
@@ -634,6 +643,7 @@ static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)
 
 void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)
 {
+	struct npc_kpu_profile_action *act;
 	struct rvu_hwinfo *hw = rvu->hw;
 	int num_pkinds, idx;
 
@@ -665,9 +675,15 @@ void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)
 	num_pkinds = rvu->kpu.pkinds;
 	num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
 
-	for (idx = 0; idx < num_pkinds; idx++)
-		npc_config_kpmaction(rvu, blkaddr, &rvu->kpu.ikpu[idx],
+	/* Cn20k does not support Custom profile from filesystem */
+	for (idx = 0; idx < num_pkinds; idx++) {
+		act = npc_get_ikpu_nth_entry(rvu, idx);
+		if (!act)
+			continue;
+
+		npc_config_kpmaction(rvu, blkaddr, act,
 				     0, idx, true);
+	}
 
 	/* Program KPM CAM and Action profiles */
 	npc_program_kpm_profile(rvu, blkaddr, hw->npc_kpms);
@@ -679,7 +695,7 @@ struct npc_priv_t *npc_priv_get(void)
 }
 
 static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
-				struct npc_mcam_kex_extr *mkex_extr,
+				const struct npc_mcam_kex_extr *mkex_extr,
 				u8 intf)
 {
 	u8 num_extr = rvu->hw->npc_kex_extr;
@@ -708,7 +724,7 @@ static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
 }
 
 static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
-				struct npc_mcam_kex_extr *mkex_extr,
+				const struct npc_mcam_kex_extr *mkex_extr,
 				u8 intf)
 {
 	u8 num_extr = rvu->hw->npc_kex_extr;
@@ -737,7 +753,7 @@ static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
 }
 
 static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
-				     struct npc_mcam_kex_extr *mkex_extr)
+				     const struct npc_mcam_kex_extr *mkex_extr)
 {
 	struct rvu_hwinfo *hw = rvu->hw;
 	u8 intf;
@@ -1589,8 +1605,8 @@ npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,
 int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
 			       struct npc_kpu_profile_adapter *profile)
 {
+	const struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
 	size_t hdr_sz = sizeof(struct npc_cn20k_kpu_profile_fwdata);
-	struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
 	struct npc_kpu_profile_action *action;
 	struct npc_kpu_profile_cam *cam;
 	struct npc_kpu_fwdata *fw_kpu;
@@ -1635,9 +1651,9 @@ int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
 	}
 
 	/* Verify if profile fits the HW */
-	if (fw->kpus > profile->kpus) {
-		dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus,
-			 profile->kpus);
+	if (fw->kpus > rvu->hw->npc_kpus) {
+		dev_warn(rvu->dev, "Not enough KPUs: %d > %d\n", fw->kpus,
+			 rvu->hw->npc_kpus);
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
index cefc5d70f3e4..c8c0cb68535c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
@@ -265,6 +265,19 @@ struct npc_kpu_profile_cam {
 	u16 dp2_mask;
 } __packed;
 
+struct npc_kpu_profile_cam2 {
+	u8 state;
+	u8 state_mask;
+	u16 dp0;
+	u16 dp0_mask;
+	u16 dp1;
+	u16 dp1_mask;
+	u16 dp2;
+	u16 dp2_mask;
+	u8 ptype;
+	u8 ptype_mask;
+} __packed;
+
 struct npc_kpu_profile_action {
 	u8 errlev;
 	u8 errcode;
@@ -290,6 +303,10 @@ struct npc_kpu_profile {
 	int action_entries;
 	struct npc_kpu_profile_cam *cam;
 	struct npc_kpu_profile_action *action;
+	int cam_entries2;
+	int action_entries2;
+	struct npc_kpu_profile_action *action2;
+	struct npc_kpu_profile_cam2 *cam2;
 };
 
 /* NPC KPU register formats */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index a466181cf908..2a2f2287e0c0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -553,17 +553,19 @@ struct npc_kpu_profile_adapter {
 	const char			*name;
 	u64				version;
 	const struct npc_lt_def_cfg	*lt_def;
-	const struct npc_kpu_profile_action	*ikpu; /* array[pkinds] */
-	const struct npc_kpu_profile	*kpu; /* array[kpus] */
+	struct npc_kpu_profile_action	*ikpu; /* array[pkinds] */
+	struct npc_kpu_profile_action	*ikpu2; /* array[pkinds] */
+	struct npc_kpu_profile	*kpu; /* array[kpus] */
 	union npc_mcam_key_prfl {
-		struct npc_mcam_kex		*mkex;
+		const struct npc_mcam_kex		*mkex;
 					/* used for cn9k and cn10k */
-		struct npc_mcam_kex_extr	*mkex_extr; /* used for cn20k */
+		const struct npc_mcam_kex_extr	*mkex_extr; /* used for cn20k */
 	} mcam_kex_prfl;
 	struct npc_mcam_kex_hash	*mkex_hash;
 	bool				custom;
 	size_t				pkinds;
 	size_t				kpus;
+	bool				from_fs;
 };
 
 #define RVU_SWITCH_LBK_CHAN	63
@@ -634,7 +636,7 @@ struct rvu {
 
 	/* Firmware data */
 	struct rvu_fwdata	*fwdata;
-	void			*kpu_fwdata;
+	const void		*kpu_fwdata;
 	size_t			kpu_fwdata_sz;
 	void __iomem		*kpu_prfl_addr;
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 8d260bcfbf38..05ade74bbe0d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -1384,7 +1384,8 @@ void rvu_npc_free_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
 }
 
 static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
-				struct npc_mcam_kex *mkex, u8 intf)
+				const struct npc_mcam_kex *mkex,
+				u8 intf)
 {
 	int lid, lt, ld, fl;
 
@@ -1413,7 +1414,8 @@ static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
 }
 
 static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
-				struct npc_mcam_kex *mkex, u8 intf)
+				const struct npc_mcam_kex *mkex,
+				u8 intf)
 {
 	int lid, lt, ld, fl;
 
@@ -1442,7 +1444,7 @@ static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
 }
 
 static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
-				     struct npc_mcam_kex *mkex)
+				     const struct npc_mcam_kex *mkex)
 {
 	struct rvu_hwinfo *hw = rvu->hw;
 	u8 intf;
@@ -1582,8 +1584,12 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,
 			      const struct npc_kpu_profile_cam *kpucam,
 			      int kpu, int entry)
 {
+	const struct npc_kpu_profile_cam2 *kpucam2 = (void *)kpucam;
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
 	struct npc_kpu_cam cam0 = {0};
 	struct npc_kpu_cam cam1 = {0};
+	u64 *val = (u64 *)&cam1;
+	u64 *mask = (u64 *)&cam0;
 
 	cam1.state = kpucam->state & kpucam->state_mask;
 	cam1.dp0_data = kpucam->dp0 & kpucam->dp0_mask;
@@ -1595,6 +1601,14 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,
 	cam0.dp1_data = ~kpucam->dp1 & kpucam->dp1_mask;
 	cam0.dp2_data = ~kpucam->dp2 & kpucam->dp2_mask;
 
+	if (profile->from_fs) {
+		u8 ptype = kpucam2->ptype;
+		u8 pmask = kpucam2->ptype_mask;
+
+		*val |= FIELD_PREP(GENMASK_ULL(57, 56), ptype & pmask);
+		*mask |= FIELD_PREP(GENMASK_ULL(57, 56), ~ptype & pmask);
+	}
+
 	rvu_write64(rvu, blkaddr,
 		    NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 0), *(u64 *)&cam0);
 	rvu_write64(rvu, blkaddr,
@@ -1606,34 +1620,104 @@ u64 npc_enable_mask(int count)
 	return (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL));
 }
 
+struct npc_kpu_profile_action *
+npc_get_ikpu_nth_entry(struct rvu *rvu, int n)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+
+	if (profile->from_fs)
+		return &profile->ikpu2[n];
+
+	return &profile->ikpu[n];
+}
+
+int
+npc_get_num_kpu_cam_entries(struct rvu *rvu,
+			    const struct npc_kpu_profile *kpu_pfl)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+
+	if (profile->from_fs)
+		return kpu_pfl->cam_entries2;
+
+	return kpu_pfl->cam_entries;
+}
+
+struct npc_kpu_profile_cam *
+npc_get_kpu_cam_nth_entry(struct rvu *rvu,
+			  const struct npc_kpu_profile *kpu_pfl, int n)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+
+	if (profile->from_fs)
+		return (void *)&kpu_pfl->cam2[n];
+
+	return (void *)&kpu_pfl->cam[n];
+}
+
+int
+npc_get_num_kpu_action_entries(struct rvu *rvu,
+			       const struct npc_kpu_profile *kpu_pfl)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+
+	if (profile->from_fs)
+		return kpu_pfl->action_entries2;
+
+	return kpu_pfl->action_entries;
+}
+
+struct npc_kpu_profile_action *
+npc_get_kpu_action_nth_entry(struct rvu *rvu,
+			     const struct npc_kpu_profile *kpu_pfl,
+			     int n)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+
+	if (profile->from_fs)
+		return (void *)&kpu_pfl->action2[n];
+
+	return (void *)&kpu_pfl->action[n];
+}
+
 static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
 				    const struct npc_kpu_profile *profile)
 {
+	int num_cam_entries, num_action_entries;
 	int entry, num_entries, max_entries;
 	u64 entry_mask;
 
-	if (profile->cam_entries != profile->action_entries) {
+	num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile);
+	num_action_entries = npc_get_num_kpu_action_entries(rvu, profile);
+
+	if (num_cam_entries != num_action_entries) {
 		dev_err(rvu->dev,
 			"KPU%d: CAM and action entries [%d != %d] not equal\n",
-			kpu, profile->cam_entries, profile->action_entries);
+			kpu, num_cam_entries, num_action_entries);
 	}
 
 	max_entries = rvu->hw->npc_kpu_entries;
 
+	WARN(num_cam_entries > max_entries,
+	     "KPU%u: err: hw max entries=%u, input entries=%u\n",
+	     kpu,  rvu->hw->npc_kpu_entries, num_cam_entries);
+
 	/* Program CAM match entries for previous KPU extracted data */
-	num_entries = min_t(int, profile->cam_entries, max_entries);
+	num_entries = min_t(int, num_cam_entries, max_entries);
 	for (entry = 0; entry < num_entries; entry++)
 		npc_config_kpucam(rvu, blkaddr,
-				  &profile->cam[entry], kpu, entry);
+				  (void *)npc_get_kpu_cam_nth_entry(rvu, profile, entry),
+				  kpu, entry);
 
 	/* Program this KPU's actions */
-	num_entries = min_t(int, profile->action_entries, max_entries);
+	num_entries = min_t(int, num_action_entries, max_entries);
 	for (entry = 0; entry < num_entries; entry++)
-		npc_config_kpuaction(rvu, blkaddr, &profile->action[entry],
+		npc_config_kpuaction(rvu, blkaddr,
+				     (void *)npc_get_kpu_action_nth_entry(rvu, profile, entry),
 				     kpu, entry, false);
 
 	/* Enable all programmed entries */
-	num_entries = min_t(int, profile->action_entries, profile->cam_entries);
+	num_entries = min_t(int, num_action_entries, num_cam_entries);
 	entry_mask = npc_enable_mask(num_entries);
 	/* Disable first KPU_MAX_CST_ENT entries for built-in profile */
 	if (!rvu->kpu.custom)
@@ -1677,26 +1761,145 @@ static void npc_prepare_default_kpu(struct rvu *rvu,
 	npc_cn20k_update_action_entries_n_flags(rvu, profile);
 }
 
-static int npc_apply_custom_kpu(struct rvu *rvu,
-				struct npc_kpu_profile_adapter *profile)
+static int npc_alloc_kpu_cam2_n_action2(struct rvu *rvu, int kpu_num,
+					int num_entries)
+{
+	struct npc_kpu_profile_adapter *adapter = &rvu->kpu;
+	struct npc_kpu_profile *kpu;
+
+	kpu = &adapter->kpu[kpu_num];
+
+	kpu->cam2 = devm_kcalloc(rvu->dev, num_entries,
+				 sizeof(*kpu->cam2), GFP_KERNEL);
+	if (!kpu->cam2)
+		return -ENOMEM;
+
+	kpu->action2 = devm_kcalloc(rvu->dev, num_entries,
+				    sizeof(*kpu->action2), GFP_KERNEL);
+	if (!kpu->action2)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int npc_apply_custom_kpu_from_fw(struct rvu *rvu,
+					struct npc_kpu_profile_adapter *profile)
 {
 	size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;
+	const struct npc_kpu_profile_fwdata *fw;
 	struct npc_kpu_profile_action *action;
-	struct npc_kpu_profile_fwdata *fw;
 	struct npc_kpu_profile_cam *cam;
 	struct npc_kpu_fwdata *fw_kpu;
-	int entries;
-	u16 kpu, entry;
+	int entries, entry, kpu;
 
-	if (is_cn20k(rvu->pdev))
-		return npc_cn20k_apply_custom_kpu(rvu, profile);
+	fw = rvu->kpu_fwdata;
+
+	for (kpu = 0; kpu < fw->kpus; kpu++) {
+		fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
+		if (fw_kpu->entries > KPU_MAX_CST_ENT)
+			dev_warn(rvu->dev,
+				 "Too many custom entries on KPU%d: %d > %d\n",
+				 kpu, fw_kpu->entries, KPU_MAX_CST_ENT);
+		entries = min(fw_kpu->entries, KPU_MAX_CST_ENT);
+		cam = (struct npc_kpu_profile_cam *)fw_kpu->data;
+		offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);
+		action = (struct npc_kpu_profile_action *)(fw->data + offset);
+		offset += fw_kpu->entries * sizeof(*action);
+		if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
+			dev_warn(rvu->dev,
+				 "Profile size mismatch on KPU%i parsing.\n",
+				 kpu + 1);
+			return -EINVAL;
+		}
+		for (entry = 0; entry < entries; entry++) {
+			profile->kpu[kpu].cam[entry] = cam[entry];
+			profile->kpu[kpu].action[entry] = action[entry];
+		}
+	}
+
+	return 0;
+}
+
+static int npc_apply_custom_kpu_from_fs(struct rvu *rvu,
+					struct npc_kpu_profile_adapter *profile)
+{
+	size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;
+	const struct npc_kpu_profile_fwdata *fw;
+	struct npc_kpu_profile_action *action;
+	struct npc_kpu_profile_cam2 *cam2;
+	struct npc_kpu_fwdata *fw_kpu;
+	int entries, ret, entry, kpu;
 
 	fw = rvu->kpu_fwdata;
 
+	/* Binary blob contains ikpu actions entries at start of data[0] */
+	profile->ikpu2 = devm_kcalloc(rvu->dev, 1,
+				      sizeof(ikpu_action_entries),
+				      GFP_KERNEL);
+	if (!profile->ikpu2)
+		return -ENOMEM;
+
+	action = (struct npc_kpu_profile_action *)(fw->data + offset);
+
+	if (rvu->kpu_fwdata_sz < hdr_sz + sizeof(ikpu_action_entries))
+		return -ENOMEM;
+
+	memcpy((void *)profile->ikpu2, action, sizeof(ikpu_action_entries));
+	offset += sizeof(ikpu_action_entries);
+
+	for (kpu = 0; kpu < fw->kpus; kpu++) {
+		fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
+		entries = min(fw_kpu->entries, rvu->hw->npc_kpu_entries);
+		dev_info(rvu->dev,
+			 "Loading %u entries on KPU%d\n", entries, kpu);
+
+		cam2 = (struct npc_kpu_profile_cam2 *)fw_kpu->data;
+		offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam2);
+		action = (struct npc_kpu_profile_action *)(fw->data + offset);
+		offset += fw_kpu->entries * sizeof(*action);
+		if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
+			dev_warn(rvu->dev,
+				 "profile size mismatch on kpu%i parsing.\n",
+				 kpu + 1);
+			return -EINVAL;
+		}
+
+		profile->kpu[kpu].cam_entries2 = entries;
+		profile->kpu[kpu].action_entries2 = entries;
+		ret = npc_alloc_kpu_cam2_n_action2(rvu, kpu, entries);
+		if (ret) {
+			dev_warn(rvu->dev,
+				 "profile entry allocation failed for kpu=%d for %d entries\n",
+				 kpu, entries);
+			return -EINVAL;
+		}
+
+		for (entry = 0; entry < entries; entry++) {
+			profile->kpu[kpu].cam2[entry] = cam2[entry];
+			profile->kpu[kpu].action2[entry] = action[entry];
+		}
+	}
+
+	return 0;
+}
+
+static int npc_apply_custom_kpu(struct rvu *rvu,
+				struct npc_kpu_profile_adapter *profile,
+				bool from_fs, int *fw_kpus)
+{
+	size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata);
+	const struct npc_kpu_profile_fwdata *fw;
+	struct npc_kpu_profile_fwdata *sfw;
+
+	if (is_cn20k(rvu->pdev))
+		return npc_cn20k_apply_custom_kpu(rvu, profile);
+
 	if (rvu->kpu_fwdata_sz < hdr_sz) {
 		dev_warn(rvu->dev, "Invalid KPU profile size\n");
 		return -EINVAL;
 	}
+
+	fw = rvu->kpu_fwdata;
 	if (le64_to_cpu(fw->signature) != KPU_SIGN) {
 		dev_warn(rvu->dev, "Invalid KPU profile signature %llx\n",
 			 fw->signature);
@@ -1724,42 +1927,28 @@ static int npc_apply_custom_kpu(struct rvu *rvu,
 		return -EINVAL;
 	}
 	/* Verify if profile fits the HW */
-	if (fw->kpus > profile->kpus) {
-		dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus,
-			 profile->kpus);
+	if (fw->kpus > rvu->hw->npc_kpus) {
+		dev_warn(rvu->dev, "Not enough KPUs: %d > %d\n", fw->kpus,
+			 rvu->hw->npc_kpus);
 		return -EINVAL;
 	}
 
+	*fw_kpus = fw->kpus;
+
+	sfw = devm_kcalloc(rvu->dev, 1, sizeof(*sfw), GFP_KERNEL);
+	if (!sfw)
+		return -ENOMEM;
+
+	memcpy(sfw, fw, sizeof(*sfw));
+
 	profile->custom = 1;
-	profile->name = fw->name;
+	profile->name = sfw->name;
 	profile->version = le64_to_cpu(fw->version);
-	profile->mcam_kex_prfl.mkex = &fw->mkex;
-	profile->lt_def = &fw->lt_def;
-
-	for (kpu = 0; kpu < fw->kpus; kpu++) {
-		fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
-		if (fw_kpu->entries > KPU_MAX_CST_ENT)
-			dev_warn(rvu->dev,
-				 "Too many custom entries on KPU%d: %d > %d\n",
-				 kpu, fw_kpu->entries, KPU_MAX_CST_ENT);
-		entries = min(fw_kpu->entries, KPU_MAX_CST_ENT);
-		cam = (struct npc_kpu_profile_cam *)fw_kpu->data;
-		offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);
-		action = (struct npc_kpu_profile_action *)(fw->data + offset);
-		offset += fw_kpu->entries * sizeof(*action);
-		if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
-			dev_warn(rvu->dev,
-				 "Profile size mismatch on KPU%i parsing.\n",
-				 kpu + 1);
-			return -EINVAL;
-		}
-		for (entry = 0; entry < entries; entry++) {
-			profile->kpu[kpu].cam[entry] = cam[entry];
-			profile->kpu[kpu].action[entry] = action[entry];
-		}
-	}
+	profile->mcam_kex_prfl.mkex = &sfw->mkex;
+	profile->lt_def = &sfw->lt_def;
 
-	return 0;
+	return from_fs ? npc_apply_custom_kpu_from_fs(rvu, profile) :
+		npc_apply_custom_kpu_from_fw(rvu, profile);
 }
 
 static int npc_load_kpu_prfl_img(struct rvu *rvu, void __iomem *prfl_addr,
@@ -1847,45 +2036,19 @@ static int npc_load_kpu_profile_fwdb(struct rvu *rvu, const char *kpu_profile)
 	return ret;
 }
 
-void npc_load_kpu_profile(struct rvu *rvu)
+static int npc_load_kpu_profile_from_fw(struct rvu *rvu)
 {
 	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
 	const char *kpu_profile = rvu->kpu_pfl_name;
-	const struct firmware *fw = NULL;
-	bool retry_fwdb = false;
-
-	/* If user not specified profile customization */
-	if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))
-		goto revert_to_default;
-	/* First prepare default KPU, then we'll customize top entries. */
-	npc_prepare_default_kpu(rvu, profile);
-
-	/* Order of preceedence for load loading NPC profile (high to low)
-	 * Firmware binary in filesystem.
-	 * Firmware database method.
-	 * Default KPU profile.
-	 */
-	if (!request_firmware_direct(&fw, kpu_profile, rvu->dev)) {
-		dev_info(rvu->dev, "Loading KPU profile from firmware: %s\n",
-			 kpu_profile);
-		rvu->kpu_fwdata = kzalloc(fw->size, GFP_KERNEL);
-		if (rvu->kpu_fwdata) {
-			memcpy(rvu->kpu_fwdata, fw->data, fw->size);
-			rvu->kpu_fwdata_sz = fw->size;
-		}
-		release_firmware(fw);
-		retry_fwdb = true;
-		goto program_kpu;
-	}
+	int fw_kpus = 0;
 
-load_image_fwdb:
 	/* Loading the KPU profile using firmware database */
 	if (npc_load_kpu_profile_fwdb(rvu, kpu_profile))
-		goto revert_to_default;
+		return -EFAULT;
 
-program_kpu:
 	/* Apply profile customization if firmware was loaded. */
-	if (!rvu->kpu_fwdata_sz || npc_apply_custom_kpu(rvu, profile)) {
+	if (!rvu->kpu_fwdata_sz ||
+	    npc_apply_custom_kpu(rvu, profile, false, &fw_kpus)) {
 		/* If image from firmware filesystem fails to load or invalid
 		 * retry with firmware database method.
 		 */
@@ -1899,10 +2062,6 @@ void npc_load_kpu_profile(struct rvu *rvu)
 			}
 			rvu->kpu_fwdata = NULL;
 			rvu->kpu_fwdata_sz = 0;
-			if (retry_fwdb) {
-				retry_fwdb = false;
-				goto load_image_fwdb;
-			}
 		}
 
 		dev_warn(rvu->dev,
@@ -1910,7 +2069,7 @@ void npc_load_kpu_profile(struct rvu *rvu)
 			 kpu_profile);
 		kfree(rvu->kpu_fwdata);
 		rvu->kpu_fwdata = NULL;
-		goto revert_to_default;
+		return -EFAULT;
 	}
 
 	dev_info(rvu->dev, "Using custom profile '%s', version %d.%d.%d\n",
@@ -1918,14 +2077,86 @@ void npc_load_kpu_profile(struct rvu *rvu)
 		 NPC_KPU_VER_MIN(profile->version),
 		 NPC_KPU_VER_PATCH(profile->version));
 
-	return;
+	return 0;
+}
+
+static int npc_load_kpu_profile_from_fs(struct rvu *rvu)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+	const char *kpu_profile = rvu->kpu_pfl_name;
+	const struct firmware *fw = NULL;
+	int ret, fw_kpus = 0;
+	char path[512] = "kpu/";
+
+	if (strlen(kpu_profile) > sizeof(path) - strlen("kpu/") - 1) {
+		dev_err(rvu->dev, "kpu profile name is too big\n");
+		return -ENOSPC;
+	}
+
+	strcat(path, kpu_profile);
+
+	if (request_firmware_direct(&fw, path, rvu->dev))
+		return -ENOENT;
+
+	dev_info(rvu->dev, "Loading KPU profile from filesystem: %s\n",
+		 path);
+
+	rvu->kpu_fwdata = fw->data;
+	rvu->kpu_fwdata_sz = fw->size;
+
+	ret = npc_apply_custom_kpu(rvu, profile, true, &fw_kpus);
+	release_firmware(fw);
+	rvu->kpu_fwdata = NULL;
+
+	if (ret) {
+		rvu->kpu_fwdata_sz = 0;
+		dev_err(rvu->dev,
+			"Loading KPU profile from filesystem failed\n");
+		return ret;
+	}
+
+	rvu->kpu.kpus = fw_kpus;
+	profile->kpus = fw_kpus;
+	profile->from_fs = true;
+	return 0;
+}
+
+void npc_load_kpu_profile(struct rvu *rvu)
+{
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+	const char *kpu_profile = rvu->kpu_pfl_name;
+
+	profile->from_fs = false;
+
+	npc_prepare_default_kpu(rvu, profile);
+
+	/* If user not specified profile customization */
+	if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))
+		return;
+
+	/* Order of preceedence for load loading NPC profile (high to low)
+	 * Firmware binary in filesystem.
+	 * Firmware database method.
+	 * Default KPU profile.
+	 */
+
+	/* No support for filesystem KPU loading for cn20k */
+	if (!is_cn20k(rvu->pdev)) {
+		if (!npc_load_kpu_profile_from_fs(rvu))
+			return;
+	}
+
+	/* First prepare default KPU, then we'll customize top entries. */
+	npc_prepare_default_kpu(rvu, profile);
+	if (!npc_load_kpu_profile_from_fw(rvu))
+		return;
 
-revert_to_default:
 	npc_prepare_default_kpu(rvu, profile);
 }
 
 static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
 {
+	struct npc_kpu_profile_adapter *profile = &rvu->kpu;
 	struct rvu_hwinfo *hw = rvu->hw;
 	int num_pkinds, num_kpus, idx;
 
@@ -1949,7 +2180,9 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
 	num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
 
 	for (idx = 0; idx < num_pkinds; idx++)
-		npc_config_kpuaction(rvu, blkaddr, &rvu->kpu.ikpu[idx], 0, idx, true);
+		npc_config_kpuaction(rvu, blkaddr,
+				     npc_get_ikpu_nth_entry(rvu, idx),
+				     0, idx, true);
 
 	/* Program KPU CAM and Action profiles */
 	num_kpus = rvu->kpu.kpus;
@@ -1957,6 +2190,11 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
 
 	for (idx = 0; idx < num_kpus; idx++)
 		npc_program_kpu_profile(rvu, blkaddr, idx, &rvu->kpu.kpu[idx]);
+
+	if (profile->from_fs) {
+		rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_TYPE(54), 0x03);
+		rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_TYPE(58), 0x03);
+	}
 }
 
 void npc_mcam_rsrcs_deinit(struct rvu *rvu)
@@ -2186,18 +2424,21 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blkaddr)
 
 static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr)
 {
-	struct npc_mcam_kex_extr *mkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;
-	struct npc_mcam_kex *mkex = rvu->kpu.mcam_kex_prfl.mkex;
+	const struct npc_mcam_kex_extr *mkex_extr;
 	struct npc_mcam *mcam = &rvu->hw->mcam;
 	struct rvu_hwinfo *hw = rvu->hw;
+	const struct npc_mcam_kex *mkex;
 	u64 nibble_ena, rx_kex, tx_kex;
 	u64 *keyx_cfg, reg;
 	u8 intf;
 
+	mkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;
+	mkex = rvu->kpu.mcam_kex_prfl.mkex;
+
 	if (is_cn20k(rvu->pdev)) {
-		keyx_cfg = mkex_extr->keyx_cfg;
+		keyx_cfg = (u64 *)mkex_extr->keyx_cfg;
 	} else {
-		keyx_cfg = mkex->keyx_cfg;
+		keyx_cfg = (u64 *)mkex->keyx_cfg;
 		/* Reserve last counter for MCAM RX miss action which is set to
 		 * drop packet. This way we will know how many pkts didn't
 		 * match any MCAM entry.
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h
index 83c5e32e2afc..662f6693cfe9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.h
@@ -18,4 +18,21 @@ int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
 
 void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index);
 void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index);
+
+struct npc_kpu_profile_action *
+npc_get_ikpu_nth_entry(struct rvu *rvu, int n);
+
+int
+npc_get_num_kpu_cam_entries(struct rvu *rvu,
+			    const struct npc_kpu_profile *kpu_pfl);
+struct npc_kpu_profile_cam *
+npc_get_kpu_cam_nth_entry(struct rvu *rvu,
+			  const struct npc_kpu_profile *kpu_pfl, int n);
+
+int
+npc_get_num_kpu_action_entries(struct rvu *rvu,
+			       const struct npc_kpu_profile *kpu_pfl);
+struct npc_kpu_profile_action *
+npc_get_kpu_action_nth_entry(struct rvu *rvu,
+			     const struct npc_kpu_profile *kpu_pfl, int n);
 #endif /* RVU_NPC_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
index 62cdc714ba57..ab89b8c6e490 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -596,6 +596,7 @@
 #define NPC_AF_INTFX_KEX_CFG(a)		(0x01010 | (a) << 8)
 #define NPC_AF_PKINDX_ACTION0(a)	(0x80000ull | (a) << 6)
 #define NPC_AF_PKINDX_ACTION1(a)	(0x80008ull | (a) << 6)
+#define NPC_AF_PKINDX_TYPE(a)		(0x80010ull | (a) << 6)
 #define NPC_AF_PKINDX_CPI_DEFX(a, b)	(0x80020ull | (a) << 6 | (b) << 3)
 #define NPC_AF_KPUX_ENTRYX_CAMX(a, b, c) \
 		(0x100000 | (a) << 14 | (b) << 6 | (c) << 3)
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH bpf-next 2/3] bpf: Disallow freplace on kprobe with mismatched kprobe_write_ctx values
From: Leon Hwang @ 2026-03-30  5:51 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: bpf, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Shuah Khan,
	David S . Miller, Jakub Kicinski, Jesper Dangaard Brouer,
	Toke Hoiland-Jorgensen, Lorenzo Bianconi, linux-kernel,
	linux-kselftest, netdev, kernel-patches-bot
In-Reply-To: <acbrlN_n4Z684h9e@krava>

On 28/3/26 04:41, Jiri Olsa wrote:
> On Tue, Mar 24, 2026 at 11:04:43PM +0800, Leon Hwang wrote:
[...]
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -6404,6 +6404,14 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off,
>>  		/* remember the offset of last byte accessed in ctx */
>>  		if (env->prog->aux->max_ctx_offset < off + size)
>>  			env->prog->aux->max_ctx_offset = off + size;
>> +		if (env->prog->type == BPF_PROG_TYPE_EXT) {
>> +			struct bpf_prog *dst_prog = env->prog->aux->dst_prog;
>> +
>> +			if (env->prog->aux->kprobe_write_ctx != dst_prog->aux->kprobe_write_ctx) {
>> +				verbose(env, "Extension program cannot have different kprobe_write_ctx value with target prog\n");
>> +				return -EINVAL;
>> +			}
>> +		}
> 
> would it be more clear to check this in bpf_check_attach_target,
> instead of depending on actual write to context
> 

I've considered it.

But we can't, because bpf_check_attach_target is before check_ctx_access
at load time.

Besides, sashiko has pointed out that this check in check_ctx_access can
be bypassed when attaching to kprobe_write_ctx=false target [1].

So, I posted v2 to do the check in bpf_tracing_prog_attach at attach
time [2].

[1]
https://sashiko.dev/#/patchset/20260324150444.68166-1-leon.hwang%40linux.dev
[2] https://lore.kernel.org/bpf/20260326141718.17731-1-leon.hwang@linux.dev/

Thanks,
Leon


^ permalink raw reply

* [BUG] bpf: warn_free_bad_obj in bpf_prog_test_run_skb - slab cross-cache confusion in skb_free_head
From: antonius @ 2026-03-30  5:52 UTC (permalink / raw)
  To: bpf
  Cc: netdev, linux-kernel, ast, daniel, andrii, martin.lau, song,
	john.fastabend, kuba, davem, syzkaller-bugs


[-- Attachment #1.1: Type: text/plain, Size: 4758 bytes --]

Hello,

I found a slab cache confusion bug in bpf_prog_test_run_skb() on Linux
7.0.0-rc5, triggered via BPF_PROG_TEST_RUN with BPF_PROG_TYPE_SCHED_CLS.

The issue was originally discovered by syzkaller during a fuzzing campaign
targeting io_uring BPF filter and BPF test_run subsystems.

*REPORTER*
Antonius / Blue Dragon Security
https://bluedragonsec.com
https://github.com/bluedragonsecurity



*Bug Description *
bpf_test_init() allocates skb->head using kzalloc() with size:
  data_size_in + NET_SKB_PAD + NET_IP_ALIGN = 284 + 32 + 2 = 318 bytes

SLUB rounds this up to the kmalloc-1k cache (704 bytes as reported by
KFENCE). However, skb_free_head() subsequently calls:
  kmem_cache_free(skbuff_small_head_cache, head)

This is the wrong cache — the object belongs to kmalloc-1k, not
skbuff_small_head. SLUB detects this mismatch and fires warn_free_bad_obj(),
followed by a KFENCE out-of-bounds read in print_track().


*Affected Code*
net/bpf/test_run.c: bpf_test_init()
net/core/skbuff.c:  skb_free_head()

The root cause is a mismatch between the allocation cache used by
bpf_test_init() and the cache assumed by skb_free_head() when determining
how to free skb->head for test skbs.

*Kernel Version*

7.0.0-rc5 (commit: confirmed on rc5 tag)
Also tested: Lubuntu 25.10 (kernel 7.0.0-rc5, CONFIG_KFENCE=y)
             Debian Trixie syzkaller VM (kernel 7.0.0-rc5, CONFIG_KFENCE=y)

*Privilege Required*

CAP_BPF or root. BPF_PROG_TYPE_SCHED_CLS requires bpf_capable().

*Reproducer*

Minimal C reproducer (2 syscalls):
n.b : I have attacher the reproducer file (repro_bpf.c)

Build: gcc -O0 -o repro_bpf repro_bpf.c
Run:
for i in $(seq 1 1000); do
    sudo ./repro_bpf
    dmesg | grep -q "warn_free\|KFENCE\|cut here" && { echo "CRASH at iter
$i!"; dmesg; break; }
    echo -n "."
done
sudo dmesg | grep warn_free_bad_obj

*Kernel Output*

[  761.069607] ------------[ cut here ]------------
[  761.069623] kmem_cache_free(skbuff_small_head, ffff888186dfac00): object
belongs to different cache kmalloc-1k
[  761.069638] WARNING: mm/slub.c:6258 at warn_free_bad_obj+0x91/0xc0,
CPU#0: repro/1513
[  761.069670] Modules linked in:
[  761.069690] CPU: 0 UID: 0 PID: 1513 Comm: repro Not tainted 7.0.0-rc5 #1
[  761.069716] RIP: 0010:warn_free_bad_obj+0x98/0xc0
[  761.069882] Call Trace:
[  761.069888]  <TASK>
[  761.069899]  skb_free_head+0x1ec/0x290
[  761.069918]  skb_release_data+0x7a6/0x9d0
[  761.069970]  bpf_prog_test_run_skb+0x14f8/0x3410
[  761.070190]  __sys_bpf+0x769/0x4b60
[  761.070422]  do_syscall_64+0x111/0x690
[  761.070456]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[  761.070610]  </TASK>
[  761.073682]
==================================================================
[  761.073736] BUG: KFENCE: out-of-bounds read in print_track+0x0/0x50
[  761.073790] Out-of-bounds read at 0xffff888186dfb010 (1040B right of
kfence-#252):
[  761.074117] kfence-#252: 0xffff888186dfac00-0xffff888186dfaebf,
size=704, cache=kmalloc-1k
[  761.074168] allocated by task 1513 on cpu 0 at 761.069452s:
[  761.074198]  bpf_test_init.isra.0+0xf9/0x1e0
[  761.074218]  bpf_prog_test_run_skb+0x489/0x3410

*Security Impact*

This bug causes heap corruption via slab cross-cache confusion. An object
from kmalloc-1k is placed into the freelist of skbuff_small_head cache.
Subsequent alloc_skb() calls can reclaim this chunk, potentially leading to:
  - Information leak (stale kernel data readable via new skb->head)
  - Heap corruption if controlled data written before reclaim
  - Denial of service (kernel WARNING, system instability)

Full exploitation to LPE would require chaining with additional primitives
(KASLR bypass, heap spray). Bug is not directly exploitable for LPE without
further primitives.

CVSS v3.1 estimate: AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H = 6.7 (Medium)

*Fix Suggestion*

In bpf_test_init() (net/bpf/test_run.c), the skb->head allocation should
either:
1. Use skb_head_from_pool() or kmalloc_reserve() to ensure the allocation
   lands in the cache that skb_free_head() expects, or
2. Set skb->head_frag = 0 and clear the relevant flags so skb_free_head()
   takes the kfree() path instead of kmem_cache_free() path.

Alternatively, skb_free_head() should verify the slab cache before calling
kmem_cache_free().

---
Reported-by: Antonius <antonius@bluedragonsec.com>
Please use this tag in the fix commit:
  Reported-by: Antonius <antonius@bluedragonsec.com>
---
If this is a known issue or already fixed, please point me to the
relevant commit. I was unable to find a matching LKML/syzbot entry
for this specific issue

Thanks,
Antonius
Blue Dragon Security
https://bluedragonsec.com

[-- Attachment #1.2: Type: text/html, Size: 5583 bytes --]

[-- Attachment #2: dmesg.txt --]
[-- Type: text/plain, Size: 21162 bytes --]

[ 3065.322973] ------------[ cut here ]------------
[ 3065.322990] kmem_cache_free(skbuff_small_head, ffff888186d6e000): object belongs to different cache kmalloc-1k
[ 3065.323005] WARNING: mm/slub.c:6258 at warn_free_bad_obj+0x91/0xc0, CPU#0: repro_bpf/2167
[ 3065.323038] Modules linked in:
[ 3065.323061] CPU: 0 UID: 0 PID: 2167 Comm: repro_bpf Not tainted 7.0.0-rc5 #1 PREEMPT(lazy) 
[ 3065.323077] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3065.323098] RIP: 0010:warn_free_bad_obj+0x98/0xc0
[ 3065.323115] Code: 67 48 0f b9 3a 5b 5d c3 cc cc cc cc 48 c7 c1 c5 88 7c 87 48 85 ed 74 04 48 8b 4d 58 48 8d 3d 2f fa 9f 07 48 8b 72 58 48 89 da <67> 48 0f b9 3a 48 85 ed 74 b7 48 89 de 48 89 ef 5b 5d e9 01 eb ff
[ 3065.323128] RSP: 0018:ffffc90003e279d0 EFLAGS: 00010286
[ 3065.323142] RAX: ffffea00061b5b80 RBX: ffff888186d6e000 RCX: ffffffff877c6c5e
[ 3065.323161] RDX: ffff888186d6e000 RSI: ffffffff87068bc0 RDI: ffffffff8985e370
[ 3065.323170] RBP: ffff8881000421c0 R08: 0000000000000005 R09: 0000000000000180
[ 3065.323180] R10: 0000000000000180 R11: ffff8881060939c0 R12: 0000000000000000
[ 3065.323189] R13: 0000000000000000 R14: ffff888186d6e1b0 R15: 0000000000000000
[ 3065.323198] FS:  00007fbd28700780(0000) GS:ffff8881fc6a5000(0000) knlGS:0000000000000000
[ 3065.323211] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3065.323221] CR2: 000055919b946080 CR3: 000000010b7d4006 CR4: 0000000000370ef0
[ 3065.323231] Call Trace:
[ 3065.323237]  <TASK>
[ 3065.323247]  skb_free_head+0x1ec/0x290
[ 3065.323267]  skb_release_data+0x7a6/0x9d0
[ 3065.323285]  ? __pfx_bpf_ctx_finish.isra.0+0x10/0x10
[ 3065.323308]  ? bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.323322]  sk_skb_reason_drop+0x142/0x550
[ 3065.323343]  bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.323356]  ? __lock_acquire+0x466/0x2270
[ 3065.323373]  ? lock_is_held_type+0x8f/0x100
[ 3065.323388]  ? lock_is_held_type+0x8f/0x100
[ 3065.323414]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.323427]  ? lock_release+0xc8/0x2a0
[ 3065.323441]  ? bpf_check_uarg_tail_zero+0x127/0x1b0
[ 3065.323457]  ? __sanitizer_cov_trace_switch+0x54/0x90
[ 3065.323473]  ? fdget+0x17a/0x210
[ 3065.323495]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.323510]  __sys_bpf+0x769/0x4b60
[ 3065.323530]  ? __pfx___sys_bpf+0x10/0x10
[ 3065.323551]  ? find_held_lock+0x2b/0x80
[ 3065.323581]  ? finish_task_switch.isra.0+0x120/0x5d0
[ 3065.323598]  ? lock_release+0xc8/0x2a0
[ 3065.323616]  ? trace_hardirqs_on+0x18/0x170
[ 3065.323631]  ? finish_task_switch.isra.0+0x1af/0x5d0
[ 3065.323646]  ? __switch_to+0x7a0/0x1130
[ 3065.323662]  ? __switch_to_asm+0x33/0x70
[ 3065.323734]  ? exit_to_user_mode_loop+0xae/0x460
[ 3065.323763]  __x64_sys_bpf+0x78/0xc0
[ 3065.323780]  ? trace_hardirqs_on+0x18/0x170
[ 3065.323794]  do_syscall_64+0x111/0x690
[ 3065.323813]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3065.323827] RIP: 0033:0x7fbd2883790d
[ 3065.323844] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48
[ 3065.323857] RSP: 002b:00007ffe05c1edd8 EFLAGS: 00000206 ORIG_RAX: 0000000000000141
[ 3065.323872] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbd2883790d
[ 3065.323881] RDX: 0000000000000050 RSI: 00007ffe05c1ee00 RDI: 000000000000000a
[ 3065.323891] RBP: 00007ffe05c1ee60 R08: 0000000000000000 R09: 0000000000000000
[ 3065.323900] R10: 0000000000000004 R11: 0000000000000206 R12: 00007ffe05c1efa8
[ 3065.323909] R13: 0000000000000001 R14: 00007fbd289a3000 R15: 00005614a0f75d80
[ 3065.323932]  </TASK>
[ 3065.323938] irq event stamp: 4563
[ 3065.323945] hardirqs last  enabled at (4569): [<ffffffff8164e686>] __up_console_sem+0x76/0x80
[ 3065.323963] hardirqs last disabled at (4574): [<ffffffff8164e66b>] __up_console_sem+0x5b/0x80
[ 3065.323979] softirqs last  enabled at (4198): [<ffffffff85800328>] bpf_test_run+0x388/0xc20
[ 3065.324000] softirqs last disabled at (4196): [<ffffffff8580037e>] bpf_test_run+0x3de/0xc20
[ 3065.324020] ---[ end trace 0000000000000000 ]---
[ 3065.329750] Allocated in 0xadacafaea9a8abaa age=5932173448745943461 cpu=2913775534 pid=-1448563798
[ 3065.329797] ------------[ cut here ]------------
[ 3065.329804] pool index 43945 out of bounds (431) for stack id a9a8abaa
[ 3065.329814] WARNING: lib/stackdepot.c:506 at depot_fetch_stack+0x83/0xb0, CPU#0: repro_bpf/2167
[ 3065.329838] Modules linked in:
[ 3065.329853] CPU: 0 UID: 0 PID: 2167 Comm: repro_bpf Tainted: G        W           7.0.0-rc5 #1 PREEMPT(lazy) 
[ 3065.329871] Tainted: [W]=WARN
[ 3065.329877] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3065.329886] RIP: 0010:depot_fetch_stack+0x8a/0xb0
[ 3065.329905] Code: be ff ff ff ff 48 c7 c7 58 c1 df 88 e8 6f a1 aa 02 83 f8 01 75 bd 90 0f 0b 90 eb b7 48 8d 3d 0d 4d d6 05 89 e9 44 89 ea 89 de <67> 48 0f b9 3a 31 c0 eb c2 90 0f 0b 90 31 c0 eb ba 90 0f 0b 90 31
[ 3065.329918] RSP: 0018:ffffc90003e27988 EFLAGS: 00010216
[ 3065.329931] RAX: 0000000000000000 RBX: 000000000000aba9 RCX: 00000000a9a8abaa
[ 3065.329940] RDX: 00000000000001af RSI: 000000000000aba9 RDI: ffffffff898838d0
[ 3065.329950] RBP: 00000000a9a8abaa R08: 0000000000000001 R09: 0000000000000000
[ 3065.329959] R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000d40
[ 3065.329968] R13: 00000000000001af R14: ffff888186d6e1b0 R15: 0000000000000000
[ 3065.329977] FS:  00007fbd28700780(0000) GS:ffff8881fc6a5000(0000) knlGS:0000000000000000
[ 3065.329991] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3065.330001] CR2: 00007fadb5c80560 CR3: 000000010b7d4002 CR4: 0000000000370ef0
[ 3065.330010] Call Trace:
[ 3065.330017]  <TASK>
[ 3065.330026]  stack_depot_print+0x30/0x60
[ 3065.330045]  print_tracking+0x3a/0x70
[ 3065.330061]  skb_free_head+0x1ec/0x290
[ 3065.330078]  skb_release_data+0x7a6/0x9d0
[ 3065.330106]  ? __pfx_bpf_ctx_finish.isra.0+0x10/0x10
[ 3065.330130]  ? bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.330153]  sk_skb_reason_drop+0x142/0x550
[ 3065.330173]  bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.330187]  ? __lock_acquire+0x466/0x2270
[ 3065.330204]  ? lock_is_held_type+0x8f/0x100
[ 3065.330218]  ? lock_is_held_type+0x8f/0x100
[ 3065.330244]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.330258]  ? lock_release+0xc8/0x2a0
[ 3065.330271]  ? bpf_check_uarg_tail_zero+0x127/0x1b0
[ 3065.330287]  ? __sanitizer_cov_trace_switch+0x54/0x90
[ 3065.330303]  ? fdget+0x17a/0x210
[ 3065.330325]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.330341]  __sys_bpf+0x769/0x4b60
[ 3065.330361]  ? __pfx___sys_bpf+0x10/0x10
[ 3065.330381]  ? find_held_lock+0x2b/0x80
[ 3065.330400]  ? finish_task_switch.isra.0+0x120/0x5d0
[ 3065.330416]  ? lock_release+0xc8/0x2a0
[ 3065.330434]  ? trace_hardirqs_on+0x18/0x170
[ 3065.330449]  ? finish_task_switch.isra.0+0x1af/0x5d0
[ 3065.330463]  ? __switch_to+0x7a0/0x1130
[ 3065.330478]  ? __switch_to_asm+0x33/0x70
[ 3065.330513]  ? exit_to_user_mode_loop+0xae/0x460
[ 3065.330531]  __x64_sys_bpf+0x78/0xc0
[ 3065.330548]  ? trace_hardirqs_on+0x18/0x170
[ 3065.330573]  do_syscall_64+0x111/0x690
[ 3065.330593]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3065.330608] RIP: 0033:0x7fbd2883790d
[ 3065.330629] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48
[ 3065.330642] RSP: 002b:00007ffe05c1edd8 EFLAGS: 00000206 ORIG_RAX: 0000000000000141
[ 3065.330656] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbd2883790d
[ 3065.330665] RDX: 0000000000000050 RSI: 00007ffe05c1ee00 RDI: 000000000000000a
[ 3065.330674] RBP: 00007ffe05c1ee60 R08: 0000000000000000 R09: 0000000000000000
[ 3065.330683] R10: 0000000000000004 R11: 0000000000000206 R12: 00007ffe05c1efa8
[ 3065.330693] R13: 0000000000000001 R14: 00007fbd289a3000 R15: 00005614a0f75d80
[ 3065.330747]  </TASK>
[ 3065.330755] irq event stamp: 4989
[ 3065.330761] hardirqs last  enabled at (4995): [<ffffffff8164e686>] __up_console_sem+0x76/0x80
[ 3065.330779] hardirqs last disabled at (5000): [<ffffffff8164e66b>] __up_console_sem+0x5b/0x80
[ 3065.330796] softirqs last  enabled at (4198): [<ffffffff85800328>] bpf_test_run+0x388/0xc20
[ 3065.330816] softirqs last disabled at (4196): [<ffffffff8580037e>] bpf_test_run+0x3de/0xc20
[ 3065.330837] ---[ end trace 0000000000000000 ]---
[ 3065.331246] ------------[ cut here ]------------
[ 3065.331254] corrupt handle or use after stack_depot_put()
[ 3065.331259] WARNING: lib/stackdepot.c:780 at stack_depot_print+0x55/0x60, CPU#0: repro_bpf/2167
[ 3065.331285] Modules linked in:
[ 3065.331298] CPU: 0 UID: 0 PID: 2167 Comm: repro_bpf Tainted: G        W           7.0.0-rc5 #1 PREEMPT(lazy) 
[ 3065.331315] Tainted: [W]=WARN
[ 3065.331322] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3065.331330] RIP: 0010:stack_depot_print+0x55/0x60
[ 3065.331349] Code: e8 c0 f9 ff ff 48 85 c0 74 19 8b 70 14 48 8d 78 20 85 f6 74 e2 5b 31 d2 5d e9 b7 ed c0 fd c3 cc cc cc cc 48 8d 3d 8b 47 d6 05 <67> 48 0f b9 3a eb c6 0f 1f 40 00 90 90 90 90 90 90 90 90 90 90 90
[ 3065.331362] RSP: 0018:ffffc90003e279b0 EFLAGS: 00010246
[ 3065.331374] RAX: 0000000000000000 RBX: 00000000a9a8abaa RCX: 00000000a9a8abaa
[ 3065.331384] RDX: 00000000000001af RSI: 000000000000aba9 RDI: ffffffff89883930
[ 3065.331393] RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000
[ 3065.331402] R10: 0000000000000000 R11: 0000000000000001 R12: 00000001002a2d4f
[ 3065.331411] R13: 0000000000000000 R14: ffff888186d6e1b0 R15: 0000000000000000
[ 3065.331420] FS:  00007fbd28700780(0000) GS:ffff8881fc6a5000(0000) knlGS:0000000000000000
[ 3065.331433] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3065.331443] CR2: 00007fadb5c80560 CR3: 000000010b7d4002 CR4: 0000000000370ef0
[ 3065.331453] Call Trace:
[ 3065.331459]  <TASK>
[ 3065.331467]  print_tracking+0x3a/0x70
[ 3065.331482]  skb_free_head+0x1ec/0x290
[ 3065.331499]  skb_release_data+0x7a6/0x9d0
[ 3065.331516]  ? __pfx_bpf_ctx_finish.isra.0+0x10/0x10
[ 3065.331539]  ? bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.331564]  sk_skb_reason_drop+0x142/0x550
[ 3065.331585]  bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.331599]  ? __lock_acquire+0x466/0x2270
[ 3065.331623]  ? lock_is_held_type+0x8f/0x100
[ 3065.331638]  ? lock_is_held_type+0x8f/0x100
[ 3065.331664]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.331701]  ? lock_release+0xc8/0x2a0
[ 3065.331717]  ? bpf_check_uarg_tail_zero+0x127/0x1b0
[ 3065.331733]  ? __sanitizer_cov_trace_switch+0x54/0x90
[ 3065.331750]  ? fdget+0x17a/0x210
[ 3065.331771]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.331787]  __sys_bpf+0x769/0x4b60
[ 3065.331807]  ? __pfx___sys_bpf+0x10/0x10
[ 3065.331827]  ? find_held_lock+0x2b/0x80
[ 3065.331846]  ? finish_task_switch.isra.0+0x120/0x5d0
[ 3065.331862]  ? lock_release+0xc8/0x2a0
[ 3065.331879]  ? trace_hardirqs_on+0x18/0x170
[ 3065.331894]  ? finish_task_switch.isra.0+0x1af/0x5d0
[ 3065.331908]  ? __switch_to+0x7a0/0x1130
[ 3065.331923]  ? __switch_to_asm+0x33/0x70
[ 3065.331958]  ? exit_to_user_mode_loop+0xae/0x460
[ 3065.331976]  __x64_sys_bpf+0x78/0xc0
[ 3065.331993]  ? trace_hardirqs_on+0x18/0x170
[ 3065.332007]  do_syscall_64+0x111/0x690
[ 3065.332026]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3065.332040] RIP: 0033:0x7fbd2883790d
[ 3065.332051] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48
[ 3065.332064] RSP: 002b:00007ffe05c1edd8 EFLAGS: 00000206 ORIG_RAX: 0000000000000141
[ 3065.332079] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbd2883790d
[ 3065.332099] RDX: 0000000000000050 RSI: 00007ffe05c1ee00 RDI: 000000000000000a
[ 3065.332108] RBP: 00007ffe05c1ee60 R08: 0000000000000000 R09: 0000000000000000
[ 3065.332118] R10: 0000000000000004 R11: 0000000000000206 R12: 00007ffe05c1efa8
[ 3065.332127] R13: 0000000000000001 R14: 00007fbd289a3000 R15: 00005614a0f75d80
[ 3065.332159]  </TASK>
[ 3065.332165] irq event stamp: 5401
[ 3065.332171] hardirqs last  enabled at (5407): [<ffffffff8164e686>] __up_console_sem+0x76/0x80
[ 3065.332188] hardirqs last disabled at (5412): [<ffffffff8164e66b>] __up_console_sem+0x5b/0x80
[ 3065.332205] softirqs last  enabled at (4198): [<ffffffff85800328>] bpf_test_run+0x388/0xc20
[ 3065.332225] softirqs last disabled at (4196): [<ffffffff8580037e>] bpf_test_run+0x3de/0xc20
[ 3065.332246] ---[ end trace 0000000000000000 ]---
[ 3065.337724] Freed in 0xadacafaea9a8abaa age=5932173448745943461 cpu=2913775534 pid=-1448563798
[ 3065.337767] ------------[ cut here ]------------
[ 3065.337775] pool index 43945 out of bounds (431) for stack id a9a8abaa
[ 3065.337785] WARNING: lib/stackdepot.c:506 at depot_fetch_stack+0x83/0xb0, CPU#0: repro_bpf/2167
[ 3065.337811] Modules linked in:
[ 3065.337826] CPU: 0 UID: 0 PID: 2167 Comm: repro_bpf Tainted: G        W           7.0.0-rc5 #1 PREEMPT(lazy) 
[ 3065.337844] Tainted: [W]=WARN
[ 3065.337850] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3065.337860] RIP: 0010:depot_fetch_stack+0x8a/0xb0
[ 3065.337879] Code: be ff ff ff ff 48 c7 c7 58 c1 df 88 e8 6f a1 aa 02 83 f8 01 75 bd 90 0f 0b 90 eb b7 48 8d 3d 0d 4d d6 05 89 e9 44 89 ea 89 de <67> 48 0f b9 3a 31 c0 eb c2 90 0f 0b 90 31 c0 eb ba 90 0f 0b 90 31
[ 3065.337892] RSP: 0018:ffffc90003e279a8 EFLAGS: 00010216
[ 3065.337906] RAX: 0000000000000000 RBX: 000000000000aba9 RCX: 00000000a9a8abaa
[ 3065.337916] RDX: 00000000000001af RSI: 000000000000aba9 RDI: ffffffff898838d0
[ 3065.337926] RBP: 00000000a9a8abaa R08: 0000000000000001 R09: 0000000000000000
[ 3065.337935] R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000d40
[ 3065.337945] R13: 00000000000001af R14: ffff888186d6e1b0 R15: 0000000000000000
[ 3065.337954] FS:  00007fbd28700780(0000) GS:ffff8881fc6a5000(0000) knlGS:0000000000000000
[ 3065.337968] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3065.337978] CR2: 00007fadb5a9d9a0 CR3: 000000010b7d4002 CR4: 0000000000370ef0
[ 3065.337988] Call Trace:
[ 3065.337995]  <TASK>
[ 3065.338004]  stack_depot_print+0x30/0x60
[ 3065.338024]  skb_free_head+0x1ec/0x290
[ 3065.338042]  skb_release_data+0x7a6/0x9d0
[ 3065.338060]  ? __pfx_bpf_ctx_finish.isra.0+0x10/0x10
[ 3065.338085]  ? bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.338100]  sk_skb_reason_drop+0x142/0x550
[ 3065.338121]  bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.338136]  ? __lock_acquire+0x466/0x2270
[ 3065.338153]  ? lock_is_held_type+0x8f/0x100
[ 3065.338168]  ? lock_is_held_type+0x8f/0x100
[ 3065.338195]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.338209]  ? lock_release+0xc8/0x2a0
[ 3065.338223]  ? bpf_check_uarg_tail_zero+0x127/0x1b0
[ 3065.338239]  ? __sanitizer_cov_trace_switch+0x54/0x90
[ 3065.338256]  ? fdget+0x17a/0x210
[ 3065.338279]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.338295]  __sys_bpf+0x769/0x4b60
[ 3065.338316]  ? __pfx___sys_bpf+0x10/0x10
[ 3065.338337]  ? find_held_lock+0x2b/0x80
[ 3065.338356]  ? finish_task_switch.isra.0+0x120/0x5d0
[ 3065.338373]  ? lock_release+0xc8/0x2a0
[ 3065.338391]  ? trace_hardirqs_on+0x18/0x170
[ 3065.338406]  ? finish_task_switch.isra.0+0x1af/0x5d0
[ 3065.338421]  ? __switch_to+0x7a0/0x1130
[ 3065.338438]  ? __switch_to_asm+0x33/0x70
[ 3065.338473]  ? exit_to_user_mode_loop+0xae/0x460
[ 3065.338492]  __x64_sys_bpf+0x78/0xc0
[ 3065.338510]  ? trace_hardirqs_on+0x18/0x170
[ 3065.338524]  do_syscall_64+0x111/0x690
[ 3065.338544]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3065.338567] RIP: 0033:0x7fbd2883790d
[ 3065.338589] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48
[ 3065.338603] RSP: 002b:00007ffe05c1edd8 EFLAGS: 00000206 ORIG_RAX: 0000000000000141
[ 3065.338618] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbd2883790d
[ 3065.338628] RDX: 0000000000000050 RSI: 00007ffe05c1ee00 RDI: 000000000000000a
[ 3065.338638] RBP: 00007ffe05c1ee60 R08: 0000000000000000 R09: 0000000000000000
[ 3065.338647] R10: 0000000000000004 R11: 0000000000000206 R12: 00007ffe05c1efa8
[ 3065.338656] R13: 0000000000000001 R14: 00007fbd289a3000 R15: 00005614a0f75d80
[ 3065.338715]  </TASK>
[ 3065.338723] irq event stamp: 5821
[ 3065.338730] hardirqs last  enabled at (5827): [<ffffffff8164e686>] __up_console_sem+0x76/0x80
[ 3065.338749] hardirqs last disabled at (5832): [<ffffffff8164e66b>] __up_console_sem+0x5b/0x80
[ 3065.338766] softirqs last  enabled at (4198): [<ffffffff85800328>] bpf_test_run+0x388/0xc20
[ 3065.338788] softirqs last disabled at (4196): [<ffffffff8580037e>] bpf_test_run+0x3de/0xc20
[ 3065.338809] ---[ end trace 0000000000000000 ]---
[ 3065.339970] ------------[ cut here ]------------
[ 3065.339981] corrupt handle or use after stack_depot_put()
[ 3065.339986] WARNING: lib/stackdepot.c:780 at stack_depot_print+0x55/0x60, CPU#0: repro_bpf/2167
[ 3065.340013] Modules linked in:
[ 3065.340027] CPU: 0 UID: 0 PID: 2167 Comm: repro_bpf Tainted: G        W           7.0.0-rc5 #1 PREEMPT(lazy) 
[ 3065.340045] Tainted: [W]=WARN
[ 3065.340051] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 3065.340060] RIP: 0010:stack_depot_print+0x55/0x60
[ 3065.340078] Code: e8 c0 f9 ff ff 48 85 c0 74 19 8b 70 14 48 8d 78 20 85 f6 74 e2 5b 31 d2 5d e9 b7 ed c0 fd c3 cc cc cc cc 48 8d 3d 8b 47 d6 05 <67> 48 0f b9 3a eb c6 0f 1f 40 00 90 90 90 90 90 90 90 90 90 90 90
[ 3065.340102] RSP: 0018:ffffc90003e279d0 EFLAGS: 00010246
[ 3065.340115] RAX: 0000000000000000 RBX: 00000000a9a8abaa RCX: 00000000a9a8abaa
[ 3065.340125] RDX: 00000000000001af RSI: 000000000000aba9 RDI: ffffffff89883930
[ 3065.340135] RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000
[ 3065.340144] R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000
[ 3065.340161] R13: 0000000000000000 R14: ffff888186d6e1b0 R15: 0000000000000000
[ 3065.340171] FS:  00007fbd28700780(0000) GS:ffff8881fc6a5000(0000) knlGS:0000000000000000
[ 3065.340184] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3065.340194] CR2: 00007fadb5e73e70 CR3: 000000010b7d4002 CR4: 0000000000370ef0
[ 3065.340203] Call Trace:
[ 3065.340210]  <TASK>
[ 3065.340218]  skb_free_head+0x1ec/0x290
[ 3065.340235]  skb_release_data+0x7a6/0x9d0
[ 3065.340253]  ? __pfx_bpf_ctx_finish.isra.0+0x10/0x10
[ 3065.340276]  ? bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.340290]  sk_skb_reason_drop+0x142/0x550
[ 3065.340310]  bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.340324]  ? __lock_acquire+0x466/0x2270
[ 3065.340340]  ? lock_is_held_type+0x8f/0x100
[ 3065.340354]  ? lock_is_held_type+0x8f/0x100
[ 3065.340380]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.340394]  ? lock_release+0xc8/0x2a0
[ 3065.340407]  ? bpf_check_uarg_tail_zero+0x127/0x1b0
[ 3065.340423]  ? __sanitizer_cov_trace_switch+0x54/0x90
[ 3065.340439]  ? fdget+0x17a/0x210
[ 3065.340461]  ? __pfx_bpf_prog_test_run_skb+0x10/0x10
[ 3065.340476]  __sys_bpf+0x769/0x4b60
[ 3065.340496]  ? __pfx___sys_bpf+0x10/0x10
[ 3065.340517]  ? find_held_lock+0x2b/0x80
[ 3065.340535]  ? finish_task_switch.isra.0+0x120/0x5d0
[ 3065.340555]  ? lock_release+0xc8/0x2a0
[ 3065.340588]  ? trace_hardirqs_on+0x18/0x170
[ 3065.340604]  ? finish_task_switch.isra.0+0x1af/0x5d0
[ 3065.340618]  ? __switch_to+0x7a0/0x1130
[ 3065.340634]  ? __switch_to_asm+0x33/0x70
[ 3065.340699]  ? exit_to_user_mode_loop+0xae/0x460
[ 3065.340721]  __x64_sys_bpf+0x78/0xc0
[ 3065.340738]  ? trace_hardirqs_on+0x18/0x170
[ 3065.340752]  do_syscall_64+0x111/0x690
[ 3065.340771]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3065.340785] RIP: 0033:0x7fbd2883790d
[ 3065.340797] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48
[ 3065.340810] RSP: 002b:00007ffe05c1edd8 EFLAGS: 00000206 ORIG_RAX: 0000000000000141
[ 3065.340825] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbd2883790d
[ 3065.340834] RDX: 0000000000000050 RSI: 00007ffe05c1ee00 RDI: 000000000000000a
[ 3065.340843] RBP: 00007ffe05c1ee60 R08: 0000000000000000 R09: 0000000000000000
[ 3065.340852] R10: 0000000000000004 R11: 0000000000000206 R12: 00007ffe05c1efa8
[ 3065.340862] R13: 0000000000000001 R14: 00007fbd289a3000 R15: 00005614a0f75d80
[ 3065.340896]  </TASK>
[ 3065.340918] irq event stamp: 6227
[ 3065.340925] hardirqs last  enabled at (6233): [<ffffffff8164e686>] __up_console_sem+0x76/0x80
[ 3065.340943] hardirqs last disabled at (6238): [<ffffffff8164e66b>] __up_console_sem+0x5b/0x80
[ 3065.340961] softirqs last  enabled at (4198): [<ffffffff85800328>] bpf_test_run+0x388/0xc20
[ 3065.340987] softirqs last disabled at (4196): [<ffffffff8580037e>] bpf_test_run+0x3de/0xc20
[ 3065.341022] ---[ end trace 0000000000000000 ]---

[-- Attachment #3: repro_bpf.c --]
[-- Type: text/x-csrc, Size: 3937 bytes --]

#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/mman.h>

#ifndef __NR_bpf
#define __NR_bpf 321
#endif

/* BPF insns: ld_imm64(r0,0) + exit — 3 insns = 24 bytes */
static uint8_t bpf_prog_bytes[] = {
    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

/* Data 284 bytes persis dari syzkaller repro.cprog — confirmed crash */
static uint8_t syz_data[284] = {
    0x60,0xdc,0x24,0x19,0xdd,0x5e,0x95,0xd4,0x73,0x79,0xd5,0x04,0xef,0x23,0xc1,0x79,
    0x45,0x52,0xaa,0x7b,0x7d,0x1d,0x56,0xfa,0xba,0x28,0x2e,0x46,0xc9,0x45,0x81,0x3d,
    0x60,0x90,0xa3,0x11,0x47,0xc0,0x7f,0x95,0xf2,0x71,0x69,0xcb,0x54,0xbe,0x67,0x59,
    0x79,0x28,0x85,0xcb,0x60,0xfa,0x32,0x80,0x61,0xa0,0xc9,0x05,0xc3,0xaa,0x1e,0x4c,
    0x7b,0x82,0xf5,0x74,0x69,0x25,0x10,0x83,0xa0,0x12,0x8e,0x50,0xde,0xb0,0x10,0x72,
    0xd9,0xc4,0x7a,0x94,0xca,0x02,0xb3,0xf7,0x4a,0xf9,0xba,0xcf,0xb5,0xf7,0x06,0x13,
    0x36,0x1b,0x48,0x01,0xbe,0xd2,0x6b,0x41,0x30,0xf9,0x68,0x1e,0xd2,0xa7,0xc6,0x93,
    0xff,0x8e,0xd1,0xea,0xf8,0x20,0xc0,0x60,0x13,0x33,0xe5,0xed,0x3f,0xd2,0xdc,0x8a,
    0x5d,0xea,0xbe,0xeb,0x37,0xaf,0x12,0x0a,0x72,0xe5,0x00,0x8f,0xea,0xf8,0xae,0x0f,
    0x59,0x9d,0xc1,0x86,0xc5,0xd5,0x8c,0x54,0x4a,0x1e,0xc8,0x83,0xf4,0xbc,0x04,0x6e,
    0xd9,0x7a,0xf6,0x39,0x06,0xc0,0x12,0xab,0x0b,0xa6,0xa6,0x6e,0x06,0xcc,0x06,0x17,
    0x78,0xe5,0x95,0x13,0x1c,0x15,0xcd,0xdf,0x7c,0x57,0x75,0xe3,0xaa,0x3d,0x8a,0x14,
    0x13,0x97,0xed,0x95,0x93,0x90,0x27,0x81,0xf2,0xa1,0x64,0x32,0x5f,0x30,0x4c,0xba,
    0x56,0x6f,0xa5,0x7e,0xef,0xff,0xa7,0x9e,0xa5,0xbb,0x08,0x71,0xd9,0x9f,0x3e,0xbb,
    0x4c,0x46,0xed,0x51,0xc9,0x55,0x2b,0xda,0x25,0xa8,0x12,0x85,0xdc,0x0b,0x06,0x4a,
    0xa7,0xfc,0xfb,0x00,0xf7,0x8a,0x33,0x24,0x8e,0x4d,0xf8,0x87,0xf2,0xe6,0x09,0x5c,
    0x05,0xc9,0x97,0x20,0x96,0x66,0xf9,0xb5,0xad,0x2f,0xed,0x68,0x41,0xfa,0xb9,0x93,
    0x28,0x88,0x5b,0x45,0x5e,0x61,0x6f,0x62,0x94,0xaa,0x17,0x68,
};

static int bpf_load(void)
{
    uint8_t attr[0x94];
    memset(attr, 0, sizeof(attr));
    *(uint32_t*)(attr+0x00) = 3;                         /* SCHED_CLS */
    *(uint32_t*)(attr+0x04) = 3;                         /* insn_cnt */
    *(uint64_t*)(attr+0x08) = (uint64_t)bpf_prog_bytes;
    *(uint64_t*)(attr+0x10) = (uint64_t)"GPL";
    return (int)syscall(__NR_bpf, 5, attr, 0x94);
}

static long bpf_run(int fd, void *data, uint32_t sz,
                    uint32_t repeat, uint32_t flags)
{
    uint8_t attr[0x50];
    memset(attr, 0, sizeof(attr));
    *(uint32_t*)(attr+0x00) = (uint32_t)fd;
    *(uint32_t*)(attr+0x08) = sz;
    *(uint64_t*)(attr+0x10) = (uint64_t)data;
    *(uint32_t*)(attr+0x20) = repeat;
    *(uint32_t*)(attr+0x40) = flags;   /* BPF_F_TEST_RUN_ON_CPU = 4 */
    *(uint32_t*)(attr+0x44) = 0;       /* cpu = 0 */
    return syscall(__NR_bpf, 10, attr, 0x50);
}

int main(void)
{
    printf("repro2 — warn_free_bad_obj (syzkaller exact data)\n");
    printf("uid=%d euid=%d\n", getuid(), geteuid());

    /* Setup mmap persis seperti syzkaller */
    syscall(__NR_mmap, 0x1ffffffff000ul, 0x1000ul,
            0ul, 0x32ul, -1, 0ul);
    syscall(__NR_mmap, 0x200000000000ul, 0x1000000ul,
            7ul, 0x32ul, -1, 0ul);
    syscall(__NR_mmap, 0x200001000000ul, 0x1000ul,
            0ul, 0x32ul, -1, 0ul);

    int fd = bpf_load();
    if (fd < 0) {
        printf("[-] BPF_PROG_LOAD: %s\n", strerror(errno));
        return 1;
    }
    printf("[+] prog fd=%d\n", fd);

    printf("[*] Trigger: syz_data=284B flags=4 repeat=4\n");
    long ret = bpf_run(fd, syz_data, 284, 4, 4);
    printf("[*] ret=%ld\n", ret);

    /* Loop untuk reliability */
    for (int i = 0; i < 50; i++)
        bpf_run(fd, syz_data, 284, 4, 4);

    printf("[+] Done — cek: dmesg | grep warn_free\n");
    close(fd);
    return 0;
}

[-- Attachment #4: dmesg.png --]
[-- Type: image/png, Size: 397200 bytes --]

^ permalink raw reply

* [PATCH net] net: ethernet: cortina: Fix SKB leak
From: Linus Walleij @ 2026-03-30  6:00 UTC (permalink / raw)
  To: Hans Ulli Kroll, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Michał Mirosław
  Cc: netdev, Andreas Haarmann-Thiemann, Linus Walleij

From: Andreas Haarmann-Thiemann <eitschman@nebelreich.de>

Under sustained RX load (e.g. large file transfers over the network), the
device freezes completely and requires a hard power cycle. No kernel panic
or oops is produced; the system simply stops responding.

In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when
gmac_get_queue_page() returns NULL for the second page of a multi-page
fragment, the driver logs an error and continues — but does not free the
in-progress skb that was already being assembled via napi_build_skb() /
napi_get_frags():

    gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE);
    if (!gpage) {
        dev_err(geth->dev, "could not find mapping\n");
        /* BUG: skb leaked here */
        port->stats.rx_dropped++;
       continue;
    }

This path is distinct from the similar block in gmac_cleanup_rxq(), which
correctly only logs "could not find page" without an skb in flight.

Each occurrence of this error path leaks one skb. Under sustained traffic
the leak exhausts kernel memory, causing the observed lockup.

Free the in-progress skb via napi_free_frags() before continuing, matching
the pattern already used elsewhere in the driver.

Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet")
Signed-off-by: Andreas Haarmann-Thiemann <eitschman@nebelreich.de>
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
 drivers/net/ethernet/cortina/gemini.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c
index 4824232f4890..723d90d5fdf3 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -1491,6 +1491,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
 		gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE);
 		if (!gpage) {
 			dev_err(geth->dev, "could not find mapping\n");
+			if (skb) {
+				napi_free_frags(&port->napi);
+				skb = NULL;
+			}
 			continue;
 		}
 		page = gpage->page;

---
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
change-id: 20260330-gemini-ethernet-fix-604c28c53da1

Best regards,
-- 
Linus Walleij <linusw@kernel.org>


^ permalink raw reply related

* Re: [PATCH v2 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-03-30  6:29 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mukesh Ojha, linux-arm-msm, devicetree, dri-devel, freedreno,
	linux-media, netdev, linux-wireless, ath12k, linux-remoteproc,
	andersson, konradybcio, robh, krzk+dt, conor+dt, robin.clark,
	sean, akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
	airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
	elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
	mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
	tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
	jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <2da6cbcc-677d-4ba8-9762-ecb47b157f21@kernel.org>

On Fri, Mar 27, 2026 at 02:39:24PM +0100, Krzysztof Kozlowski wrote:
> On 23/03/2026 13:50, Sumit Garg wrote:
> >>> +
> >>> +#include <linux/device/devres.h>
> >>> +#include <linux/firmware/qcom/qcom_pas.h>
> >>> +#include <linux/kernel.h>
> >>> +#include <linux/module.h>
> >>> +
> >>> +#include "qcom_pas.h"
> >>> +
> >>> +struct qcom_pas_ops *ops_ptr;
> >>
> >> Should this be static ?
> > 
> > It was static earlier in v1. I dropped it based on earlier v1 discussion
> > with Krzysztof. Let me conclude that discussion on the other thread
> > again.
> 
> The discussion was whether this should be singleton in the first place,
> not making it a global singleton.
> 
> Of course it cannot be anything else than static - nothing should poke here.

Sure, I have put the static back for v3.

-Sumit

^ permalink raw reply

* [PATCH net-next v2] sfc: add transmit timestamping support
From: Izabela Bakollari @ 2026-03-30  6:32 UTC (permalink / raw)
  To: Edward Cree, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni
  Cc: netdev, linux-net-drivers, linux-kernel

Add ethtool op to advertise TX timestamping. Insert a
skb_tx_timestamp call in __efx_enqueue_skb.

Signed-off-by: Izabela Bakollari <ibakolla@redhat.com>
Reviewed-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ethtool.c | 2 ++
 drivers/net/ethernet/sfc/tx.c      | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 362388754a29..c0038b942913 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -231,6 +231,8 @@ static int efx_ethtool_get_ts_info(struct net_device *net_dev,
 {
 	struct efx_nic *efx = efx_netdev_priv(net_dev);
 
+	ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE;
+
 	efx_ptp_get_ts_info(efx, ts_info);
 	return 0;
 }
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index 4dff19b6ef17..ea0fc1000476 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -371,6 +371,8 @@ netdev_tx_t __efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb
 	if (!data_mapped && (efx_tx_map_data(tx_queue, skb, segments)))
 		goto err;
 
+	skb_tx_timestamp(skb);
+
 	efx_tx_maybe_stop_queue(tx_queue);
 
 	tx_queue->xmit_pending = true;
-- 
2.51.0


^ permalink raw reply related

* RE: [Intel-wired-lan] [PATCH iwl-net v1] igc: fix potential skb leak in igc_fpe_xmit_smd_frame()
From: Loktionov, Aleksandr @ 2026-03-30  6:32 UTC (permalink / raw)
  To: Kohei Enju, intel-wired-lan@lists.osuosl.org,
	netdev@vger.kernel.org
  Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Faizal Rahim
In-Reply-To: <20260329145122.126040-1-kohei@enjuk.jp>



> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Kohei Enju
> Sent: Sunday, March 29, 2026 4:51 PM
> To: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org
> Cc: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; Andrew Lunn
> <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>; Eric
> Dumazet <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo
> Abeni <pabeni@redhat.com>; Faizal Rahim
> <faizal.abdul.rahim@linux.intel.com>; Kohei Enju <kohei@enjuk.jp>
> Subject: [Intel-wired-lan] [PATCH iwl-net v1] igc: fix potential skb
> leak in igc_fpe_xmit_smd_frame()
> 
> When igc_fpe_init_tx_descriptor() fails, no one takes care of an
> allocated skb, leaking it. [1]
> 
> Use dev_kfree_skb_any() on failure.
> Also call igc_flush_tx_descriptors() only on success.
> 
> [1]
> unreferenced object 0xffff88813aee1b40 (size 224):
>   comm "softirq", pid 0, jiffies 4294709256 [...]
>   backtrace (crc dee31384):
>     kmem_cache_alloc_node_noprof+0x54f/0x640
>     __alloc_skb+0xd9/0x5b0
>     igc_fpe_xmit_smd_frame.isra.0+0xad/0x510
>     igc_fpe_send_mpacket+0x32/0x80
> [...]
> 
> Fixes: 5422570c0010 ("igc: add support for frame preemption
> verification")
> Signed-off-by: Kohei Enju <kohei@enjuk.jp>
> ---
>  drivers/net/ethernet/intel/igc/igc_tsn.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c
> b/drivers/net/ethernet/intel/igc/igc_tsn.c
> index 8a110145bfee..eaa274248d54 100644
> --- a/drivers/net/ethernet/intel/igc/igc_tsn.c
> +++ b/drivers/net/ethernet/intel/igc/igc_tsn.c
> @@ -109,10 +109,14 @@ static int igc_fpe_xmit_smd_frame(struct
> igc_adapter *adapter,
>  	__netif_tx_lock(nq, cpu);
> 
>  	err = igc_fpe_init_tx_descriptor(ring, skb, type);
> -	igc_flush_tx_descriptors(ring);
> +	if (!err)
> +		igc_flush_tx_descriptors(ring);
> 
>  	__netif_tx_unlock(nq);
> 
> +	if (err)
> +		dev_kfree_skb_any(skb);
> +
>  	return err;
>  }
> 
> --
> 2.51.0

I'd recommend adding reproduction steps and Cc: stable@vger.kernel.org
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>


^ permalink raw reply

* [PATCH net v3] net/x25: Fix overflow when accumulating packets
From: Martin Schiller @ 2026-03-30  6:36 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
  Cc: Yiming Qian, linux-x25, netdev, linux-kernel, security,
	Martin Schiller

Add a check to ensure that `x25_sock.fraglen` does not overflow.

The `fraglen` also needs to be resetted when purging `fragment_queue` in
`x25_clear_queues()`.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Suggested-by: Yiming Qian <yimingqian591@gmail.com>
Signed-off-by: Martin Schiller <ms@dev.tdt.de>
---
Changes in v3:
- Added missing Cc: Simon Horman <horms@kernel.org>  
- Added missing Fixes tag
- Replaced `Reported-by:` by `Suggested-by:`, because I cannot give an
  URL to the required `Closes:` tag
- Link to v2: https://lore.kernel.org/r/20260327-x25_fraglen-v2-1-143911c3f62a@dev.tdt.de

Changes in v2:
- Use USHRT_MAX instead of sizeof(fraglen) nonsense
- Link to v1: https://lore.kernel.org/r/20260327-x25_fraglen-v1-1-9fc751d4f754@dev.tdt.de
---
 net/x25/x25_in.c   | 6 ++++++
 net/x25/x25_subr.c | 1 +
 2 files changed, 7 insertions(+)

diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index b981a4828d08c2e6676749a06035910eab01e6cd..cb84c683d249d6078f3673835bb2f80eb487f253 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -34,6 +34,12 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
 	struct sk_buff *skbo, *skbn = skb;
 	struct x25_sock *x25 = x25_sk(sk);
 
+	/* make sure we don't overflow */
+	if (x25->fraglen + skb->len > USHRT_MAX) {
+		kfree_skb(skb);
+		return 1;
+	}
+
 	if (more) {
 		x25->fraglen += skb->len;
 		skb_queue_tail(&x25->fragment_queue, skb);
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 0285aaa1e93c17233748d38eef6d8b5c6059b67a..159708d9ad20cb2e6db24ead67daf1e9d6258f64 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
 	skb_queue_purge(&x25->interrupt_in_queue);
 	skb_queue_purge(&x25->interrupt_out_queue);
 	skb_queue_purge(&x25->fragment_queue);
+	x25->fraglen = 0;
 }
 
 

---
base-commit: dc9e9d61e301c087bcd990dbf2fa18ad3e2e1429
change-id: 20260325-x25_fraglen-8fc240d1edd3

Best regards,
-- 
Martin Schiller <ms@dev.tdt.de>


^ permalink raw reply related

* RE: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
From: Korenblit, Miriam Rachel @ 2026-03-30  6:43 UTC (permalink / raw)
  To: Cao, Junjie, Berg, Johannes, linux-wireless@vger.kernel.org,
	richardcochran@gmail.com
  Cc: horms@kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, yedidya.ben.shimol@intel.com,
	Stern, Avraham, Gabay, Daniel, Prabhu, Krishnanand,
	Coelho, Luciano, gregory.greenman@intel.com,
	stable@vger.kernel.org, Vadim Fedorenko
In-Reply-To: <20260212125035.1345718-1-junjie.cao@intel.com>



> -----Original Message-----
> From: Cao, Junjie <junjie.cao@intel.com>
> Sent: Thursday, February 12, 2026 2:51 PM
> To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>; Berg,
> Johannes <johannes.berg@intel.com>; linux-wireless@vger.kernel.org;
> richardcochran@gmail.com
> Cc: horms@kernel.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org;
> yedidya.ben.shimol@intel.com; Stern, Avraham <avraham.stern@intel.com>;
> Gabay, Daniel <daniel.gabay@intel.com>; Prabhu, Krishnanand
> <krishnanand.prabhu@intel.com>; Coelho, Luciano <luciano.coelho@intel.com>;
> gregory.greenman@intel.com; stable@vger.kernel.org; Cao, Junjie
> <junjie.cao@intel.com>; Vadim Fedorenko <vadim.fedorenko@linux.dev>
> Subject: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
> 
> iwl_mvm_ptp_remove() calls cancel_delayed_work_sync() only after
> ptp_clock_unregister() and clearing ptp_data state (ptp_clock, ptp_clock_info,
> last_gp2).
> 
> This creates a race where the delayed work iwl_mvm_ptp_work() can execute
> between ptp_clock_unregister() and cancel_delayed_work_sync(), observing
> partially cleared PTP state.

But the work runs under the mvm mutex, and so does iwl_mvm_ptp_remove, so not sure how such a race can happen?
> 
> Move cancel_delayed_work_sync() before ptp_clock_unregister() to ensure the
> delayed work is fully stopped before any PTP cleanup begins.
> 
> Fixes: 1595ecce1cf3 ("wifi: iwlwifi: mvm: add support for PTP HW clock (PHC)")
> Cc: stable@vger.kernel.org
> Reviewed-by: Simon Horman <horms@kernel.org>
> Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
> Signed-off-by: Junjie Cao <junjie.cao@intel.com>
> ---
>  drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> index ad156b82eaa9..efb291ceb0e5 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> @@ -323,11 +323,11 @@ void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
>  			       mvm->ptp_data.ptp_clock_info.name,
>  			       ptp_clock_index(mvm->ptp_data.ptp_clock));
> 
> +		cancel_delayed_work_sync(&mvm->ptp_data.dwork);
>  		ptp_clock_unregister(mvm->ptp_data.ptp_clock);
>  		mvm->ptp_data.ptp_clock = NULL;
>  		memset(&mvm->ptp_data.ptp_clock_info, 0,
>  		       sizeof(mvm->ptp_data.ptp_clock_info));
>  		mvm->ptp_data.last_gp2 = 0;
> -		cancel_delayed_work_sync(&mvm->ptp_data.dwork);
>  	}
>  }
> --
> 2.48.1


^ permalink raw reply

* RE: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
From: Korenblit, Miriam Rachel @ 2026-03-30  6:49 UTC (permalink / raw)
  To: Cao, Junjie, Berg, Johannes, linux-wireless@vger.kernel.org,
	richardcochran@gmail.com
  Cc: horms@kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, yedidya.ben.shimol@intel.com,
	Stern, Avraham, Gabay, Daniel, Prabhu, Krishnanand,
	Coelho, Luciano, gregory.greenman@intel.com,
	stable@vger.kernel.org, Vadim Fedorenko
In-Reply-To: <DM3PPF63A6024A9E6728A0315DC6653D109A352A@DM3PPF63A6024A9.namprd11.prod.outlook.com>



> -----Original Message-----
> From: Korenblit, Miriam Rachel
> Sent: Monday, March 30, 2026 9:44 AM
> To: Cao, Junjie <junjie.cao@intel.com>; Berg, Johannes
> <johannes.berg@intel.com>; linux-wireless@vger.kernel.org;
> richardcochran@gmail.com
> Cc: horms@kernel.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org;
> yedidya.ben.shimol@intel.com; Stern, Avraham <avraham.stern@intel.com>;
> Gabay, Daniel <Daniel.Gabay@intel.com>; Prabhu, Krishnanand
> <krishnanand.prabhu@intel.com>; Coelho, Luciano <luciano.coelho@intel.com>;
> gregory.greenman@intel.com; stable@vger.kernel.org; Vadim Fedorenko
> <vadim.fedorenko@linux.dev>
> Subject: RE: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP removal
> 
> 
> 
> > -----Original Message-----
> > From: Cao, Junjie <junjie.cao@intel.com>
> > Sent: Thursday, February 12, 2026 2:51 PM
> > To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>;
> > Berg, Johannes <johannes.berg@intel.com>;
> > linux-wireless@vger.kernel.org; richardcochran@gmail.com
> > Cc: horms@kernel.org; netdev@vger.kernel.org;
> > linux-kernel@vger.kernel.org; yedidya.ben.shimol@intel.com; Stern,
> > Avraham <avraham.stern@intel.com>; Gabay, Daniel
> > <daniel.gabay@intel.com>; Prabhu, Krishnanand
> > <krishnanand.prabhu@intel.com>; Coelho, Luciano
> > <luciano.coelho@intel.com>; gregory.greenman@intel.com;
> > stable@vger.kernel.org; Cao, Junjie <junjie.cao@intel.com>; Vadim
> > Fedorenko <vadim.fedorenko@linux.dev>
> > Subject: [PATCH v2 1/2] wifi: iwlwifi: mvm: fix race condition in PTP
> > removal
> >
> > iwl_mvm_ptp_remove() calls cancel_delayed_work_sync() only after
> > ptp_clock_unregister() and clearing ptp_data state (ptp_clock,
> > ptp_clock_info, last_gp2).
> >
> > This creates a race where the delayed work iwl_mvm_ptp_work() can
> > execute between ptp_clock_unregister() and cancel_delayed_work_sync(),
> > observing partially cleared PTP state.
> 
> But the work runs under the mvm mutex, and so does iwl_mvm_ptp_remove, so
> not sure how such a race can happen?
Oops, err. It does not run under the mutex. Sorry.
Still note that even with the zeroed data no harm will be done by the worker.

Will apply the patch.
> >
> > Move cancel_delayed_work_sync() before ptp_clock_unregister() to
> > ensure the delayed work is fully stopped before any PTP cleanup begins.
> >
> > Fixes: 1595ecce1cf3 ("wifi: iwlwifi: mvm: add support for PTP HW clock
> > (PHC)")
> > Cc: stable@vger.kernel.org
> > Reviewed-by: Simon Horman <horms@kernel.org>
> > Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
> > Signed-off-by: Junjie Cao <junjie.cao@intel.com>
> > ---
> >  drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > index ad156b82eaa9..efb291ceb0e5 100644
> > --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
> > @@ -323,11 +323,11 @@ void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
> >  			       mvm->ptp_data.ptp_clock_info.name,
> >  			       ptp_clock_index(mvm->ptp_data.ptp_clock));
> >
> > +		cancel_delayed_work_sync(&mvm->ptp_data.dwork);
> >  		ptp_clock_unregister(mvm->ptp_data.ptp_clock);
> >  		mvm->ptp_data.ptp_clock = NULL;
> >  		memset(&mvm->ptp_data.ptp_clock_info, 0,
> >  		       sizeof(mvm->ptp_data.ptp_clock_info));
> >  		mvm->ptp_data.last_gp2 = 0;
> > -		cancel_delayed_work_sync(&mvm->ptp_data.dwork);
> >  	}
> >  }
> > --
> > 2.48.1


^ permalink raw reply

* [PATCH v4] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
From: Kangzheng Gu @ 2026-03-30  6:53 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni, horms, kees, thorsten.blum, arnd,
	sjur.brandeland, xiaoguai0992
  Cc: netdev, linux-kernel, stable
In-Reply-To: <20260329190350.19065-1-xiaoguai0992@gmail.com>

cfctrl_link_setup() copies the RFM volume name from a received control
packet into linkparam.u.rfm.volume until a '\0' is found. A malformed
packet can omit the terminator and make the copy run past the 20-byte
stack buffer.

Stop copying once the buffer is full and mark the frame as failed by
setting CFCTRL_ERR_BIT so the link setup is rejected.

Fixes: b482cd2053e3 ("net-caif: add CAIF core protocol stack")
Cc: stable@vger.kernel.org
Signed-off-by: Kangzheng Gu <xiaoguai0992@gmail.com>
---
 v4:
 - remove the Reported-by.
 - print a warn message and reject link setup by setting CFCTRL_ERR_BIT.
 - using %zu to adapt the compilation of 32-bit kernel.

 net/caif/cfctrl.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index c6cc2bfed65d..373ab1dc67a7 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -416,8 +416,16 @@ static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp
 		cp = (u8 *) linkparam.u.rfm.volume;
 		for (tmp = cfpkt_extr_head_u8(pkt);
 		     cfpkt_more(pkt) && tmp != '\0';
-		     tmp = cfpkt_extr_head_u8(pkt))
+		     tmp = cfpkt_extr_head_u8(pkt)) {
+			if (cp >= (u8 *)linkparam.u.rfm.volume +
+			    sizeof(linkparam.u.rfm.volume) - 1) {
+				pr_warn("Request reject, volume name length exceeds %zu\n",
+					sizeof(linkparam.u.rfm.volume));
+				cmdrsp |= CFCTRL_ERR_BIT;
+				break;
+			}
 			*cp++ = tmp;
+		}
 		*cp = '\0';
 
 		if (CFCTRL_ERR_BIT & cmdrsp)
-- 
2.50.1


^ permalink raw reply related

* Re: [PATCH v2 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-03-30  7:08 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Konrad Dybcio, linux-arm-msm, devicetree, dri-devel, freedreno,
	linux-media, netdev, linux-wireless, ath12k, linux-remoteproc,
	andersson, konradybcio, robh, krzk+dt, conor+dt, robin.clark,
	sean, akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
	airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
	elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
	mathieu.poirier, trilokkumar.soni, mukesh.ojha, pavan.kondeti,
	jorge.ramirez, tonyh, vignesh.viswanathan, srinivas.kandagatla,
	amirreza.zarrabi, jens.wiklander, op-tee, apurupa, skare,
	linux-kernel, Sumit Garg
In-Reply-To: <a0a7269d-7a09-4a78-a4b0-b39b67bc253b@kernel.org>

On Fri, Mar 27, 2026 at 02:56:40PM +0100, Krzysztof Kozlowski wrote:
> On 23/03/2026 15:26, Konrad Dybcio wrote:
> >>>
> >>> This pattern has been carried from the PAS API contract among kernel
> >>> clients and the SCM PAS service earlier. The clients don't hold a
> >>> reference to the PAS data like underlying platform or TEE device etc.
> >>> Hence the need to have a global data pointer to hold reference to the
> >>> ops data structure registered by drivers having different lifetime of
> >>> devices. Also, the PAS APIs can be called from very different client
> >>> driver contexts.
> >>>
> >>> Surely, avoiding global data is always better given a better alternative
> >>> is there. Do you have any better alternative proposal here?
> >>
> >> Why it cannot be part of the context?
> >>
> >> Look at your API, e.g.:
> >> qcom_pas_init_image(). It takes struct qcom_pas_context which should
> >> contain the ops.

Have a look at all other PAS client APIs, the context isn't something
that each client takes a reference and pass it on for every PAS
invocation. And changing the PAS API contract for kernel clients is out
of scope of this patch-set.

> > 
> > This would make the client have to select the ops. The whole point is to
> > avoid that, since the client has no clue (and is supposed not to have any).
> 
> Yeah, I see. The problem is that this patchset just keeps growing the
> singletons so except existing 'struct qcom_scm *__scm' in qcom_scm.c,
> this one brings at least three new: 'ops_ptr', 'qcom_pas_ops_scm' and
> 'qcom_pas_ops_tee'.

Not sure how you equate ops structure __pointer__ to the ops structure
itself. Can you enlighten me how in the rest of the kernel ops data
structures are shared among independent modules registering on different
bus types?

> 
> I don't think you need all four in total, but only one which will hold
> whatever pointers are necessary.

Your arguments seems to be in favour of the existing monolithic SCM
driver design but you need to understand that's not how underlying TZ
services are implemented. The PAS service in TZ has nothing to do with
the ICE service for inline crypto as an example.

Please go through the motivation of this patch-set and the corresponding
OP-TEE implementation as TZ which is all open source.

-Sumit

^ permalink raw reply

* Re: [PATCH net-next v3 1/3] dt-bindings: net: pse-pd: add poll-interval-ms property
From: Krzysztof Kozlowski @ 2026-03-30  7:10 UTC (permalink / raw)
  To: Carlo Szelinsky
  Cc: Oleksij Rempel, Kory Maincent, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
	linux-kernel, linux-leds
In-Reply-To: <20260329153124.2823980-2-github@szelinsky.de>

On Sun, Mar 29, 2026 at 05:31:22PM +0200, Carlo Szelinsky wrote:
> Add the optional poll-interval-ms property for PSE controllers that
> use poll-based event detection instead of interrupts. Defaults to
> 500ms if not specified.

Why?

> 
> Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
> Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
> ---
>  .../devicetree/bindings/net/pse-pd/pse-controller.yaml    | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
> index cd09560e0aea..329d020f054c 100644
> --- a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
> +++ b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
> @@ -27,6 +27,14 @@ properties:
>        subnode. This property is deprecated, please use pse-pis instead.
>      enum: [0, 1]
>  
> +  poll-interval-ms:

We allow poll interval for input devices, because how sensitive buttons
are or what capacitor is there charging/discharging is really a
hardware property of the board.

Why that would be true for PSE controller? Controller is specific, so
any internal aspects of polling are already implied by compatible.

You have entire commit msg to explain WHY you are doing this, not
explain WHAT you did. We see what you did in the diff.

Best regards,
Krzysztof


^ permalink raw reply

* RE: [PATCH net-next v5 00/14] macb usrio/tsu patches
From: Jiawen Wu @ 2026-03-30  7:12 UTC (permalink / raw)
  To: patchwork-bot+netdevbpf, 'Conor Dooley',
	'Conor Dooley'
  Cc: netdev, conor.dooley, Valentina.FernandezAlanis, andrew+netdev,
	davem, edumazet, kuba, pabeni, robh, krzk+dt, conor+dt,
	daire.mcnamara, pjw, palmer, aou, alex, nicolas.ferre,
	claudiu.beznea, richardcochran, samuel.holland, devicetree,
	linux-kernel, linux-riscv, dave.stevenson, sean.anderson,
	vineeth.karumanchi, abin.joseph, theo.lebrun, Ryan.Wanner,
	haokexin, netdev, conor.dooley, Valentina.FernandezAlanis,
	andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
	conor+dt, daire.mcnamara, pjw, palmer, aou, alex, nicolas.ferre,
	claudiu.beznea, richardcochran, samuel.holland, devicetree,
	linux-kernel, linux-riscv, dave.stevenson, sean.anderson,
	vineeth.karumanchi, abin.joseph, theo.lebrun, Ryan.Wanner,
	haokexin
In-Reply-To: <177482042554.472023.12757157452690281696.git-patchwork-notify@kernel.org>

> Hello:
> 
> This series was applied to netdev/net-next.git (main)
> by Jakub Kicinski <kuba@kernel.org>:
> 
> On Wed, 25 Mar 2026 16:28:04 +0000 you wrote:
> > From: Conor Dooley <conor.dooley@microchip.com>
> >
> > Hey folks,
> >
> > At the very least, it'd be good of the soc vendor folks could check
> > their platforms and see if their usrio stuff actually lines up with what
> > the driver currently calls "macb_default_usrio". Ours didn't and it was
> > a nasty surprise.
> >
> > [...]
> 
> Here is the summary with links:
>   - [net-next,v5,01/14] Revert "net: macb: Clean up the .usrio settings in macb_config instances"
>     https://git.kernel.org/netdev/net-next/c/8ccf062c6770
>   - [net-next,v5,02/14] net: macb: rename macb_default_usrio to at91_default_usrio as not all platforms have mii mode control in
> usrio
>     https://git.kernel.org/netdev/net-next/c/a17871778ee2
>   - [net-next,v5,03/14] net: macb: split USRIO_HAS_CLKEN capability in two
>     https://git.kernel.org/netdev/net-next/c/039f185a0060
>   - [net-next,v5,04/14] dt-bindings: net: cdns,macb: replace cdns,refclk-ext with cdns,refclk-source
>     https://git.kernel.org/netdev/net-next/c/dfa36d7e860c
>   - [net-next,v5,05/14] net: macb: rework usrio refclk selection code
>     https://git.kernel.org/netdev/net-next/c/6c5b565d7d41
>   - [net-next,v5,06/14] net: macb: np4 doesn't need a usrio pointer
>     https://git.kernel.org/netdev/net-next/c/826cbe636e10
>   - [net-next,v5,07/14] net: macb: add mpfs specific usrio configuration
>     https://git.kernel.org/netdev/net-next/c/c711311d6ba3
>   - [net-next,v5,08/14] net: macb: warn on pclk use as a tsu_clk fallback
>     https://git.kernel.org/netdev/net-next/c/3fe13d858f83
>   - [net-next,v5,09/14] net: macb: clean up tsu clk rate acquisition
>     https://git.kernel.org/netdev/net-next/c/b698a1e397ab
>   - [net-next,v5,10/14] dt-bindings: net: macb: add property indicating timer adjust mode
>     https://git.kernel.org/netdev/net-next/c/09a6164a4f1d
>   - [net-next,v5,11/14] net: macb: timer adjust mode is not supported
>     https://git.kernel.org/netdev/net-next/c/41adda8764fd
>   - [net-next,v5,12/14] net: macb: runtime detect MACB_CAPS_USRIO_DISABLED
>     https://git.kernel.org/netdev/net-next/c/47c86c463612
>   - [net-next,v5,13/14] net: macb: set MACB_CAPS_USRIO_DISABLED if no usrio config is provided
>     https://git.kernel.org/netdev/net-next/c/32fc6a9f6e75
>   - [net-next,v5,14/14] net: macb: drop usrio pointer on EyeQ5 config
>     https://git.kernel.org/netdev/net-next/c/cd1082a96f9a
> 
> You are awesome, thank you!
> --
> Deet-doot-dot, I am a bot.
> https://korg.docs.kernel.org/patchwork/pwbot.html

Hi,

There are compilation errors after merging this patch set.
I believe the error occurred where the CONFIG_OF is not set.

root@w-MS-7E16:~/net-next# make C=1 W=1
  CALL    scripts/checksyscalls.sh
  DESCEND objtool
  INSTALL libsubcmd_headers
  CC [M]  drivers/net/ethernet/cadence/macb_main.o
drivers/net/ethernet/cadence/macb_main.c:5755:19: error: ‘at91_default_usrio’ undeclared here (not in a function)
 5755 |         .usrio = &at91_default_usrio,
      |                   ^~~~~~~~~~~~~~~~~~
make[6]: *** [scripts/Makefile.build:289: drivers/net/ethernet/cadence/macb_main.o] Error 1
make[5]: *** [scripts/Makefile.build:548: drivers/net/ethernet/cadence] Error 2
make[4]: *** [scripts/Makefile.build:548: drivers/net/ethernet] Error 2
make[3]: *** [scripts/Makefile.build:548: drivers/net] Error 2
make[2]: *** [scripts/Makefile.build:548: drivers] Error 2
make[1]: *** [/root/net-next/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2


^ permalink raw reply


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