airoha: rework and backport for multi-serdes prep

Backport additional upstream patch in preparation for multi-serdes and
proper PCS support.

Automatically refresh all affected patch.

(cherry picked from commit 25de25827e56957da268867325eb4e6ed675b6f7)
Link: https://github.com/openwrt/openwrt/pull/22820
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi 2026-03-24 19:33:41 +01:00
parent c68589027b
commit 23bcea0e21
No known key found for this signature in database
GPG Key ID: AC001D09ADBFEAD7
7 changed files with 345 additions and 18 deletions

View File

@ -0,0 +1,162 @@
From df8e1e4a2eb5f8ecdef36c502601e8afbc6ad891 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Wed, 24 Dec 2025 17:29:33 +0100
Subject: [PATCH] net: airoha: Reset PPE default cput port in
airoha_ppe_hw_init()
Before this patch the default PPE cpu port used for a specific GDM
device was set running ndo_init() callback during device initialization.
The selected PPE cpu port configured for the specific GDM device depends
on the QDMA block assigned to the GDM device. The selected QDMA block
depends on LAN/WAN configuration as specified in commmit XXXX.
However, the user selected PPE cpu port can be different with respect to
the one hardcoded in the NPU firmware binary. The hardcoded PPE cput port
value is loaded initializing the PPE engine running npu ops ppe_init()
callback in airoha_ppe_offload_setup routine.
Reset the default value for PPE cpu ports in airoha_ppe_hw_init routine
in order to apply the user requested configuration according to the device
DTS setup.
Please note this patch is fixing an issue not visible to the user (so we
do not need to backport it) since airoha_eth driver currently supports just
the internal phy available via the MT7530 DSA switch and there are no WAN
interfaces officially supporte since PCS/external phy is not merged mainline
yet (it will be posted with following patches).
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 28 +++++------------------
drivers/net/ethernet/airoha/airoha_eth.h | 2 ++
drivers/net/ethernet/airoha/airoha_ppe.c | 23 ++++++++++++++++++-
drivers/net/ethernet/airoha/airoha_regs.h | 7 +++---
4 files changed, 33 insertions(+), 27 deletions(-)
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1755,8 +1755,7 @@ static int airoha_dev_init(struct net_de
{
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_eth *eth = port->eth;
- u32 fe_cpu_port;
- u8 ppe_id;
+ int i;
/* QDMA0 is used for lan ports while QDMA1 is used for WAN ports */
port->qdma = &eth->qdma[!airoha_is_lan_gdm_port(port)];
@@ -1774,28 +1773,13 @@ static int airoha_dev_init(struct net_de
if (err)
return err;
}
- fallthrough;
- case AIROHA_GDM2_IDX:
- if (airoha_ppe_is_enabled(eth, 1)) {
- /* For PPE2 always use secondary cpu port. */
- fe_cpu_port = FE_PSE_PORT_CDM2;
- ppe_id = 1;
- break;
- }
- fallthrough;
- default: {
- u8 qdma_id = port->qdma - &eth->qdma[0];
-
- /* For PPE1 select cpu port according to the running QDMA. */
- fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1;
- ppe_id = 0;
break;
- }
+ default:
+ break;
}
- airoha_fe_rmw(eth, REG_PPE_DFT_CPORT0(ppe_id),
- DFT_CPORT_MASK(port->id),
- __field_prep(DFT_CPORT_MASK(port->id), fe_cpu_port));
+ for (i = 0; i < eth->soc->num_ppe; i++)
+ airoha_ppe_set_cpu_port(port, i);
return 0;
}
@@ -1898,7 +1882,7 @@ static u32 airoha_get_dsa_tag(struct sk_
#endif
}
-static int airoha_get_fe_port(struct airoha_gdm_port *port)
+int airoha_get_fe_port(struct airoha_gdm_port *port)
{
struct airoha_qdma *qdma = port->qdma;
struct airoha_eth *eth = qdma->eth;
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -646,9 +646,11 @@ static inline bool airoha_is_7583(struct
return eth->soc->version == 0x7583;
}
+int airoha_get_fe_port(struct airoha_gdm_port *port);
bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
struct airoha_gdm_port *port);
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
u16 hash, bool rx_wlan);
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -85,6 +85,20 @@ static u32 airoha_ppe_get_timestamp(stru
return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp);
}
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id)
+{
+ struct airoha_qdma *qdma = port->qdma;
+ u8 fport = airoha_get_fe_port(port);
+ struct airoha_eth *eth = qdma->eth;
+ u8 qdma_id = qdma - &eth->qdma[0];
+ u32 fe_cpu_port;
+
+ fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1;
+ airoha_fe_rmw(eth, REG_PPE_DFT_CPORT(ppe_id, fport),
+ DFT_CPORT_MASK(fport),
+ __field_prep(DFT_CPORT_MASK(fport), fe_cpu_port));
+}
+
static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
{
u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries;
@@ -147,7 +161,9 @@ static void airoha_ppe_hw_init(struct ai
airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
- for (p = 0; p < ARRAY_SIZE(eth->ports); p++)
+ for (p = 0; p < ARRAY_SIZE(eth->ports); p++) {
+ struct airoha_gdm_port *port = eth->ports[p];
+
airoha_fe_rmw(eth, REG_PPE_MTU(i, p),
FP0_EGRESS_MTU_MASK |
FP1_EGRESS_MTU_MASK,
@@ -155,6 +171,11 @@ static void airoha_ppe_hw_init(struct ai
AIROHA_MAX_MTU) |
FIELD_PREP(FP1_EGRESS_MTU_MASK,
AIROHA_MAX_MTU));
+ if (!port)
+ continue;
+
+ airoha_ppe_set_cpu_port(port, i);
+ }
}
}
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -312,10 +312,9 @@
#define REG_PPE_HASH_SEED(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x244)
#define PPE_HASH_SEED 0x12345678
-#define REG_PPE_DFT_CPORT0(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x248)
-#define DFT_CPORT_MASK(_n) GENMASK(3 + ((_n) << 2), ((_n) << 2))
-
-#define REG_PPE_DFT_CPORT1(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x24c)
+#define REG_PPE_DFT_CPORT_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x248)
+#define REG_PPE_DFT_CPORT(_m, _n) (REG_PPE_DFT_CPORT_BASE(_m) + (((_n) / 8) << 2))
+#define DFT_CPORT_MASK(_n) GENMASK(3 + (((_n) % 8) << 2), (((_n) % 8) << 2))
#define REG_PPE_TB_HASH_CFG(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x250)
#define PPE_DRAM_HASH1_MODE_MASK GENMASK(31, 28)

