* [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats
@ 2026-10-21 10:04 SAYANTAN NANDY
2026-10-21 12:48 ` Andrew Lunn
2026-10-25 11:40 ` netdev-bot+sashiko
0 siblings, 2 replies; 6+ messages in thread
From: SAYANTAN NANDY @ 2026-10-21 10:04 UTC (permalink / raw)
To: netdev; +Cc: lorenzo, andrew, Chad Monroe, SAYANTAN NANDY
From: Chad Monroe <chad@monroe.io>
With flow stats enabled, PPE offload setup requests flow statistics
from the NPU. If the running NPU firmware does not support flow
counters, the request fails and the current setup path aborts PPE
offload.
Treat flow statistics as an optional capability so that a failure to
set up the counters does not prevent normal PPE offload. Continue PPE
initialization when the NPU refuses the flow-statistics request.
Also treat a zero NPU statistics address returned by the firmware as a
refusal. The host-side DMA buffer (foe_stats_dma) is allocated by
dmam_alloc_coherent() in airoha_ppe_init() from system memory. The NPU
statistics address (npu_stats_addr) is a separate allocation from the
NPU firmware's internal SRAM pool. When that pool is exhausted, the
firmware replies with success and npu_stats_addr = 0. A zero address
does not provide a usable counter region and must not be passed to
devm_ioremap().
When flow stats entries are available, clear PSE_PORT6_SHARE_DIS so
that PSE port 6 (CDM3 path to the NPU) participates in shared-buffer
flow control. PSE_FC_CFG bits 26:16 control per-port whether flow
control considers the shared buffer pool. Bit 22 is port 6.
When flow statistics are unavailable, PPE continues to operate without
NPU flow counters while retaining normal offload functionality.
This combines the original SmartRG/Airoha fixes for:
- keeping PPE offload active when the NPU refuses flow statistics
- treating a zero NPU statistics address as a flow-statistics refusal
Add NULL checks on npu->stats so that stats reset, stats reads, and flow
updates do not dereference a NULL pointer when the NPU refuses to
allocate the counter region. Avoid redirecting flows to the NPU when
flow counters are unavailable.
Clear npu->stats at the start of airoha_npu_ppe_stats_setup() so that a
stale mapping from a previous setup does not persist after a refusal on
rebind.
Based on the original SmartRG/Airoha work by Chad Monroe:
5ce96ab ("SDG-9458: keep PPE offload when NPU refuses flow stats")
0ad8528 ("SDG-9458: airoha: treat a zero NPU stats address as a refusal")
Fixes: b81e0f2b58be ("net: airoha: Add FLOW_CLS_STATS callback support")
Tested-on: AN7581 with MT7992
Signed-off-by: Chad Monroe <chad@monroe.io>
Signed-off-by: SAYANTAN NANDY <sayantann11@gmail.com>
---
Changes since v3:
- Add NULL checks on npu->stats to prevent NULL pointer dereferences
and avoid flow misrouting when the NPU refuses stats (sashiko).
- Clear npu->stats at the start of stats setup to prevent stale
mappings on rebind (sashiko).
- Move PSE_FC_CFG and PSE_PORT6_SHARE_DIS to preserve register
address ordering (sashiko).
Changes since v2:
- Drop flow_stats_cap flag entirely (Lorenzo).
- Keep airoha_ppe_get_num_stats_entries() unchanged (Lorenzo).
- Guard airoha_fe_clear() with sram_num_stats_entries > 0 (Lorenzo).
- Replace error assignment and goto with a direct check and dev_warn.
Changes since v1:
- Explain that npu_stats_addr is an NPU firmware SRAM allocation,
distinct from the host-side foe_stats_dma buffer (Lorenzo).
- Use airoha_fe_clear() and shorten the warning message (Lorenzo).
- Add hardware testing information requested by netdev-bot.
drivers/net/ethernet/airoha/airoha_npu.c | 10 ++++++++++
drivers/net/ethernet/airoha/airoha_ppe.c | 18 +++++++++++++-----
drivers/net/ethernet/airoha/airoha_regs.h | 3 +++
3 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
index 4d3195eb00f7..42d48a4fab4c 100644
--- a/drivers/net/ethernet/airoha/airoha_npu.c
+++ b/drivers/net/ethernet/airoha/airoha_npu.c
@@ -441,6 +441,8 @@ static int airoha_npu_ppe_stats_setup(struct airoha_npu *npu,
if (!ppe_data)
return -ENOMEM;
+ npu->stats = NULL;
+
ppe_data->func_type = NPU_OP_SET;
ppe_data->func_id = PPE_FUNC_SET_WAIT_FLOW_STATS_SETUP;
ppe_data->stats_info.foe_stats_addr = foe_stats_addr;
@@ -450,6 +452,14 @@ static int airoha_npu_ppe_stats_setup(struct airoha_npu *npu,
if (err)
goto out;
+ /* The firmware reports success with a zero address when its SRAM
+ * pool has no room left for the counters.
+ */
+ if (!ppe_data->stats_info.npu_stats_addr) {
+ err = -ENOSPC;
+ goto out;
+ }
+
npu->stats = devm_ioremap(npu->dev,
ppe_data->stats_info.npu_stats_addr,
size);
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 92611802801e..3147655e8ecc 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -144,6 +144,9 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
sram_ppe_num_data_entries =
PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries);
+ if (sram_num_stats_entries > 0)
+ airoha_fe_clear(eth, PSE_FC_CFG, PSE_PORT6_SHARE_DIS);
+
for (i = 0; i < eth->soc->num_ppe; i++) {
airoha_fe_wr(eth, REG_PPE_TB_BASE(i),
ppe->foe_dma + sram_tb_size);
@@ -613,6 +616,9 @@ static void airoha_ppe_foe_flow_stat_entry_reset(struct airoha_ppe *ppe,
struct airoha_npu *npu,
int index)
{
+ if (!npu->stats)
+ return;
+
memset_io(&npu->stats[index], 0, sizeof(*npu->stats));
memset(&ppe->foe_stats[index], 0, sizeof(*ppe->foe_stats));
}
@@ -644,6 +650,9 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe,
if (ppe_num_stats_entries < 0)
return;
+ if (!npu->stats)
+ return;
+
if (airoha_ppe_foe_get_flow_stats_index(ppe, hash, &index))
return;
@@ -1324,7 +1333,7 @@ void airoha_ppe_foe_entry_get_stats(struct airoha_ppe *ppe, u32 hash,
rcu_read_lock();
npu = rcu_dereference(eth->npu);
- if (npu) {
+ if (npu && npu->stats) {
u64 packets = ppe->foe_stats[index].packets;
u64 bytes = ppe->foe_stats[index].bytes;
struct airoha_foe_stats npu_stats;
@@ -1454,10 +1463,9 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth)
ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe);
if (ppe_num_stats_entries > 0) {
- err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,
- ppe_num_stats_entries);
- if (err)
- goto error_npu_put;
+ if (npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,
+ ppe_num_stats_entries))
+ dev_warn(eth->dev, "NPU refused flow stats\n");
}
airoha_ppe_hw_init(ppe);
diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
index 442b48c9b991..1e949fa4407d 100644
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -82,6 +82,9 @@
#define PSE_SHARE_USED_MTHD_MASK GENMASK(31, 16)
#define PSE_SHARE_USED_HTHD_MASK GENMASK(15, 0)
+#define PSE_FC_CFG 0x0098
+#define PSE_PORT6_SHARE_DIS BIT(22)
+
#define REG_GDM_MISC_CFG 0x0148
#define GDM2_RDM_ACK_WAIT_PREF_MASK BIT(9)
#define GDM2_CHN_VLD_MODE_MASK BIT(5)
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats
2026-10-21 10:04 [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats SAYANTAN NANDY
@ 2026-10-21 12:48 ` Andrew Lunn
2026-10-25 15:25 ` Chad Monroe
2026-10-25 11:40 ` netdev-bot+sashiko
1 sibling, 1 reply; 6+ messages in thread
From: Andrew Lunn @ 2026-10-21 12:48 UTC (permalink / raw)
To: SAYANTAN NANDY; +Cc: netdev, lorenzo, Chad Monroe
On Wed, Oct 21, 2026 at 03:34:23PM +0530, SAYANTAN NANDY wrote:
> From: Chad Monroe <chad@monroe.io>
>
> With flow stats enabled, PPE offload setup requests flow statistics
> from the NPU. If the running NPU firmware does not support flow
> counters, the request fails and the current setup path aborts PPE
> offload.
Since this never worked, it is not a regression fix.
Why not keep it KISS and report the firmware is too old and suggest
the firmware is updated?
Can the driver do the firmware upgrade?
Andrew
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats
2026-10-21 12:48 ` Andrew Lunn
@ 2026-10-25 15:25 ` Chad Monroe
2026-10-25 22:52 ` Andrew Lunn
0 siblings, 1 reply; 6+ messages in thread
From: Chad Monroe @ 2026-10-25 15:25 UTC (permalink / raw)
To: Andrew Lunn; +Cc: SAYANTAN NANDY, netdev, lorenzo
On Wednesday, October 21st, 2026 at 5:49 AM, Andrew Lunn <andrew@lunn.ch> wrote:
> On Wed, Oct 21, 2026 at 03:34:23PM +0530, SAYANTAN NANDY wrote:
> > From: Chad Monroe <chad@monroe.io>
> >
> > With flow stats enabled, PPE offload setup requests flow statistics
> > from the NPU. If the running NPU firmware does not support flow
> > counters, the request fails and the current setup path aborts PPE
> > offload.
>
> Since this never worked, it is not a regression fix.
>
> Why not keep it KISS and report the firmware is too old and suggest
> the firmware is updated?
>
> Can the driver do the firmware upgrade?
>
> Andrew
>
Hi Andrew,
The NPU firmware bin is downloaded at each boot and is present in
linux-firmware so no issue with keeping it up to date.
The main reason for this change is to behave better when flags mismatch.
Previously, loading a driver compiled with flow stats support enabled
would silently fail to offload if the firmware didn't have support.
I did not like this blind failure so figured it would be better to
check what the firmware supports. If flow stats support is not present
in the firmware at least we can still do offloading.
The main question is whether Airoha will release variants of firmware
with flow stats support disabled in the future, or if this flag will
always remain enabled. If it's just an issue of old firmware (all new
version will support it) then report + failure is sufficient.
Thanks,
-Chad
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats
2026-10-25 15:25 ` Chad Monroe
@ 2026-10-25 22:52 ` Andrew Lunn
2026-10-26 7:31 ` Lorenzo Bianconi
0 siblings, 1 reply; 6+ messages in thread
From: Andrew Lunn @ 2026-10-25 22:52 UTC (permalink / raw)
To: Chad Monroe; +Cc: SAYANTAN NANDY, netdev, lorenzo
On Sun, Oct 25, 2026 at 03:25:28PM +0000, Chad Monroe wrote:
> On Wednesday, October 21st, 2026 at 5:49 AM, Andrew Lunn <andrew@lunn.ch> wrote:
>
> > On Wed, Oct 21, 2026 at 03:34:23PM +0530, SAYANTAN NANDY wrote:
> > > From: Chad Monroe <chad@monroe.io>
> > >
> > > With flow stats enabled, PPE offload setup requests flow statistics
> > > from the NPU. If the running NPU firmware does not support flow
> > > counters, the request fails and the current setup path aborts PPE
> > > offload.
> >
> > Since this never worked, it is not a regression fix.
> >
> > Why not keep it KISS and report the firmware is too old and suggest
> > the firmware is updated?
> >
> > Can the driver do the firmware upgrade?
> >
> > Andrew
> >
>
> Hi Andrew,
>
> The NPU firmware bin is downloaded at each boot and is present in
> linux-firmware so no issue with keeping it up to date.
>
> The main reason for this change is to behave better when flags mismatch.
> Previously, loading a driver compiled with flow stats support enabled
> would silently fail to offload if the firmware didn't have support.
Sayantan suggested this is a regression. It used to work, but does not
now?
We should avoid regressions.
Andrew
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats
2026-10-25 22:52 ` Andrew Lunn
@ 2026-10-26 7:31 ` Lorenzo Bianconi
0 siblings, 0 replies; 6+ messages in thread
From: Lorenzo Bianconi @ 2026-10-26 7:31 UTC (permalink / raw)
To: Andrew Lunn; +Cc: Chad Monroe, SAYANTAN NANDY, netdev
[-- Attachment #1: Type: text/plain, Size: 1511 bytes --]
> On Sun, Oct 25, 2026 at 03:25:28PM +0000, Chad Monroe wrote:
> > On Wednesday, October 21st, 2026 at 5:49 AM, Andrew Lunn <andrew@lunn.ch> wrote:
> >
> > > On Wed, Oct 21, 2026 at 03:34:23PM +0530, SAYANTAN NANDY wrote:
> > > > From: Chad Monroe <chad@monroe.io>
> > > >
> > > > With flow stats enabled, PPE offload setup requests flow statistics
> > > > from the NPU. If the running NPU firmware does not support flow
> > > > counters, the request fails and the current setup path aborts PPE
> > > > offload.
> > >
> > > Since this never worked, it is not a regression fix.
> > >
> > > Why not keep it KISS and report the firmware is too old and suggest
> > > the firmware is updated?
> > >
> > > Can the driver do the firmware upgrade?
> > >
> > > Andrew
> > >
> >
> > Hi Andrew,
> >
> > The NPU firmware bin is downloaded at each boot and is present in
> > linux-firmware so no issue with keeping it up to date.
> >
> > The main reason for this change is to behave better when flags mismatch.
> > Previously, loading a driver compiled with flow stats support enabled
> > would silently fail to offload if the firmware didn't have support.
>
> Sayantan suggested this is a regression. It used to work, but does not
> now?
>
> We should avoid regressions.
I do not think this is a regression. In this case, the default behaviour is
just fall-back to sw flowtable acceleration.
@sayantan: can you please confirm?
Regards,
Lorenzo
>
> Andrew
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats
2026-10-21 10:04 [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats SAYANTAN NANDY
2026-10-21 12:48 ` Andrew Lunn
@ 2026-10-25 11:40 ` netdev-bot+sashiko
1 sibling, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-10-25 11:40 UTC (permalink / raw)
To: sayantann11; +Cc: netdev, lorenzo, andrew, chad, kuba
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 (1) · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] In airoha_npu_ppe_stats_setup()
(drivers/net/ethernet/airoha/airoha_npu.c), the new `npu->stats =…
- [Low] airoha_ppe_offload_setup() ignores every error from
ppe_init_stats() and prints the same `dev_warn(eth->dev, "NPU refused…
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but each
successful airoha_npu_ppe_stats_setup() creates a new…
--
net: airoha: keep PPE offload when NPU refuses flow stats
With this patch, NPU flow statistics are optional. PPE offload setup now
continues when ppe_init_stats() fails, and a zero npu_stats_addr from the
firmware counts as a refusal. It also adds NULL checks on npu->stats,
clears npu->stats at the start of airoha_npu_ppe_stats_setup(), and clears
PSE_PORT6_SHARE_DIS when flow stats entries are configured.
> diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
> index 4d3195eb00f7a..42d48a4fab4ce 100644
> --- a/drivers/net/ethernet/airoha/airoha_npu.c
> +++ b/drivers/net/ethernet/airoha/airoha_npu.c
> @@ -441,6 +441,8 @@ static int airoha_npu_ppe_stats_setup(struct airoha_npu *npu,
> if (!ppe_data)
> return -ENOMEM;
>
> + npu->stats = NULL;
> +
[Severity: Medium]
Should this clear come before the kzalloc_obj() check?
If the GFP_ATOMIC allocation of ppe_data fails, the function returns
-ENOMEM before npu->stats is reset. Any mapping from an earlier bind is
left in place.
struct airoha_npu belongs to the NPU device, which stays bound when the
eth driver unbinds. airoha_ppe_deinit() does not reset npu->stats:
airoha_ppe_deinit() {
...
if (npu) {
synchronize_rcu();
npu->ops.ppe_deinit(npu);
airoha_npu_put(npu);
}
...
}
Before this patch, any ppe_init_stats() error aborted
airoha_ppe_offload_setup(). Now it only warns and then calls
airoha_ppe_hw_init(), airoha_ppe_foe_flow_stats_reset() and
rcu_assign_pointer().
Suppose the eth driver is unbound and rebound, and this allocation then
fails. Would the stale pointer get past all the new !npu->stats checks?
If so, airoha_ppe_foe_flow_stats_reset() would memset_io() the old region.
airoha_ppe_foe_flow_stats_update() would rewrite ib2 to send bound flows
to PSE port 6. airoha_ppe_foe_entry_get_stats() would read the old
counters.
In this bind, PPE_FUNC_SET_WAIT_FLOW_STATS_SETUP would never have been sent
with ppe->foe_stats_dma. It's not clear what the firmware then does with
the port 6 traffic, or with the old foe_stats_addr from the previous bind.
The commit message says:
Clear npu->stats at the start of airoha_npu_ppe_stats_setup() so that a
stale mapping from a previous setup does not persist after a refusal on
rebind.
This error path, which the patch makes non-fatal, still seems to leave the
stale mapping in place. Could the clear move above the allocation? Or
could airoha_ppe_offload_setup() clear npu->stats on any error?
> @@ -450,6 +452,14 @@ static int airoha_npu_ppe_stats_setup(struct airoha_npu *npu,
> if (err)
> goto out;
>
> + /* The firmware reports success with a zero address when its SRAM
> + * pool has no room left for the counters.
> + */
> + if (!ppe_data->stats_info.npu_stats_addr) {
> + err = -ENOSPC;
> + goto out;
> + }
> +
> npu->stats = devm_ioremap(npu->dev,
> ppe_data->stats_info.npu_stats_addr,
> size);
[Severity: Medium]
This is a pre-existing issue and was not introduced by this patch. Does
each successful setup leak the previous devm_ioremap() mapping?
The mapping is attached to npu->dev, which outlives eth driver binds.
airoha_ppe_deinit() doesn't unmap npu->stats. The new npu->stats = NULL
only drops the pointer.
So each eth unbind/rebind that sets up stats again leaves the old mapping
on the NPU device's devres list. It stays there until the NPU device
itself unbinds.
The old code leaked in the same way when it overwrote the pointer, so
this patch doesn't add a new leak.
Should the old region be released with devm_iounmap(), either here or
during PPE teardown?
> diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
> index 92611802801ea..3147655e8ecc4 100644
> --- a/drivers/net/ethernet/airoha/airoha_ppe.c
> +++ b/drivers/net/ethernet/airoha/airoha_ppe.c
[ ... ]
> @@ -1454,10 +1463,9 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth)
>
> ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe);
> if (ppe_num_stats_entries > 0) {
> - err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,
> - ppe_num_stats_entries);
> - if (err)
> - goto error_npu_put;
> + if (npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,
> + ppe_num_stats_entries))
> + dev_warn(eth->dev, "NPU refused flow stats\n");
[Severity: Low]
Could this warning include the error code?
airoha_npu_ppe_stats_setup() can fail with any of these:
-ENOMEM from kzalloc or devm_ioremap()
an error from dma_mapping_error()
-ETIMEDOUT from regmap_read_poll_timeout_atomic() in
airoha_npu_send_msg()
-EINVAL when the firmware status isn't NPU_MBOX_SUCCESS
the new -ENOSPC
Only -EINVAL and -ENOSPC are actual firmware refusals. Allocation failures
and mailbox timeouts are also logged as "NPU refused flow stats", and the
errno is dropped. That makes it hard to tell missing firmware support
apart from an unresponsive NPU or memory pressure.
The commit message says continuing on any error is intended, so this is
only about the log message.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261021100423.9159-1-sayantann11%40gmail.com
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-26 7:31 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-21 10:04 [PATCH net v4] net: airoha: keep PPE offload when NPU refuses flow stats SAYANTAN NANDY
2026-10-21 12:48 ` Andrew Lunn
2026-10-25 15:25 ` Chad Monroe
2026-10-25 22:52 ` Andrew Lunn
2026-10-26 7:31 ` Lorenzo Bianconi
2026-10-25 11:40 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox