From: Chad Monroe 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 Signed-off-by: SAYANTAN NANDY --- 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