View File

@ -0,0 +1,165 @@
From b1c803d5c8167026791abfaed96fd3e6a1fcd750 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Sat, 21 Mar 2026 15:41:44 +0100
Subject: [PATCH] net: airoha: Rework the code flow in airoha_remove() and in
airoha_probe() error path
As suggested by Simon in [0], rework the code flow in airoha_remove()
and in the airoha_probe() error path in order to rely on a more common
approach un-registering configured net-devices first and destroying the
hw resources at the end of the code.
Introduce airoha_qdma_cleanup routine to release QDMA resources.
[0] https://lore.kernel.org/netdev/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org/
Suggested-by: Simon Horman <horms@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260321-airoha-remove-rework-v2-1-16c7bade5fe5@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 76 ++++++++++++++----------
1 file changed, 44 insertions(+), 32 deletions(-)
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1368,6 +1368,33 @@ static int airoha_qdma_init(struct platf
return airoha_qdma_hw_init(qdma);
}
+static void airoha_qdma_cleanup(struct airoha_qdma *qdma)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
+ continue;
+
+ netif_napi_del(&qdma->q_rx[i].napi);
+ airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
+ if (qdma->q_rx[i].page_pool) {
+ page_pool_destroy(qdma->q_rx[i].page_pool);
+ qdma->q_rx[i].page_pool = NULL;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
+ netif_napi_del(&qdma->q_tx_irq[i].napi);
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ if (!qdma->q_tx[i].ndesc)
+ continue;
+
+ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
+ }
+}
+
static int airoha_hw_init(struct platform_device *pdev,
struct airoha_eth *eth)
{
@@ -1395,41 +1422,30 @@ static int airoha_hw_init(struct platfor
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
err = airoha_qdma_init(pdev, eth, &eth->qdma[i]);
if (err)
- return err;
+ goto error;
}
err = airoha_ppe_init(eth);
if (err)
- return err;
+ goto error;
set_bit(DEV_STATE_INITIALIZED, &eth->state);
return 0;
+error:
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_cleanup(&eth->qdma[i]);
+
+ return err;
}
-static void airoha_hw_cleanup(struct airoha_qdma *qdma)
+static void airoha_hw_cleanup(struct airoha_eth *eth)
{
int i;
- for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
- if (!qdma->q_rx[i].ndesc)
- continue;
-
- netif_napi_del(&qdma->q_rx[i].napi);
- airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]);
- if (qdma->q_rx[i].page_pool)
- page_pool_destroy(qdma->q_rx[i].page_pool);
- }
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++)
- netif_napi_del(&qdma->q_tx_irq[i].napi);
-
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
- if (!qdma->q_tx[i].ndesc)
- continue;
-
- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
- }
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
+ airoha_qdma_cleanup(&eth->qdma[i]);
+ airoha_ppe_deinit(eth);
}
static void airoha_qdma_start_napi(struct airoha_qdma *qdma)
@@ -3012,7 +3028,7 @@ static int airoha_probe(struct platform_
err = airoha_hw_init(pdev, eth);
if (err)
- goto error_hw_cleanup;
+ goto error_netdev_free;
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(&eth->qdma[i]);
@@ -3040,10 +3056,6 @@ static int airoha_probe(struct platform_
error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(&eth->qdma[i]);
- airoha_ppe_deinit(eth);
-error_hw_cleanup:
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
- airoha_hw_cleanup(&eth->qdma[i]);
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -3055,6 +3067,8 @@ error_hw_cleanup:
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
+ airoha_hw_cleanup(eth);
+error_netdev_free:
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
@@ -3066,10 +3080,8 @@ static void airoha_remove(struct platfor
struct airoha_eth *eth = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(&eth->qdma[i]);
- airoha_hw_cleanup(&eth->qdma[i]);
- }
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
@@ -3080,9 +3092,9 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
- free_netdev(eth->napi_dev);
+ airoha_hw_cleanup(eth);
- airoha_ppe_deinit(eth);
+ free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
}

View File

@ -13,7 +13,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1382,6 +1382,10 @@ static int airoha_hw_init(struct platfor
@@ -1409,6 +1409,10 @@ static int airoha_hw_init(struct platfor
if (err)
return err;

View File

@ -28,7 +28,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
airoha_fe_crsn_qsel_init(eth);
@@ -1625,7 +1627,8 @@ static int airoha_dev_open(struct net_de
@@ -1641,7 +1643,8 @@ static int airoha_dev_open(struct net_de
if (err)
return err;

View File

@ -15,7 +15,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -3113,7 +3113,6 @@ static void airoha_remove(struct platfor
@@ -3109,7 +3109,6 @@ static void airoha_remove(struct platfor
}
static const char * const en7581_xsi_rsts_names[] = {
@ -23,7 +23,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
"hsi0-mac",
"hsi1-mac",
"hsi-mac",
@@ -3145,7 +3144,6 @@ static int airoha_en7581_get_src_port_id
@@ -3141,7 +3140,6 @@ static int airoha_en7581_get_src_port_id
}
static const char * const an7583_xsi_rsts_names[] = {

View File

@ -35,7 +35,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
struct airoha_eth *eth = port->qdma->eth;
@@ -1622,6 +1628,17 @@ static int airoha_dev_open(struct net_de
@@ -1638,6 +1644,17 @@ static int airoha_dev_open(struct net_de
struct airoha_qdma *qdma = port->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
@ -53,7 +53,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
if (err)
@@ -1686,6 +1703,11 @@ static int airoha_dev_stop(struct net_de
@@ -1702,6 +1719,11 @@ static int airoha_dev_stop(struct net_de
}
}
@ -199,7 +199,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
return airoha_metadata_dst_alloc(port);
}
@@ -3079,6 +3214,10 @@ error_hw_cleanup:
@@ -3075,6 +3210,10 @@ error_napi_stop:
if (port->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->dev);
@ -209,8 +209,8 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ }
airoha_metadata_dst_free(port);
}
free_netdev(eth->napi_dev);
@@ -3105,6 +3244,10 @@ static void airoha_remove(struct platfor
airoha_hw_cleanup(eth);
@@ -3101,6 +3240,10 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
@ -219,7 +219,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+ airoha_pcs_destroy(port->pcs);
+ }
}
free_netdev(eth->napi_dev);
airoha_hw_cleanup(eth);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@ -236,7 +236,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS);
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -359,6 +359,18 @@
@@ -358,6 +358,18 @@
#define IP_FRAGMENT_PORT_MASK GENMASK(8, 5)
#define IP_FRAGMENT_NBQ_MASK GENMASK(4, 0)

View File

@ -28,7 +28,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
@@ -1631,6 +1633,7 @@ static int airoha_dev_open(struct net_de
@@ -1647,6 +1649,7 @@ static int airoha_dev_open(struct net_de
struct airoha_qdma *qdma = port->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
@ -36,7 +36,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
if (airhoa_is_phy_external(port)) {
err = phylink_of_phy_connect(port->phylink, dev->dev.of_node, 0);
if (err) {
@@ -1641,6 +1644,7 @@ static int airoha_dev_open(struct net_de
@@ -1657,6 +1660,7 @@ static int airoha_dev_open(struct net_de
phylink_start(port->phylink);
}
@ -44,7 +44,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
@@ -1706,10 +1710,12 @@ static int airoha_dev_stop(struct net_de
@@ -1722,10 +1726,12 @@ static int airoha_dev_stop(struct net_de
}
}
@ -103,7 +103,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
return airoha_metadata_dst_alloc(port);
}
@@ -3217,10 +3229,12 @@ error_hw_cleanup:
@@ -3213,10 +3225,12 @@ error_napi_stop:
if (port->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->dev);
@ -115,8 +115,8 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+#endif
airoha_metadata_dst_free(port);
}
free_netdev(eth->napi_dev);
@@ -3247,10 +3261,12 @@ static void airoha_remove(struct platfor
airoha_hw_cleanup(eth);
@@ -3243,10 +3257,12 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
@ -127,7 +127,7 @@ Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
}
+#endif
}
free_netdev(eth->napi_dev);
airoha_hw_cleanup(eth);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h