Skip to content

Commit 1b9922d

Browse files
committed
airoha: backport fixes merged in net upstream tree
Airoha reported some bug in the TX/RX descriptor handling and PPE. Backport the fix for such bug merged in net staging tree. It's expected that these patch will be dropped in future minor kernel version when submitted to stable staging tree. All affected patch automatically refreshed. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
1 parent 4ca22b1 commit 1b9922d

16 files changed

Lines changed: 771 additions & 23 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
From f329924bb49458c65297f1361f545816a5b90998 Mon Sep 17 00:00:00 2001
2+
From: Lorenzo Bianconi <lorenzo@kernel.org>
3+
Date: Fri, 17 Apr 2026 08:36:31 +0200
4+
Subject: [PATCH 1/2] net: airoha: Move ndesc initialization at end of
5+
airoha_qdma_init_tx()
6+
7+
If queue entry list allocation fails in airoha_qdma_init_tx_queue routine,
8+
airoha_qdma_cleanup_tx_queue() will trigger a NULL pointer dereference
9+
accessing the queue entry array. The issue is due to the early ndesc
10+
initialization in airoha_qdma_init_tx_queue(). Fix the issue moving ndesc
11+
initialization at end of airoha_qdma_init_tx routine.
12+
13+
Fixes: 3f47e67dff1f7 ("net: airoha: Add the capability to consume out-of-order DMA tx descriptors")
14+
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
15+
Link: https://patch.msgid.link/20260417-airoha_qdma_cleanup_tx_queue-fix-net-v4-1-e04bcc2c9642@kernel.org
16+
Reviewed-by: Simon Horman <horms@kernel.org>
17+
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
18+
---
19+
drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++----
20+
1 file changed, 4 insertions(+), 4 deletions(-)
21+
22+
--- a/drivers/net/ethernet/airoha/airoha_eth.c
23+
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
24+
@@ -954,27 +954,27 @@ static int airoha_qdma_init_tx_queue(str
25+
dma_addr_t dma_addr;
26+
27+
spin_lock_init(&q->lock);
28+
- q->ndesc = size;
29+
q->qdma = qdma;
30+
q->free_thr = 1 + MAX_SKB_FRAGS;
31+
INIT_LIST_HEAD(&q->tx_list);
32+
33+
- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry),
34+
+ q->entry = devm_kzalloc(eth->dev, size * sizeof(*q->entry),
35+
GFP_KERNEL);
36+
if (!q->entry)
37+
return -ENOMEM;
38+
39+
- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc),
40+
+ q->desc = dmam_alloc_coherent(eth->dev, size * sizeof(*q->desc),
41+
&dma_addr, GFP_KERNEL);
42+
if (!q->desc)
43+
return -ENOMEM;
44+
45+
- for (i = 0; i < q->ndesc; i++) {
46+
+ for (i = 0; i < size; i++) {
47+
u32 val = FIELD_PREP(QDMA_DESC_DONE_MASK, 1);
48+
49+
list_add_tail(&q->entry[i].list, &q->tx_list);
50+
WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val));
51+
}
52+
+ q->ndesc = size;
53+
54+
/* xmit ring drop default setting */
55+
airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(qid),
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
From 3309965fe44c00fd65af7cef5016e9e782c021a7 Mon Sep 17 00:00:00 2001
2+
From: Lorenzo Bianconi <lorenzo@kernel.org>
3+
Date: Fri, 17 Apr 2026 08:36:32 +0200
4+
Subject: [PATCH 2/2] net: airoha: Add missing bits in
5+
airoha_qdma_cleanup_tx_queue()
6+
7+
Similar to airoha_qdma_cleanup_rx_queue(), reset DMA TX descriptors in
8+
airoha_qdma_cleanup_tx_queue routine. Moreover, reset TX_DMA_IDX to
9+
TX_CPU_IDX to notify the NIC the QDMA TX ring is empty.
10+
11+
Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
12+
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
13+
Link: https://patch.msgid.link/20260417-airoha_qdma_cleanup_tx_queue-fix-net-v4-2-e04bcc2c9642@kernel.org
14+
Reviewed-by: Simon Horman <horms@kernel.org>
15+
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
16+
---
17+
drivers/net/ethernet/airoha/airoha_eth.c | 32 ++++++++++++++++++++++--
18+
1 file changed, 30 insertions(+), 2 deletions(-)
19+
20+
--- a/drivers/net/ethernet/airoha/airoha_eth.c
21+
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
22+
@@ -1039,12 +1039,15 @@ static int airoha_qdma_init_tx(struct ai
23+
24+
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
25+
{
26+
- struct airoha_eth *eth = q->qdma->eth;
27+
- int i;
28+
+ struct airoha_qdma *qdma = q->qdma;
29+
+ struct airoha_eth *eth = qdma->eth;
30+
+ int i, qid = q - &qdma->q_tx[0];
31+
+ u16 index = 0;
32+
33+
spin_lock_bh(&q->lock);
34+
for (i = 0; i < q->ndesc; i++) {
35+
struct airoha_queue_entry *e = &q->entry[i];
36+
+ struct airoha_qdma_desc *desc = &q->desc[i];
37+
38+
if (!e->dma_addr)
39+
continue;
40+
@@ -1055,8 +1058,33 @@ static void airoha_qdma_cleanup_tx_queue
41+
e->dma_addr = 0;
42+
e->skb = NULL;
43+
list_add_tail(&e->list, &q->tx_list);
44+
+
45+
+ /* Reset DMA descriptor */
46+
+ WRITE_ONCE(desc->ctrl, 0);
47+
+ WRITE_ONCE(desc->addr, 0);
48+
+ WRITE_ONCE(desc->data, 0);
49+
+ WRITE_ONCE(desc->msg0, 0);
50+
+ WRITE_ONCE(desc->msg1, 0);
51+
+ WRITE_ONCE(desc->msg2, 0);
52+
+
53+
q->queued--;
54+
}
55+
+
56+
+ if (!list_empty(&q->tx_list)) {
57+
+ struct airoha_queue_entry *e;
58+
+
59+
+ e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
60+
+ list);
61+
+ index = e - q->entry;
62+
+ }
63+
+ /* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is
64+
+ * empty.
65+
+ */
66+
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
67+
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
68+
+ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
69+
+ FIELD_PREP(TX_RING_DMA_IDX_MASK, index));
70+
+
71+
spin_unlock_bh(&q->lock);
72+
}
73+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
From f3206328bb52c2787197d80d7cbd687946047d5f Mon Sep 17 00:00:00 2001
2+
From: Lorenzo Bianconi <lorenzo@kernel.org>
3+
Date: Tue, 14 Apr 2026 16:08:52 +0200
4+
Subject: [PATCH] net: airoha: Wait for NPU PPE configuration to complete in
5+
airoha_ppe_offload_setup()
6+
7+
In order to properly enable flowtable hw offloading, poll
8+
REG_PPE_FLOW_CFG register in airoha_ppe_offload_setup routine and
9+
wait for NPU PPE configuration triggered by ppe_init callback to complete
10+
before running airoha_ppe_hw_init().
11+
12+
Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support")
13+
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
14+
Link: https://patch.msgid.link/20260414-airoha-wait-for-npu-config-offload-setup-v2-1-5a9bf6d43aee@kernel.org
15+
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
16+
---
17+
drivers/net/ethernet/airoha/airoha_ppe.c | 28 ++++++++++++++++++++++++
18+
1 file changed, 28 insertions(+)
19+
20+
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
21+
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
22+
@@ -1354,6 +1354,29 @@ static struct airoha_npu *airoha_ppe_npu
23+
return npu;
24+
}
25+
26+
+static int airoha_ppe_wait_for_npu_init(struct airoha_eth *eth)
27+
+{
28+
+ int err;
29+
+ u32 val;
30+
+
31+
+ /* PPE_FLOW_CFG default register value is 0. Since we reset FE
32+
+ * during the device probe we can just check the configured value
33+
+ * is not 0 here.
34+
+ */
35+
+ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,
36+
+ 100 * USEC_PER_MSEC, false, eth,
37+
+ REG_PPE_PPE_FLOW_CFG(0));
38+
+ if (err)
39+
+ return err;
40+
+
41+
+ if (airoha_ppe_is_enabled(eth, 1))
42+
+ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC,
43+
+ 100 * USEC_PER_MSEC, false, eth,
44+
+ REG_PPE_PPE_FLOW_CFG(1));
45+
+
46+
+ return err;
47+
+}
48+
+
49+
static int airoha_ppe_offload_setup(struct airoha_eth *eth)
50+
{
51+
struct airoha_npu *npu = airoha_ppe_npu_get(eth);
52+
@@ -1367,6 +1390,11 @@ static int airoha_ppe_offload_setup(stru
53+
if (err)
54+
goto error_npu_put;
55+
56+
+ /* Wait for NPU PPE configuration to complete */
57+
+ err = airoha_ppe_wait_for_npu_init(eth);
58+
+ if (err)
59+
+ goto error_npu_put;
60+
+
61+
ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe);
62+
if (ppe_num_stats_entries > 0) {
63+
err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma,
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
From d647f2545219754603b2064de948425cdfd93fba Mon Sep 17 00:00:00 2001
2+
From: Lorenzo Bianconi <lorenzo@kernel.org>
3+
Date: Fri, 17 Apr 2026 17:24:41 +0200
4+
Subject: [PATCH] net: airoha: Fix PPE cpu port configuration for GDM2 loopback
5+
path
6+
7+
When QoS loopback is enabled for GDM3 or GDM4, incoming packets are
8+
forwarded to GDM2. However, the PPE cpu port for GDM2 is not configured
9+
in this path, causing traffic originating from GDM3/GDM4, which may
10+
be set up as WAN ports backed by QDMA1, to be incorrectly directed
11+
to QDMA0 instead.
12+
Configure the PPE cpu port for GDM2 when QoS loopback is active on
13+
GDM3 or GDM4 to ensure traffic is routed to the correct QDMA instance.
14+
15+
Fixes: 9cd451d414f6 ("net: airoha: Add loopback support for GDM2")
16+
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
17+
Link: https://patch.msgid.link/20260417-airoha-ppe-cpu-port-for-gdm2-loopback-v1-1-c7a9de0f6f57@kernel.org
18+
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
19+
---
20+
drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++++--
21+
drivers/net/ethernet/airoha/airoha_eth.h | 3 ++-
22+
drivers/net/ethernet/airoha/airoha_ppe.c | 6 +++---
23+
3 files changed, 11 insertions(+), 6 deletions(-)
24+
25+
--- a/drivers/net/ethernet/airoha/airoha_eth.c
26+
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
27+
@@ -1755,7 +1755,7 @@ static int airoha_set_gdm2_loopback(stru
28+
{
29+
struct airoha_eth *eth = port->qdma->eth;
30+
u32 val, pse_port, chan;
31+
- int src_port;
32+
+ int i, src_port;
33+
34+
/* Forward the traffic to the proper GDM port */
35+
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
36+
@@ -1797,6 +1797,9 @@ static int airoha_set_gdm2_loopback(stru
37+
SP_CPORT_MASK(val),
38+
__field_prep(SP_CPORT_MASK(val), FE_PSE_PORT_CDM2));
39+
40+
+ for (i = 0; i < eth->soc->num_ppe; i++)
41+
+ airoha_ppe_set_cpu_port(port, i, AIROHA_GDM2_IDX);
42+
+
43+
if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) {
44+
u32 mask = FC_ID_OF_SRC_PORT_MASK(port->nbq);
45+
46+
@@ -1835,7 +1838,8 @@ static int airoha_dev_init(struct net_de
47+
}
48+
49+
for (i = 0; i < eth->soc->num_ppe; i++)
50+
- airoha_ppe_set_cpu_port(port, i);
51+
+ airoha_ppe_set_cpu_port(port, i,
52+
+ airoha_get_fe_port(port));
53+
54+
return 0;
55+
}
56+
--- a/drivers/net/ethernet/airoha/airoha_eth.h
57+
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
58+
@@ -653,7 +653,8 @@ int airoha_get_fe_port(struct airoha_gdm
59+
bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
60+
struct airoha_gdm_port *port);
61+
62+
-void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id);
63+
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id,
64+
+ u8 fport);
65+
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
66+
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
67+
u16 hash, bool rx_wlan);
68+
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
69+
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
70+
@@ -85,10 +85,9 @@ static u32 airoha_ppe_get_timestamp(stru
71+
return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp);
72+
}
73+
74+
-void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id)
75+
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, u8 fport)
76+
{
77+
struct airoha_qdma *qdma = port->qdma;
78+
- u8 fport = airoha_get_fe_port(port);
79+
struct airoha_eth *eth = qdma->eth;
80+
u8 qdma_id = qdma - &eth->qdma[0];
81+
u32 fe_cpu_port;
82+
@@ -182,7 +181,8 @@ static void airoha_ppe_hw_init(struct ai
83+
if (!port)
84+
continue;
85+
86+
- airoha_ppe_set_cpu_port(port, i);
87+
+ airoha_ppe_set_cpu_port(port, i,
88+
+ airoha_get_fe_port(port));
89+
}
90+
}
91+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
From b94769eb2f30e61e86cd8551c084c34134290d89 Mon Sep 17 00:00:00 2001
2+
From: Lorenzo Bianconi <lorenzo@kernel.org>
3+
Date: Thu, 16 Apr 2026 12:30:12 +0200
4+
Subject: [PATCH] net: airoha: Fix possible TX queue stall in
5+
airoha_qdma_tx_napi_poll()
6+
7+
Since multiple net_device TX queues can share the same hw QDMA TX queue,
8+
there is no guarantee we have inflight packets queued in hw belonging to a
9+
net_device TX queue stopped in the xmit path because hw QDMA TX queue
10+
can be full. In this corner case the net_device TX queue will never be
11+
re-activated. In order to avoid any potential net_device TX queue stall,
12+
we need to wake all the net_device TX queues feeding the same hw QDMA TX
13+
queue in airoha_qdma_tx_napi_poll routine.
14+
15+
Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
16+
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
17+
Reviewed-by: Simon Horman <horms@kernel.org>
18+
Link: https://patch.msgid.link/20260416-airoha-txq-potential-stall-v2-1-42c732074540@kernel.org
19+
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
20+
---
21+
drivers/net/ethernet/airoha/airoha_eth.c | 37 ++++++++++++++++++++----
22+
drivers/net/ethernet/airoha/airoha_eth.h | 1 +
23+
2 files changed, 33 insertions(+), 5 deletions(-)
24+
25+
--- a/drivers/net/ethernet/airoha/airoha_eth.c
26+
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
27+
@@ -843,6 +843,21 @@ static int airoha_qdma_init_rx(struct ai
28+
return 0;
29+
}
30+
31+
+static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
32+
+{
33+
+ struct airoha_qdma *qdma = q->qdma;
34+
+ struct airoha_eth *eth = qdma->eth;
35+
+ int i;
36+
+
37+
+ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
38+
+ struct airoha_gdm_port *port = eth->ports[i];
39+
+
40+
+ if (port && port->qdma == qdma)
41+
+ netif_tx_wake_all_queues(port->dev);
42+
+ }
43+
+ q->txq_stopped = false;
44+
+}
45+
+
46+
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
47+
{
48+
struct airoha_tx_irq_queue *irq_q;
49+
@@ -919,12 +934,21 @@ static int airoha_qdma_tx_napi_poll(stru
50+
51+
txq = netdev_get_tx_queue(skb->dev, queue);
52+
netdev_tx_completed_queue(txq, 1, skb->len);
53+
- if (netif_tx_queue_stopped(txq) &&
54+
- q->ndesc - q->queued >= q->free_thr)
55+
- netif_tx_wake_queue(txq);
56+
-
57+
dev_kfree_skb_any(skb);
58+
}
59+
+
60+
+ if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) {
61+
+ /* Since multiple net_device TX queues can share the
62+
+ * same hw QDMA TX queue, there is no guarantee we have
63+
+ * inflight packets queued in hw belonging to a
64+
+ * net_device TX queue stopped in the xmit path.
65+
+ * In order to avoid any potential net_device TX queue
66+
+ * stall, we need to wake all the net_device TX queues
67+
+ * feeding the same hw QDMA TX queue.
68+
+ */
69+
+ airoha_qdma_wake_netdev_txqs(q);
70+
+ }
71+
+
72+
unlock:
73+
spin_unlock_bh(&q->lock);
74+
}
75+
@@ -2016,6 +2040,7 @@ static netdev_tx_t airoha_dev_xmit(struc
76+
if (q->queued + nr_frags >= q->ndesc) {
77+
/* not enough space in the queue */
78+
netif_tx_stop_queue(txq);
79+
+ q->txq_stopped = true;
80+
spin_unlock_bh(&q->lock);
81+
return NETDEV_TX_BUSY;
82+
}
83+
@@ -2071,8 +2096,10 @@ static netdev_tx_t airoha_dev_xmit(struc
84+
TX_RING_CPU_IDX_MASK,
85+
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
86+
87+
- if (q->ndesc - q->queued < q->free_thr)
88+
+ if (q->ndesc - q->queued < q->free_thr) {
89+
netif_tx_stop_queue(txq);
90+
+ q->txq_stopped = true;
91+
+ }
92+
93+
spin_unlock_bh(&q->lock);
94+
95+
--- a/drivers/net/ethernet/airoha/airoha_eth.h
96+
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
97+
@@ -193,6 +193,7 @@ struct airoha_queue {
98+
int ndesc;
99+
int free_thr;
100+
int buf_size;
101+
+ bool txq_stopped;
102+
103+
struct napi_struct napi;
104+
struct page_pool *page_pool;

0 commit comments

Comments
 (0)