--- /dev/null
+From 4ae0604a0673e11e2075b178387151fcad5111b5 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Tue, 7 Apr 2026 08:48:04 +0200
+Subject: [PATCH] net: airoha: Add dma_rmb() and READ_ONCE() in
+ airoha_qdma_rx_process()
+
+Add missing dma_rmb() in airoha_qdma_rx_process routine to make sure the
+DMA read operations are completed when the NIC reports the processing on
+the current descriptor is done. Moreover, add missing READ_ONCE() in
+airoha_qdma_rx_process() for DMA descriptor control fields in order to
+avoid any compiler reordering.
+
+Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260407-airoha_qdma_rx_process-fix-reordering-v3-1-91c36e9da31f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -584,7 +584,7 @@ static int airoha_qdma_fill_rx_queue(str
+ static int airoha_qdma_get_gdm_port(struct airoha_eth *eth,
+ struct airoha_qdma_desc *desc)
+ {
+- u32 port, sport, msg1 = le32_to_cpu(desc->msg1);
++ u32 port, sport, msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
+
+ sport = FIELD_GET(QDMA_ETH_RXMSG_SPORT_MASK, msg1);
+ switch (sport) {
+@@ -612,21 +612,24 @@ static int airoha_qdma_rx_process(struct
+ while (done < budget) {
+ struct airoha_queue_entry *e = &q->entry[q->tail];
+ struct airoha_qdma_desc *desc = &q->desc[q->tail];
+- u32 hash, reason, msg1 = le32_to_cpu(desc->msg1);
+- struct page *page = virt_to_head_page(e->buf);
+- u32 desc_ctrl = le32_to_cpu(desc->ctrl);
++ u32 hash, reason, msg1, desc_ctrl;
+ struct airoha_gdm_port *port;
+ int data_len, len, p;
++ struct page *page;
+
++ desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
+ if (!(desc_ctrl & QDMA_DESC_DONE_MASK))
+ break;
+
++ dma_rmb();
++
+ q->tail = (q->tail + 1) % q->ndesc;
+ q->queued--;
+
+ dma_sync_single_for_cpu(eth->dev, e->dma_addr,
+ SKB_WITH_OVERHEAD(q->buf_size), dir);
+
++ page = virt_to_head_page(e->buf);
+ len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl);
+ data_len = q->skb ? q->buf_size
+ : SKB_WITH_OVERHEAD(q->buf_size);
+@@ -670,8 +673,8 @@ static int airoha_qdma_rx_process(struct
+ * DMA descriptor. Report DSA tag to the DSA stack
+ * via skb dst info.
+ */
+- u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG,
+- le32_to_cpu(desc->msg0));
++ u32 msg0 = le32_to_cpu(READ_ONCE(desc->msg0));
++ u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, msg0);
+
+ if (sptag < ARRAY_SIZE(port->dsa_meta) &&
+ port->dsa_meta[sptag])
+@@ -679,6 +682,7 @@ static int airoha_qdma_rx_process(struct
+ &port->dsa_meta[sptag]->dst);
+ }
+
++ msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
+ hash = FIELD_GET(AIROHA_RXD4_FOE_ENTRY, msg1);
+ if (hash != AIROHA_RXD4_FOE_ENTRY)
+ skb_set_hash(q->skb, jhash_1word(hash, 0),
--- /dev/null
+From b9d8b856689d2b968495d79fe653d87fcb8ad98c Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Apr 2026 10:43:26 +0200
+Subject: [PATCH] net: airoha: Add missing PPE configurations in
+ airoha_ppe_hw_init()
+
+Add the following PPE configuration in airoha_ppe_hw_init routine:
+- 6RD hw offloading is currently not supported by Netfilter flowtable.
+ Disable explicitly PPE 6RD offloading in order to prevent PPE to learn
+ 6RD flows and eventually interrupt the traffic.
+- Add missing PPE bind rate configuration for L3 and L2 traffic.
+ PPE bind rate configuration specifies the pps threshold to move a PPE
+ entry state from UNBIND to BIND. Without this configuration this value
+ is random.
+- Set ageing thresholds to the values used in the vendor SDK in order to
+ improve connection stability under load and avoid packet loss caused by
+ fast aging.
+
+Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260412-airoha_ppe_hw_init-missing-bits-v1-1-06ac670819e3@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/ethernet/airoha/airoha_ppe.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_ppe.c
++++ b/drivers/net/ethernet/airoha/airoha_ppe.c
+@@ -125,13 +125,13 @@ static void airoha_ppe_hw_init(struct ai
+ airoha_fe_rmw(eth, REG_PPE_BND_AGE0(i),
+ PPE_BIND_AGE0_DELTA_NON_L4 |
+ PPE_BIND_AGE0_DELTA_UDP,
+- FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 1) |
+- FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 12));
++ FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 60) |
++ FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 60));
+ airoha_fe_rmw(eth, REG_PPE_BND_AGE1(i),
+ PPE_BIND_AGE1_DELTA_TCP_FIN |
+ PPE_BIND_AGE1_DELTA_TCP,
+ FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP_FIN, 1) |
+- FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 7));
++ FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 60));
+
+ airoha_fe_rmw(eth, REG_PPE_TB_HASH_CFG(i),
+ PPE_SRAM_TABLE_EN_MASK |
+@@ -159,7 +159,15 @@ static void airoha_ppe_hw_init(struct ai
+ FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK,
+ dram_num_entries));
+
++ airoha_fe_rmw(eth, REG_PPE_BIND_RATE(i),
++ PPE_BIND_RATE_L2B_BIND_MASK |
++ PPE_BIND_RATE_BIND_MASK,
++ FIELD_PREP(PPE_BIND_RATE_L2B_BIND_MASK, 0x1e) |
++ FIELD_PREP(PPE_BIND_RATE_BIND_MASK, 0x1e));
++
+ airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
++ airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i),
++ PPE_FLOW_CFG_IP6_6RD_MASK);
+
+ for (p = 0; p < ARRAY_SIZE(eth->ports); p++) {
+ struct airoha_gdm_port *port = eth->ports[p];
--- /dev/null
+From 656121b155030086b01cfce9bd31b0c925ee6860 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Wed, 8 Apr 2026 20:26:56 +0200
+Subject: [PATCH] net: airoha: Add missing RX_CPU_IDX() configuration in
+ airoha_qdma_cleanup_rx_queue()
+
+When the descriptor index written in REG_RX_CPU_IDX() is equal to the one
+stored in REG_RX_DMA_IDX(), the hw will stop since the QDMA RX ring is
+empty.
+Add missing REG_RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue
+routine during QDMA RX ring cleanup.
+
+Fixes: 514aac359987 ("net: airoha: Add missing cleanup bits in airoha_qdma_cleanup_rx_queue()")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260408-airoha-cpu-idx-airoha_qdma_cleanup_rx_queue-v1-1-8efa64844308@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -824,6 +824,11 @@ static void airoha_qdma_cleanup_rx_queue
+ }
+
+ q->head = q->tail;
++ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is
++ * empty.
++ */
++ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
++ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
+ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
+ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
+ }
--- /dev/null
+From 02f72964395911e7a09bb2ea2fe6f79eda4ea2c2 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Wed, 8 Apr 2026 12:20:09 +0200
+Subject: [PATCH] net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is
+ available
+
+airoha_fe_set routine is used to set specified bits to 1 in the selected
+register. In the FE_PSE_BUF_SET case this can due to a overestimation of
+the required buffers for I/O queues since we can miss to set some bits
+of PSE_ALLRSV_MASK subfield to 0. Fix the issue relying on airoha_fe_rmw
+routine instead.
+
+Fixes: 8e38e08f2c560 ("net: airoha: fix PSE memory configuration in airoha_fe_pse_ports_init()")
+Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260408-airoha-reg_fe_pse_buf_set-v1-1-0c4fa8f4d1d9@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -293,16 +293,18 @@ static void airoha_fe_pse_ports_init(str
+ [FE_PSE_PORT_GDM4] = 2,
+ [FE_PSE_PORT_CDM5] = 2,
+ };
+- u32 all_rsv;
+ int q;
+
+- all_rsv = airoha_fe_get_pse_all_rsv(eth);
+ if (airoha_ppe_is_enabled(eth, 1)) {
++ u32 all_rsv;
++
+ /* hw misses PPE2 oq rsv */
++ all_rsv = airoha_fe_get_pse_all_rsv(eth);
+ all_rsv += PSE_RSV_PAGES *
+ pse_port_num_queues[FE_PSE_PORT_PPE2];
++ airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK,
++ FIELD_PREP(PSE_ALLRSV_MASK, all_rsv));
+ }
+- airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv);
+
+ /* CMD1 */
+ for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++)
--- /dev/null
+From 285fa6b1e03cff78ead0383e1b259c44b95faf90 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Thu, 2 Apr 2026 14:57:10 +0200
+Subject: [PATCH] net: airoha: Fix memory leak in airoha_qdma_rx_process()
+
+If an error occurs on the subsequents buffers belonging to the
+non-linear part of the skb (e.g. due to an error in the payload length
+reported by the NIC or if we consumed all the available fragments for
+the skb), the page_pool fragment will not be linked to the skb so it will
+not return to the pool in the airoha_qdma_rx_process() error path. Fix the
+memory leak partially reverting commit 'd6d2b0e1538d ("net: airoha: Fix
+page recycling in airoha_qdma_rx_process()")' and always running
+page_pool_put_full_page routine in the airoha_qdma_rx_process() error
+path.
+
+Fixes: d6d2b0e1538d ("net: airoha: Fix page recycling in airoha_qdma_rx_process()")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260402-airoha_qdma_rx_process-mem-leak-fix-v1-1-b5706f402d3c@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -703,9 +703,8 @@ free_frag:
+ if (q->skb) {
+ dev_kfree_skb(q->skb);
+ q->skb = NULL;
+- } else {
+- page_pool_put_full_page(q->page_pool, page, true);
+ }
++ page_pool_put_full_page(q->page_pool, page, true);
+ }
+ airoha_qdma_fill_rx_queue(q);
+
--- /dev/null
+From 1acdfbdb516b32165a8ecd1d5f8c68e4eac64637 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Apr 2026 09:57:29 +0200
+Subject: [PATCH] net: airoha: Fix VIP configuration for AN7583 SoC
+
+EN7581 and AN7583 SoCs have different VIP definitions. Introduce
+get_vip_port callback in airoha_eth_soc_data struct in order to take
+into account EN7581 and AN7583 VIP register layout and definition
+differences.
+Introduce nbq parameter in airoha_gdm_port struct. At the moment nbq
+is set statically to value previously used in airhoha_set_gdm2_loopback
+routine and it will be read from device tree in subsequent patches.
+
+Fixes: e4e5ce823bdd ("net: airoha: Add AN7583 SoC support")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260412-airoha-7583-vip-fix-v1-1-c35e02b054bb@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 66 ++++++++++++++++++------
+ drivers/net/ethernet/airoha/airoha_eth.h | 2 +
+ 2 files changed, 51 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -107,19 +107,7 @@ static int airoha_set_vip_for_gdm_port(s
+ struct airoha_eth *eth = port->qdma->eth;
+ u32 vip_port;
+
+- switch (port->id) {
+- case AIROHA_GDM3_IDX:
+- /* FIXME: handle XSI_PCIE1_PORT */
+- vip_port = XSI_PCIE0_VIP_PORT_MASK;
+- break;
+- case AIROHA_GDM4_IDX:
+- /* FIXME: handle XSI_USB_PORT */
+- vip_port = XSI_ETH_VIP_PORT_MASK;
+- break;
+- default:
+- return 0;
+- }
+-
++ vip_port = eth->soc->ops.get_vip_port(port, port->nbq);
+ if (enable) {
+ airoha_fe_set(eth, REG_FE_VIP_PORT_EN, vip_port);
+ airoha_fe_set(eth, REG_FE_IFC_PORT_EN, vip_port);
+@@ -1738,7 +1726,7 @@ static int airoha_dev_set_macaddr(struct
+ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port)
+ {
+ struct airoha_eth *eth = port->qdma->eth;
+- u32 val, pse_port, chan, nbq;
++ u32 val, pse_port, chan;
+ int src_port;
+
+ /* Forward the traffic to the proper GDM port */
+@@ -1768,9 +1756,7 @@ static int airhoha_set_gdm2_loopback(str
+ airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
+ airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
+
+- /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */
+- nbq = port->id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
+- src_port = eth->soc->ops.get_src_port_id(port, nbq);
++ src_port = eth->soc->ops.get_src_port_id(port, port->nbq);
+ if (src_port < 0)
+ return src_port;
+
+@@ -2962,6 +2948,8 @@ static int airoha_alloc_gdm_port(struct
+ port->eth = eth;
+ port->dev = dev;
+ port->id = id;
++ /* XXX: Read nbq from DTS */
++ port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
+ eth->ports[p] = port;
+
+ return airoha_metadata_dst_alloc(port);
+@@ -3158,6 +3146,28 @@ static int airoha_en7581_get_src_port_id
+ return -EINVAL;
+ }
+
++static u32 airoha_en7581_get_vip_port(struct airoha_gdm_port *port, int nbq)
++{
++ switch (port->id) {
++ case AIROHA_GDM3_IDX:
++ if (nbq == 4)
++ return XSI_PCIE0_VIP_PORT_MASK;
++ if (nbq == 5)
++ return XSI_PCIE1_VIP_PORT_MASK;
++ break;
++ case AIROHA_GDM4_IDX:
++ if (!nbq)
++ return XSI_ETH_VIP_PORT_MASK;
++ if (nbq == 1)
++ return XSI_USB_VIP_PORT_MASK;
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
+ static const char * const an7583_xsi_rsts_names[] = {
+ "xsi-mac",
+ "hsi0-mac",
+@@ -3187,6 +3197,26 @@ static int airoha_an7583_get_src_port_id
+ return -EINVAL;
+ }
+
++static u32 airoha_an7583_get_vip_port(struct airoha_gdm_port *port, int nbq)
++{
++ switch (port->id) {
++ case AIROHA_GDM3_IDX:
++ if (!nbq)
++ return XSI_ETH_VIP_PORT_MASK;
++ break;
++ case AIROHA_GDM4_IDX:
++ if (!nbq)
++ return XSI_PCIE0_VIP_PORT_MASK;
++ if (nbq == 1)
++ return XSI_USB_VIP_PORT_MASK;
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
+ static const struct airoha_eth_soc_data en7581_soc_data = {
+ .version = 0x7581,
+ .xsi_rsts_names = en7581_xsi_rsts_names,
+@@ -3194,6 +3224,7 @@ static const struct airoha_eth_soc_data
+ .num_ppe = 2,
+ .ops = {
+ .get_src_port_id = airoha_en7581_get_src_port_id,
++ .get_vip_port = airoha_en7581_get_vip_port,
+ },
+ };
+
+@@ -3204,6 +3235,7 @@ static const struct airoha_eth_soc_data
+ .num_ppe = 1,
+ .ops = {
+ .get_src_port_id = airoha_an7583_get_src_port_id,
++ .get_vip_port = airoha_an7583_get_vip_port,
+ },
+ };
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.h
++++ b/drivers/net/ethernet/airoha/airoha_eth.h
+@@ -537,6 +537,7 @@ struct airoha_gdm_port {
+ struct airoha_eth *eth;
+ struct net_device *dev;
+ int id;
++ int nbq;
+
+ struct airoha_hw_stats stats;
+
+@@ -577,6 +578,7 @@ struct airoha_eth_soc_data {
+ int num_ppe;
+ struct {
+ int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq);
++ u32 (*get_vip_port)(struct airoha_gdm_port *port, int nbq);
+ } ops;
+ };
+
--- /dev/null
+From 360d745a5319f09849a94dee0974c8ead721e392 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Apr 2026 19:13:12 +0200
+Subject: [PATCH 1/4] net: airoha: Rely on net_device pointer in
+ airoha_dev_setup_tc_block signature
+
+Remove airoha_gdm_port dependency in airoha_dev_setup_tc_block routine
+signature and rely on net_device pointer instead. Please note this patch
+does not introduce any logical change and it is a preliminary patch to
+support multiple net_devices connected to the GDM3 or GDM4 ports via an
+external hw arbiter.
+
+Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260412-airoha-multi-serdes-preliminary-patch-v1-1-08d5b670ca8f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -2683,7 +2683,7 @@ static int airoha_dev_setup_tc_block_cb(
+ }
+ }
+
+-static int airoha_dev_setup_tc_block(struct airoha_gdm_port *port,
++static int airoha_dev_setup_tc_block(struct net_device *dev,
+ struct flow_block_offload *f)
+ {
+ flow_setup_cb_t *cb = airoha_dev_setup_tc_block_cb;
+@@ -2696,12 +2696,12 @@ static int airoha_dev_setup_tc_block(str
+ f->driver_block_list = &block_cb_list;
+ switch (f->command) {
+ case FLOW_BLOCK_BIND:
+- block_cb = flow_block_cb_lookup(f->block, cb, port->dev);
++ block_cb = flow_block_cb_lookup(f->block, cb, dev);
+ if (block_cb) {
+ flow_block_cb_incref(block_cb);
+ return 0;
+ }
+- block_cb = flow_block_cb_alloc(cb, port->dev, port->dev, NULL);
++ block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+@@ -2710,7 +2710,7 @@ static int airoha_dev_setup_tc_block(str
+ list_add_tail(&block_cb->driver_list, &block_cb_list);
+ return 0;
+ case FLOW_BLOCK_UNBIND:
+- block_cb = flow_block_cb_lookup(f->block, cb, port->dev);
++ block_cb = flow_block_cb_lookup(f->block, cb, dev);
+ if (!block_cb)
+ return -ENOENT;
+
+@@ -2809,7 +2809,7 @@ static int airoha_dev_tc_setup(struct ne
+ return airoha_tc_setup_qdisc_htb(port, type_data);
+ case TC_SETUP_BLOCK:
+ case TC_SETUP_FT:
+- return airoha_dev_setup_tc_block(port, type_data);
++ return airoha_dev_setup_tc_block(dev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
--- /dev/null
+From 8baf4bf72ef94c955ef89d4644f1986603ee8320 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Apr 2026 19:13:13 +0200
+Subject: [PATCH 2/4] net: airoha: Rely on net_device pointer in HTB callbacks
+
+Remove airoha_gdm_port dependency in HTB tc callback signatures and rely
+on net_device pointer instead. Please note this patch does not introduce
+any logical change and it is a preliminary patch in order to support
+multiple net_devices connected to the same GDM3 or GDM4 port via an
+external hw arbiter.
+
+Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260412-airoha-multi-serdes-preliminary-patch-v1-2-08d5b670ca8f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 45 +++++++++++++-----------
+ 1 file changed, 24 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -2488,10 +2488,11 @@ static int airoha_qdma_set_trtcm_token_b
+ mode, val);
+ }
+
+-static int airoha_qdma_set_tx_rate_limit(struct airoha_gdm_port *port,
++static int airoha_qdma_set_tx_rate_limit(struct net_device *dev,
+ int channel, u32 rate,
+ u32 bucket_size)
+ {
++ struct airoha_gdm_port *port = netdev_priv(dev);
+ int i, err;
+
+ for (i = 0; i <= TRTCM_PEAK_MODE; i++) {
+@@ -2511,21 +2512,20 @@ static int airoha_qdma_set_tx_rate_limit
+ return 0;
+ }
+
+-static int airoha_tc_htb_alloc_leaf_queue(struct airoha_gdm_port *port,
++static int airoha_tc_htb_alloc_leaf_queue(struct net_device *dev,
+ struct tc_htb_qopt_offload *opt)
+ {
+ u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
+ u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */
+- struct net_device *dev = port->dev;
+- int num_tx_queues = dev->real_num_tx_queues;
+- int err;
++ int err, num_tx_queues = dev->real_num_tx_queues;
++ struct airoha_gdm_port *port = netdev_priv(dev);
+
+ if (opt->parent_classid != TC_HTB_CLASSID_ROOT) {
+ NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid");
+ return -EINVAL;
+ }
+
+- err = airoha_qdma_set_tx_rate_limit(port, channel, rate, opt->quantum);
++ err = airoha_qdma_set_tx_rate_limit(dev, channel, rate, opt->quantum);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(opt->extack,
+ "failed configuring htb offload");
+@@ -2537,7 +2537,7 @@ static int airoha_tc_htb_alloc_leaf_queu
+
+ err = netif_set_real_num_tx_queues(dev, num_tx_queues + 1);
+ if (err) {
+- airoha_qdma_set_tx_rate_limit(port, channel, 0, opt->quantum);
++ airoha_qdma_set_tx_rate_limit(dev, channel, 0, opt->quantum);
+ NL_SET_ERR_MSG_MOD(opt->extack,
+ "failed setting real_num_tx_queues");
+ return err;
+@@ -2724,44 +2724,47 @@ static int airoha_dev_setup_tc_block(str
+ }
+ }
+
+-static void airoha_tc_remove_htb_queue(struct airoha_gdm_port *port, int queue)
++static void airoha_tc_remove_htb_queue(struct net_device *dev, int queue)
+ {
+- struct net_device *dev = port->dev;
++ struct airoha_gdm_port *port = netdev_priv(dev);
+
+ netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1);
+- airoha_qdma_set_tx_rate_limit(port, queue + 1, 0, 0);
++ airoha_qdma_set_tx_rate_limit(dev, queue + 1, 0, 0);
+ clear_bit(queue, port->qos_sq_bmap);
+ }
+
+-static int airoha_tc_htb_delete_leaf_queue(struct airoha_gdm_port *port,
++static int airoha_tc_htb_delete_leaf_queue(struct net_device *dev,
+ struct tc_htb_qopt_offload *opt)
+ {
+ u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
++ struct airoha_gdm_port *port = netdev_priv(dev);
+
+ if (!test_bit(channel, port->qos_sq_bmap)) {
+ NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
+ return -EINVAL;
+ }
+
+- airoha_tc_remove_htb_queue(port, channel);
++ airoha_tc_remove_htb_queue(dev, channel);
+
+ return 0;
+ }
+
+-static int airoha_tc_htb_destroy(struct airoha_gdm_port *port)
++static int airoha_tc_htb_destroy(struct net_device *dev)
+ {
++ struct airoha_gdm_port *port = netdev_priv(dev);
+ int q;
+
+ for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS)
+- airoha_tc_remove_htb_queue(port, q);
++ airoha_tc_remove_htb_queue(dev, q);
+
+ return 0;
+ }
+
+-static int airoha_tc_get_htb_get_leaf_queue(struct airoha_gdm_port *port,
++static int airoha_tc_get_htb_get_leaf_queue(struct net_device *dev,
+ struct tc_htb_qopt_offload *opt)
+ {
+ u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS;
++ struct airoha_gdm_port *port = netdev_priv(dev);
+
+ if (!test_bit(channel, port->qos_sq_bmap)) {
+ NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id");
+@@ -2773,23 +2776,23 @@ static int airoha_tc_get_htb_get_leaf_qu
+ return 0;
+ }
+
+-static int airoha_tc_setup_qdisc_htb(struct airoha_gdm_port *port,
++static int airoha_tc_setup_qdisc_htb(struct net_device *dev,
+ struct tc_htb_qopt_offload *opt)
+ {
+ switch (opt->command) {
+ case TC_HTB_CREATE:
+ break;
+ case TC_HTB_DESTROY:
+- return airoha_tc_htb_destroy(port);
++ return airoha_tc_htb_destroy(dev);
+ case TC_HTB_NODE_MODIFY:
+ case TC_HTB_LEAF_ALLOC_QUEUE:
+- return airoha_tc_htb_alloc_leaf_queue(port, opt);
++ return airoha_tc_htb_alloc_leaf_queue(dev, opt);
+ case TC_HTB_LEAF_DEL:
+ case TC_HTB_LEAF_DEL_LAST:
+ case TC_HTB_LEAF_DEL_LAST_FORCE:
+- return airoha_tc_htb_delete_leaf_queue(port, opt);
++ return airoha_tc_htb_delete_leaf_queue(dev, opt);
+ case TC_HTB_LEAF_QUERY_QUEUE:
+- return airoha_tc_get_htb_get_leaf_queue(port, opt);
++ return airoha_tc_get_htb_get_leaf_queue(dev, opt);
+ default:
+ return -EOPNOTSUPP;
+ }
+@@ -2806,7 +2809,7 @@ static int airoha_dev_tc_setup(struct ne
+ case TC_SETUP_QDISC_ETS:
+ return airoha_tc_setup_qdisc_ets(port, type_data);
+ case TC_SETUP_QDISC_HTB:
+- return airoha_tc_setup_qdisc_htb(port, type_data);
++ return airoha_tc_setup_qdisc_htb(dev, type_data);
+ case TC_SETUP_BLOCK:
+ case TC_SETUP_FT:
+ return airoha_dev_setup_tc_block(dev, type_data);
--- /dev/null
+From ae32f80018f0f0f4ebc7a0a70d4092d08a1545e8 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Apr 2026 19:13:14 +0200
+Subject: [PATCH 3/4] net: airoha: Rely on net_device pointer in ETS callbacks
+
+Remove airoha_gdm_port dependency in ETS tc callback signatures and rely
+on net_device pointer instead. Please note this patch does not introduce
+any logical change and it is a preliminary patch in order to support
+multiple net_devices connected to the same GDM3 or GDM4 port via an
+external hw arbiter.
+
+Tested-by: Xuegang Lu <xuegang.lu@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260412-airoha-multi-serdes-preliminary-patch-v1-3-08d5b670ca8f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 30 +++++++++++-------------
+ 1 file changed, 14 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -2134,10 +2134,11 @@ airoha_ethtool_get_rmon_stats(struct net
+ } while (u64_stats_fetch_retry(&port->stats.syncp, start));
+ }
+
+-static int airoha_qdma_set_chan_tx_sched(struct airoha_gdm_port *port,
++static int airoha_qdma_set_chan_tx_sched(struct net_device *dev,
+ int channel, enum tx_sched_mode mode,
+ const u16 *weights, u8 n_weights)
+ {
++ struct airoha_gdm_port *port = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < AIROHA_NUM_TX_RING; i++)
+@@ -2169,17 +2170,15 @@ static int airoha_qdma_set_chan_tx_sched
+ return 0;
+ }
+
+-static int airoha_qdma_set_tx_prio_sched(struct airoha_gdm_port *port,
+- int channel)
++static int airoha_qdma_set_tx_prio_sched(struct net_device *dev, int channel)
+ {
+ static const u16 w[AIROHA_NUM_QOS_QUEUES] = {};
+
+- return airoha_qdma_set_chan_tx_sched(port, channel, TC_SCH_SP, w,
++ return airoha_qdma_set_chan_tx_sched(dev, channel, TC_SCH_SP, w,
+ ARRAY_SIZE(w));
+ }
+
+-static int airoha_qdma_set_tx_ets_sched(struct airoha_gdm_port *port,
+- int channel,
++static int airoha_qdma_set_tx_ets_sched(struct net_device *dev, int channel,
+ struct tc_ets_qopt_offload *opt)
+ {
+ struct tc_ets_qopt_offload_replace_params *p = &opt->replace_params;
+@@ -2220,20 +2219,21 @@ static int airoha_qdma_set_tx_ets_sched(
+ else if (nstrict < AIROHA_NUM_QOS_QUEUES - 1)
+ mode = nstrict + 1;
+
+- return airoha_qdma_set_chan_tx_sched(port, channel, mode, w,
++ return airoha_qdma_set_chan_tx_sched(dev, channel, mode, w,
+ ARRAY_SIZE(w));
+ }
+
+-static int airoha_qdma_get_tx_ets_stats(struct airoha_gdm_port *port,
+- int channel,
++static int airoha_qdma_get_tx_ets_stats(struct net_device *dev, int channel,
+ struct tc_ets_qopt_offload *opt)
+ {
++ struct airoha_gdm_port *port = netdev_priv(dev);
+ u64 cpu_tx_packets = airoha_qdma_rr(port->qdma,
+ REG_CNTR_VAL(channel << 1));
+ u64 fwd_tx_packets = airoha_qdma_rr(port->qdma,
+ REG_CNTR_VAL((channel << 1) + 1));
+ u64 tx_packets = (cpu_tx_packets - port->cpu_tx_packets) +
+ (fwd_tx_packets - port->fwd_tx_packets);
++
+ _bstats_update(opt->stats.bstats, 0, tx_packets);
+
+ port->cpu_tx_packets = cpu_tx_packets;
+@@ -2242,7 +2242,7 @@ static int airoha_qdma_get_tx_ets_stats(
+ return 0;
+ }
+
+-static int airoha_tc_setup_qdisc_ets(struct airoha_gdm_port *port,
++static int airoha_tc_setup_qdisc_ets(struct net_device *dev,
+ struct tc_ets_qopt_offload *opt)
+ {
+ int channel;
+@@ -2255,12 +2255,12 @@ static int airoha_tc_setup_qdisc_ets(str
+
+ switch (opt->command) {
+ case TC_ETS_REPLACE:
+- return airoha_qdma_set_tx_ets_sched(port, channel, opt);
++ return airoha_qdma_set_tx_ets_sched(dev, channel, opt);
+ case TC_ETS_DESTROY:
+ /* PRIO is default qdisc scheduler */
+- return airoha_qdma_set_tx_prio_sched(port, channel);
++ return airoha_qdma_set_tx_prio_sched(dev, channel);
+ case TC_ETS_STATS:
+- return airoha_qdma_get_tx_ets_stats(port, channel, opt);
++ return airoha_qdma_get_tx_ets_stats(dev, channel, opt);
+ default:
+ return -EOPNOTSUPP;
+ }
+@@ -2803,11 +2803,9 @@ static int airoha_tc_setup_qdisc_htb(str
+ static int airoha_dev_tc_setup(struct net_device *dev, enum tc_setup_type type,
+ void *type_data)
+ {
+- struct airoha_gdm_port *port = netdev_priv(dev);
+-
+ switch (type) {
+ case TC_SETUP_QDISC_ETS:
+- return airoha_tc_setup_qdisc_ets(port, type_data);
++ return airoha_tc_setup_qdisc_ets(dev, type_data);
+ case TC_SETUP_QDISC_HTB:
+ return airoha_tc_setup_qdisc_htb(dev, type_data);
+ case TC_SETUP_BLOCK:
--- /dev/null
+From 34e1a98ff2a87cf4b8de3ccebe9d45273f014aeb Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Apr 2026 11:56:25 +0200
+Subject: [PATCH 4/4] net: airoha: Remove PCE_MC_EN_MASK bit in REG_FE_PCE_CFG
+ configuration
+
+PCE_MC_EN_MASK bit in REG_FE_PCE_CFG configuration performed in
+airoha_fe_init() is used to duplicate multicast packets and send a copy
+to the CPU when the traffic is offloaded. This is necessary just if
+it is requested by the user. Disable multicast packets duplication by
+default.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260412-airoha_fe_init_remove_mc_en_bit-v1-1-7b6a5a25a74d@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -448,9 +448,8 @@ static int airoha_fe_init(struct airoha_
+ FIELD_PREP(PSE_IQ_RES2_P5_MASK, 0x40) |
+ FIELD_PREP(PSE_IQ_RES2_P4_MASK, 0x34));
+
+- /* enable FE copy engine for MC/KA/DPI */
+- airoha_fe_wr(eth, REG_FE_PCE_CFG,
+- PCE_DPI_EN_MASK | PCE_KA_EN_MASK | PCE_MC_EN_MASK);
++ /* enable FE copy engine for KA/DPI */
++ airoha_fe_wr(eth, REG_FE_PCE_CFG, PCE_DPI_EN_MASK | PCE_KA_EN_MASK);
+ /* set vip queue selection to ring 1 */
+ airoha_fe_rmw(eth, REG_CDM_FWD_CFG(1), CDM_VIP_QSEL_MASK,
+ FIELD_PREP(CDM_VIP_QSEL_MASK, 0x4));
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -1425,6 +1425,10 @@ static int airoha_hw_init(struct platfor
+@@ -1422,6 +1422,10 @@ static int airoha_hw_init(struct platfor
if (err)
return err;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -588,8 +588,11 @@ static int airoha_qdma_get_gdm_port(stru
+@@ -577,8 +577,11 @@ static int airoha_qdma_get_gdm_port(stru
sport = FIELD_GET(QDMA_ETH_RXMSG_SPORT_MASK, msg1);
switch (sport) {
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -514,8 +514,10 @@ static int airoha_fe_init(struct airoha_
+@@ -503,8 +503,10 @@ static int airoha_fe_init(struct airoha_
FIELD_PREP(IP_ASSEMBLE_PORT_MASK, 0) |
FIELD_PREP(IP_ASSEMBLE_NBQ_MASK, 22));
airoha_fe_crsn_qsel_init(eth);
-@@ -1657,7 +1659,8 @@ static int airoha_dev_open(struct net_de
+@@ -1654,7 +1656,8 @@ static int airoha_dev_open(struct net_de
if (err)
return err;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -3127,7 +3127,6 @@ static void airoha_remove(struct platfor
+@@ -3125,7 +3125,6 @@ static void airoha_remove(struct platfor
}
static const char * const en7581_xsi_rsts_names[] = {
"hsi0-mac",
"hsi1-mac",
"hsi-mac",
-@@ -3159,7 +3158,6 @@ static int airoha_en7581_get_src_port_id
+@@ -3179,7 +3178,6 @@ static u32 airoha_en7581_get_vip_port(st
}
static const char * const an7583_xsi_rsts_names[] = {
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
struct airoha_eth *eth = port->qdma->eth;
-@@ -1654,6 +1660,17 @@ static int airoha_dev_open(struct net_de
+@@ -1651,6 +1657,17 @@ static int airoha_dev_open(struct net_de
struct airoha_qdma *qdma = port->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
if (err)
-@@ -1718,6 +1735,11 @@ static int airoha_dev_stop(struct net_de
+@@ -1715,6 +1732,11 @@ static int airoha_dev_stop(struct net_de
}
}
return 0;
}
-@@ -2849,6 +2871,20 @@ static const struct ethtool_ops airoha_e
+@@ -2845,6 +2867,20 @@ static const struct ethtool_ops airoha_e
.get_link = ethtool_op_get_link,
};
static int airoha_metadata_dst_alloc(struct airoha_gdm_port *port)
{
int i;
-@@ -2893,6 +2929,99 @@ bool airoha_is_valid_gdm_port(struct air
+@@ -2889,6 +2925,99 @@ bool airoha_is_valid_gdm_port(struct air
return false;
}
static int airoha_alloc_gdm_port(struct airoha_eth *eth,
struct device_node *np)
{
-@@ -2964,6 +3093,12 @@ static int airoha_alloc_gdm_port(struct
- port->id = id;
+@@ -2962,6 +3091,12 @@ static int airoha_alloc_gdm_port(struct
+ port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
eth->ports[p] = port;
+ if (airhoa_is_phy_external(port)) {
return airoha_metadata_dst_alloc(port);
}
-@@ -3093,6 +3228,10 @@ error_napi_stop:
+@@ -3091,6 +3226,10 @@ error_napi_stop:
if (port->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
airoha_hw_cleanup(eth);
-@@ -3119,6 +3258,10 @@ static void airoha_remove(struct platfor
+@@ -3117,6 +3256,10 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
-@@ -538,6 +538,10 @@ struct airoha_gdm_port {
- struct net_device *dev;
+@@ -539,6 +539,10 @@ struct airoha_gdm_port {
int id;
+ int nbq;
+ struct phylink *phylink;
+ struct phylink_config phylink_config;
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
-@@ -599,6 +599,9 @@ static int airoha_qdma_get_gdm_port(stru
+@@ -588,6 +588,9 @@ static int airoha_qdma_get_gdm_port(stru
case 0x18:
port = 3; /* GDM4 */
break;
static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
{
-@@ -1663,6 +1665,7 @@ static int airoha_dev_open(struct net_de
+@@ -1660,6 +1662,7 @@ static int airoha_dev_open(struct net_de
struct airoha_qdma *qdma = port->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
if (airhoa_is_phy_external(port)) {
err = phylink_of_phy_connect(port->phylink, dev->dev.of_node, 0);
if (err) {
-@@ -1673,6 +1676,7 @@ static int airoha_dev_open(struct net_de
+@@ -1670,6 +1673,7 @@ static int airoha_dev_open(struct net_de
phylink_start(port->phylink);
}
netif_tx_start_all_queues(dev);
err = airoha_set_vip_for_gdm_port(port, true);
-@@ -1738,10 +1742,12 @@ static int airoha_dev_stop(struct net_de
+@@ -1735,10 +1739,12 @@ static int airoha_dev_stop(struct net_de
}
}
return 0;
}
-@@ -2874,6 +2880,7 @@ static const struct ethtool_ops airoha_e
+@@ -2870,6 +2876,7 @@ static const struct ethtool_ops airoha_e
.get_link = ethtool_op_get_link,
};
static struct phylink_pcs *airoha_phylink_mac_select_pcs(struct phylink_config *config,
phy_interface_t interface)
{
-@@ -2887,6 +2894,7 @@ static void airoha_mac_config(struct phy
+@@ -2883,6 +2890,7 @@ static void airoha_mac_config(struct phy
const struct phylink_link_state *state)
{
}
static int airoha_metadata_dst_alloc(struct airoha_gdm_port *port)
{
-@@ -2932,6 +2940,7 @@ bool airoha_is_valid_gdm_port(struct air
+@@ -2928,6 +2936,7 @@ bool airoha_is_valid_gdm_port(struct air
return false;
}
static void airoha_mac_link_up(struct phylink_config *config, struct phy_device *phy,
unsigned int mode, phy_interface_t interface,
int speed, int duplex, bool tx_pause, bool rx_pause)
-@@ -3024,6 +3033,7 @@ static int airoha_setup_phylink(struct n
+@@ -3020,6 +3029,7 @@ static int airoha_setup_phylink(struct n
return 0;
}
static int airoha_alloc_gdm_port(struct airoha_eth *eth,
struct device_node *np)
-@@ -3096,11 +3106,13 @@ static int airoha_alloc_gdm_port(struct
- port->id = id;
+@@ -3094,11 +3104,13 @@ static int airoha_alloc_gdm_port(struct
+ port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0;
eth->ports[p] = port;
+#if defined(CONFIG_PCS_AIROHA)
return airoha_metadata_dst_alloc(port);
}
-@@ -3231,10 +3243,12 @@ error_napi_stop:
+@@ -3229,10 +3241,12 @@ error_napi_stop:
if (port->dev->reg_state == NETREG_REGISTERED)
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
airoha_hw_cleanup(eth);
-@@ -3261,10 +3275,12 @@ static void airoha_remove(struct platfor
+@@ -3259,10 +3273,12 @@ static void airoha_remove(struct platfor
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
-@@ -538,9 +538,11 @@ struct airoha_gdm_port {
- struct net_device *dev;
+@@ -539,9 +539,11 @@ struct airoha_gdm_port {
int id;
+ int nbq;
+#if defined(CONFIG_PCS_AIROHA)
struct phylink *phylink;