[openwrt/openwrt] kernel: add mediatek soc ethernet performance improvements

LEDE Commits lede-commits at lists.infradead.org
Wed Nov 9 09:19:19 PST 2022


nbd pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/ceb1451c10c1588fd009021c0226823a9959e266

commit ceb1451c10c1588fd009021c0226823a9959e266
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Fri Oct 28 13:15:37 2022 +0200

    kernel: add mediatek soc ethernet performance improvements
    
    - implement multiqueue via qdma hardware shaper to deal with ports with different speeds
    - implement hardware DSA untagging
    - add NETIF_F_ALL_TSO to reduce unnecessary segmentation
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
---
 ...t-mtk_eth_soc-account-for-vlan-in-rx-head.patch |  22 +
 ...t-mtk_eth_soc-increase-tx-ring-side-for-Q.patch | 143 +++++
 ...t-mtk_eth_soc-avoid-port_mg-assignment-on.patch |  52 ++
 ...t-mtk_eth_soc-implement-multi-queue-suppo.patch | 654 +++++++++++++++++++++
 ...05-net-dsa-tag_mtk-assign-per-port-queues.patch |  20 +
 ...t-mediatek-ppe-assign-per-port-queues-for.patch |  93 +++
 ...t-mtk_eth_soc-compile-out-netsys-v2-code-.patch |  28 +
 ...-support-for-DSA-rx-offloading-via-metada.patch |  70 +++
 ...t-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch | 196 ++++++
 ...t-mtk_eth_soc-work-around-issue-with-send.patch |  78 +++
 ...-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch |  21 +
 ...t-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch |  37 ++
 ...t-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch |   8 +-
 ...-net-ethernet-mediatek-support-net-labels.patch |   8 +-
 14 files changed, 1422 insertions(+), 8 deletions(-)

diff --git a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch
new file mode 100644
index 0000000000..45af898cf0
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 27 Oct 2022 19:50:31 +0200
+Subject: [PATCH] net: ethernet: mtk_eth_soc: account for vlan in rx
+ header length
+
+The network stack assumes that devices can handle an extra VLAN tag without
+increasing the MTU
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -29,7 +29,7 @@
+ #define MTK_TX_DMA_BUF_LEN_V2	0xffff
+ #define MTK_DMA_SIZE		512
+ #define MTK_MAC_COUNT		2
+-#define MTK_RX_ETH_HLEN		(ETH_HLEN + ETH_FCS_LEN)
++#define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + ETH_FCS_LEN)
+ #define MTK_RX_HLEN		(NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
+ #define MTK_DMA_DUMMY_DESC	0xffffffff
+ #define MTK_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
diff --git a/target/linux/generic/pending-5.15/732-02-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch b/target/linux/generic/pending-5.15/732-02-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch
new file mode 100644
index 0000000000..c6526a39a8
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-02-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch
@@ -0,0 +1,143 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 27 Oct 2022 19:53:57 +0200
+Subject: [PATCH] net: ethernet: mtk_eth_soc: increase tx ring side for
+ QDMA devices
+
+In order to use the hardware traffic shaper feature, a larger tx ring is
+needed, especially for the scratch ring, which the hardware shaper uses to
+reorder packets.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -894,7 +894,7 @@ static int mtk_init_fq_dma(struct mtk_et
+ {
+ 	const struct mtk_soc_data *soc = eth->soc;
+ 	dma_addr_t phy_ring_tail;
+-	int cnt = MTK_DMA_SIZE;
++	int cnt = MTK_QDMA_RING_SIZE;
+ 	dma_addr_t dma_addr;
+ 	int i;
+ 
+@@ -2148,19 +2148,25 @@ static int mtk_tx_alloc(struct mtk_eth *
+ 	struct mtk_tx_ring *ring = &eth->tx_ring;
+ 	int i, sz = soc->txrx.txd_size;
+ 	struct mtk_tx_dma_v2 *txd;
++	int ring_size;
+ 
+-	ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf),
++	if (MTK_HAS_CAPS(soc->caps, MTK_QDMA))
++		ring_size = MTK_QDMA_RING_SIZE;
++	else
++		ring_size = MTK_DMA_SIZE;
++
++	ring->buf = kcalloc(ring_size, sizeof(*ring->buf),
+ 			       GFP_KERNEL);
+ 	if (!ring->buf)
+ 		goto no_tx_mem;
+ 
+-	ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
++	ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
+ 				       &ring->phys, GFP_KERNEL);
+ 	if (!ring->dma)
+ 		goto no_tx_mem;
+ 
+-	for (i = 0; i < MTK_DMA_SIZE; i++) {
+-		int next = (i + 1) % MTK_DMA_SIZE;
++	for (i = 0; i < ring_size; i++) {
++		int next = (i + 1) % ring_size;
+ 		u32 next_ptr = ring->phys + next * sz;
+ 
+ 		txd = ring->dma + i * sz;
+@@ -2180,22 +2186,22 @@ static int mtk_tx_alloc(struct mtk_eth *
+ 	 * descriptors in ring->dma_pdma.
+ 	 */
+ 	if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
+-		ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
++		ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
+ 						    &ring->phys_pdma, GFP_KERNEL);
+ 		if (!ring->dma_pdma)
+ 			goto no_tx_mem;
+ 
+-		for (i = 0; i < MTK_DMA_SIZE; i++) {
++		for (i = 0; i < ring_size; i++) {
+ 			ring->dma_pdma[i].txd2 = TX_DMA_DESP2_DEF;
+ 			ring->dma_pdma[i].txd4 = 0;
+ 		}
+ 	}
+ 
+-	ring->dma_size = MTK_DMA_SIZE;
+-	atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
++	ring->dma_size = ring_size;
++	atomic_set(&ring->free_count, ring_size - 2);
+ 	ring->next_free = ring->dma;
+ 	ring->last_free = (void *)txd;
+-	ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz));
++	ring->last_free_ptr = (u32)(ring->phys + ((ring_size - 1) * sz));
+ 	ring->thresh = MAX_SKB_FRAGS;
+ 
+ 	/* make sure that all changes to the dma ring are flushed before we
+@@ -2207,14 +2213,14 @@ static int mtk_tx_alloc(struct mtk_eth *
+ 		mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr);
+ 		mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr);
+ 		mtk_w32(eth,
+-			ring->phys + ((MTK_DMA_SIZE - 1) * sz),
++			ring->phys + ((ring_size - 1) * sz),
+ 			soc->reg_map->qdma.crx_ptr);
+ 		mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr);
+ 		mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,
+ 			soc->reg_map->qdma.qtx_cfg);
+ 	} else {
+ 		mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
+-		mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0);
++		mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0);
+ 		mtk_w32(eth, 0, MT7628_TX_CTX_IDX0);
+ 		mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx);
+ 	}
+@@ -2232,7 +2238,7 @@ static void mtk_tx_clean(struct mtk_eth
+ 	int i;
+ 
+ 	if (ring->buf) {
+-		for (i = 0; i < MTK_DMA_SIZE; i++)
++		for (i = 0; i < ring->dma_size; i++)
+ 			mtk_tx_unmap(eth, &ring->buf[i], false);
+ 		kfree(ring->buf);
+ 		ring->buf = NULL;
+@@ -2240,14 +2246,14 @@ static void mtk_tx_clean(struct mtk_eth
+ 
+ 	if (ring->dma) {
+ 		dma_free_coherent(eth->dma_dev,
+-				  MTK_DMA_SIZE * soc->txrx.txd_size,
++				  ring->dma_size * soc->txrx.txd_size,
+ 				  ring->dma, ring->phys);
+ 		ring->dma = NULL;
+ 	}
+ 
+ 	if (ring->dma_pdma) {
+ 		dma_free_coherent(eth->dma_dev,
+-				  MTK_DMA_SIZE * soc->txrx.txd_size,
++				  ring->dma_size * soc->txrx.txd_size,
+ 				  ring->dma_pdma, ring->phys_pdma);
+ 		ring->dma_pdma = NULL;
+ 	}
+@@ -2767,7 +2773,7 @@ static void mtk_dma_free(struct mtk_eth
+ 			netdev_reset_queue(eth->netdev[i]);
+ 	if (eth->scratch_ring) {
+ 		dma_free_coherent(eth->dma_dev,
+-				  MTK_DMA_SIZE * soc->txrx.txd_size,
++				  MTK_QDMA_RING_SIZE * soc->txrx.txd_size,
+ 				  eth->scratch_ring, eth->phy_scratch_ring);
+ 		eth->scratch_ring = NULL;
+ 		eth->phy_scratch_ring = 0;
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -27,6 +27,7 @@
+ #define MTK_MAX_RX_LENGTH_2K	2048
+ #define MTK_TX_DMA_BUF_LEN	0x3fff
+ #define MTK_TX_DMA_BUF_LEN_V2	0xffff
++#define MTK_QDMA_RING_SIZE	2048
+ #define MTK_DMA_SIZE		512
+ #define MTK_MAC_COUNT		2
+ #define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + ETH_FCS_LEN)
diff --git a/target/linux/generic/pending-5.15/732-03-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch b/target/linux/generic/pending-5.15/732-03-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch
new file mode 100644
index 0000000000..116ae011f0
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-03-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch
@@ -0,0 +1,52 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Fri, 4 Nov 2022 19:49:08 +0100
+Subject: [PATCH] net: ethernet: mtk_eth_soc: avoid port_mg assignment on
+ MT7622 and newer
+
+On newer chips, this field is unused and contains some bits related to queue
+assignment. Initialize it to 0 in those cases.
+Fix offload_version on MT7621 and MT7623, which still need the previous value.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -4197,7 +4197,7 @@ static const struct mtk_soc_data mt7621_
+ 	.hw_features = MTK_HW_FEATURES,
+ 	.required_clks = MT7621_CLKS_BITMAP,
+ 	.required_pctl = false,
+-	.offload_version = 2,
++	.offload_version = 1,
+ 	.hash_offset = 2,
+ 	.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
+ 	.txrx = {
+@@ -4237,7 +4237,7 @@ static const struct mtk_soc_data mt7623_
+ 	.hw_features = MTK_HW_FEATURES,
+ 	.required_clks = MT7623_CLKS_BITMAP,
+ 	.required_pctl = true,
+-	.offload_version = 2,
++	.offload_version = 1,
+ 	.hash_offset = 2,
+ 	.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
+ 	.txrx = {
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -215,6 +215,8 @@ int mtk_foe_entry_prepare(struct mtk_eth
+ 		val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) |
+ 		      FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf);
+ 	} else {
++		int port_mg = eth->soc->offload_version > 1 ? 0 : 0x3f;
++
+ 		val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) |
+ 		      FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) |
+ 		      FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) |
+@@ -222,7 +224,7 @@ int mtk_foe_entry_prepare(struct mtk_eth
+ 		entry->ib1 = val;
+ 
+ 		val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) |
+-		      FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
++		      FIELD_PREP(MTK_FOE_IB2_PORT_MG, port_mg) |
+ 		      FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f);
+ 	}
+ 
diff --git a/target/linux/generic/pending-5.15/732-04-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch b/target/linux/generic/pending-5.15/732-04-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch
new file mode 100644
index 0000000000..fd1898586f
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-04-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch
@@ -0,0 +1,654 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 27 Oct 2022 20:17:27 +0200
+Subject: [PATCH] net: ethernet: mtk_eth_soc: implement multi-queue
+ support for per-port queues
+
+When sending traffic to multiple ports with different link speeds, queued
+packets to one port can drown out tx to other ports.
+In order to better handle transmission to multiple ports, use the hardware
+shaper feature to implement weighted fair queueing between ports.
+Weight and maximum rate are automatically adjusted based on the link speed
+of the port.
+The first 3 queues are unrestricted and reserved for non-DSA direct tx on
+GMAC ports. The following queues are automatically assigned by the MTK DSA
+tag driver based on the target port number.
+The PPE offload code configures the queues for offloaded traffic in the same
+way.
+This feature is only supported on devices supporting QDMA. All queues still
+share the same DMA ring and descriptor pool.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -54,6 +54,7 @@ static const struct mtk_reg_map mtk_reg_
+ 	},
+ 	.qdma = {
+ 		.qtx_cfg	= 0x1800,
++		.qtx_sch	= 0x1804,
+ 		.rx_ptr		= 0x1900,
+ 		.rx_cnt_cfg	= 0x1904,
+ 		.qcrx_ptr	= 0x1908,
+@@ -61,6 +62,7 @@ static const struct mtk_reg_map mtk_reg_
+ 		.rst_idx	= 0x1a08,
+ 		.delay_irq	= 0x1a0c,
+ 		.fc_th		= 0x1a10,
++		.tx_sch_rate	= 0x1a14,
+ 		.int_grp	= 0x1a20,
+ 		.hred		= 0x1a44,
+ 		.ctx_ptr	= 0x1b00,
+@@ -113,6 +115,7 @@ static const struct mtk_reg_map mt7986_r
+ 	},
+ 	.qdma = {
+ 		.qtx_cfg	= 0x4400,
++		.qtx_sch	= 0x4404,
+ 		.rx_ptr		= 0x4500,
+ 		.rx_cnt_cfg	= 0x4504,
+ 		.qcrx_ptr	= 0x4508,
+@@ -130,6 +133,7 @@ static const struct mtk_reg_map mt7986_r
+ 		.fq_tail	= 0x4724,
+ 		.fq_count	= 0x4728,
+ 		.fq_blen	= 0x472c,
++		.tx_sch_rate	= 0x4798,
+ 	},
+ 	.gdm1_cnt		= 0x1c00,
+ 	.gdma_to_ppe0		= 0x3333,
+@@ -570,6 +574,75 @@ static void mtk_mac_link_down(struct phy
+ 	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+ }
+ 
++static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,
++				int speed)
++{
++	const struct mtk_soc_data *soc = eth->soc;
++	u32 ofs, val;
++
++	if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA))
++		return;
++
++	val = MTK_QTX_SCH_MIN_RATE_EN |
++	      /* minimum: 10 Mbps */
++	      FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
++	      FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
++	      MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
++	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++		val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
++
++	if (IS_ENABLED(CONFIG_SOC_MT7621)) {
++		switch (speed) {
++		case SPEED_10:
++			val |= MTK_QTX_SCH_MAX_RATE_EN |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 2) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
++			break;
++		case SPEED_100:
++			val |= MTK_QTX_SCH_MAX_RATE_EN |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 3);
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
++			break;
++		case SPEED_1000:
++			val |= MTK_QTX_SCH_MAX_RATE_EN |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 105) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10);
++			break;
++		default:
++			break;
++		}
++	} else {
++		switch (speed) {
++		case SPEED_10:
++			val |= MTK_QTX_SCH_MAX_RATE_EN |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
++			break;
++		case SPEED_100:
++			val |= MTK_QTX_SCH_MAX_RATE_EN |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5);
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
++			break;
++		case SPEED_1000:
++			val |= MTK_QTX_SCH_MAX_RATE_EN |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 10) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) |
++			       FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10);
++			break;
++		default:
++			break;
++		}
++	}
++
++	ofs = MTK_QTX_OFFSET * idx;
++	mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
++}
++
+ static void mtk_mac_link_up(struct phylink_config *config,
+ 			    struct phy_device *phy,
+ 			    unsigned int mode, phy_interface_t interface,
+@@ -595,6 +668,8 @@ static void mtk_mac_link_up(struct phyli
+ 		break;
+ 	}
+ 
++	mtk_set_queue_speed(mac->hw, mac->id, speed);
++
+ 	/* Configure duplex */
+ 	if (duplex == DUPLEX_FULL)
+ 		mcr |= MAC_MCR_FORCE_DPX;
+@@ -1053,7 +1128,8 @@ static void mtk_tx_set_dma_desc_v1(struc
+ 
+ 	WRITE_ONCE(desc->txd1, info->addr);
+ 
+-	data = TX_DMA_SWC | TX_DMA_PLEN0(info->size);
++	data = TX_DMA_SWC | TX_DMA_PLEN0(info->size) |
++	       FIELD_PREP(TX_DMA_PQID, info->qid);
+ 	if (info->last)
+ 		data |= TX_DMA_LS0;
+ 	WRITE_ONCE(desc->txd3, data);
+@@ -1087,9 +1163,6 @@ static void mtk_tx_set_dma_desc_v2(struc
+ 		data |= TX_DMA_LS0;
+ 	WRITE_ONCE(desc->txd3, data);
+ 
+-	if (!info->qid && mac->id)
+-		info->qid = MTK_QDMA_GMAC2_QID;
+-
+ 	data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */
+ 	data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid);
+ 	WRITE_ONCE(desc->txd4, data);
+@@ -1133,11 +1206,12 @@ static int mtk_tx_map(struct sk_buff *sk
+ 		.gso = gso,
+ 		.csum = skb->ip_summed == CHECKSUM_PARTIAL,
+ 		.vlan = skb_vlan_tag_present(skb),
+-		.qid = skb->mark & MTK_QDMA_TX_MASK,
++		.qid = skb_get_queue_mapping(skb),
+ 		.vlan_tci = skb_vlan_tag_get(skb),
+ 		.first = true,
+ 		.last = !skb_is_nonlinear(skb),
+ 	};
++	struct netdev_queue *txq;
+ 	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_eth *eth = mac->hw;
+ 	const struct mtk_soc_data *soc = eth->soc;
+@@ -1145,8 +1219,10 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	struct mtk_tx_dma *itxd_pdma, *txd_pdma;
+ 	struct mtk_tx_buf *itx_buf, *tx_buf;
+ 	int i, n_desc = 1;
++	int queue = skb_get_queue_mapping(skb);
+ 	int k = 0;
+ 
++	txq = netdev_get_tx_queue(dev, queue);
+ 	itxd = ring->next_free;
+ 	itxd_pdma = qdma_to_pdma(ring, itxd);
+ 	if (itxd == ring->last_free)
+@@ -1195,7 +1271,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 			memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
+ 			txd_info.size = min_t(unsigned int, frag_size,
+ 					      soc->txrx.dma_max_len);
+-			txd_info.qid = skb->mark & MTK_QDMA_TX_MASK;
++			txd_info.qid = queue;
+ 			txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&
+ 					!(frag_size - txd_info.size);
+ 			txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag,
+@@ -1234,7 +1310,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 			txd_pdma->txd2 |= TX_DMA_LS1;
+ 	}
+ 
+-	netdev_sent_queue(dev, skb->len);
++	netdev_tx_sent_queue(txq, skb->len);
+ 	skb_tx_timestamp(skb);
+ 
+ 	ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+@@ -1246,8 +1322,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ 	wmb();
+ 
+ 	if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
+-		if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) ||
+-		    !netdev_xmit_more())
++		if (netif_xmit_stopped(txq) || !netdev_xmit_more())
+ 			mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr);
+ 	} else {
+ 		int next_idx;
+@@ -1316,7 +1391,7 @@ static void mtk_wake_queue(struct mtk_et
+ 	for (i = 0; i < MTK_MAC_COUNT; i++) {
+ 		if (!eth->netdev[i])
+ 			continue;
+-		netif_wake_queue(eth->netdev[i]);
++		netif_tx_wake_all_queues(eth->netdev[i]);
+ 	}
+ }
+ 
+@@ -1340,7 +1415,7 @@ static netdev_tx_t mtk_start_xmit(struct
+ 
+ 	tx_num = mtk_cal_txd_req(eth, skb);
+ 	if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
+-		netif_stop_queue(dev);
++		netif_tx_stop_all_queues(dev);
+ 		netif_err(eth, tx_queued, dev,
+ 			  "Tx Ring full when queue awake!\n");
+ 		spin_unlock(&eth->page_lock);
+@@ -1366,7 +1441,7 @@ static netdev_tx_t mtk_start_xmit(struct
+ 		goto drop;
+ 
+ 	if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
+-		netif_stop_queue(dev);
++		netif_tx_stop_all_queues(dev);
+ 
+ 	spin_unlock(&eth->page_lock);
+ 
+@@ -1533,10 +1608,12 @@ static int mtk_xdp_submit_frame(struct m
+ 	struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);
+ 	const struct mtk_soc_data *soc = eth->soc;
+ 	struct mtk_tx_ring *ring = &eth->tx_ring;
++	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_tx_dma_desc_info txd_info = {
+ 		.size	= xdpf->len,
+ 		.first	= true,
+ 		.last	= !xdp_frame_has_frags(xdpf),
++		.qid	= mac->id,
+ 	};
+ 	int err, index = 0, n_desc = 1, nr_frags;
+ 	struct mtk_tx_dma *htxd, *txd, *txd_pdma;
+@@ -1587,6 +1664,7 @@ static int mtk_xdp_submit_frame(struct m
+ 		memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
+ 		txd_info.size = skb_frag_size(&sinfo->frags[index]);
+ 		txd_info.last = index + 1 == nr_frags;
++		txd_info.qid = mac->id;
+ 		data = skb_frag_address(&sinfo->frags[index]);
+ 
+ 		index++;
+@@ -1938,8 +2016,46 @@ rx_done:
+ 	return done;
+ }
+ 
++struct mtk_poll_state {
++    struct netdev_queue *txq;
++    unsigned int total;
++    unsigned int done;
++    unsigned int bytes;
++};
++
++static void
++mtk_poll_tx_done(struct mtk_eth *eth, struct mtk_poll_state *state, u8 mac,
++		 struct sk_buff *skb)
++{
++	struct netdev_queue *txq;
++	struct net_device *dev;
++	unsigned int bytes = skb->len;
++
++	state->total++;
++	eth->tx_packets++;
++	eth->tx_bytes += bytes;
++
++	dev = eth->netdev[mac];
++	if (!dev)
++		return;
++
++	txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
++	if (state->txq == txq) {
++		state->done++;
++		state->bytes += bytes;
++		return;
++	}
++
++	if (state->txq)
++		netdev_tx_completed_queue(state->txq, state->done, state->bytes);
++
++	state->txq = txq;
++	state->done = 1;
++	state->bytes = bytes;
++}
++
+ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,
+-			    unsigned int *done, unsigned int *bytes)
++			    struct mtk_poll_state *state)
+ {
+ 	const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+ 	struct mtk_tx_ring *ring = &eth->tx_ring;
+@@ -1969,12 +2085,9 @@ static int mtk_poll_tx_qdma(struct mtk_e
+ 			break;
+ 
+ 		if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {
+-			if (tx_buf->type == MTK_TYPE_SKB) {
+-				struct sk_buff *skb = tx_buf->data;
++			if (tx_buf->type == MTK_TYPE_SKB)
++				mtk_poll_tx_done(eth, state, mac, tx_buf->data);
+ 
+-				bytes[mac] += skb->len;
+-				done[mac]++;
+-			}
+ 			budget--;
+ 		}
+ 		mtk_tx_unmap(eth, tx_buf, true);
+@@ -1992,7 +2105,7 @@ static int mtk_poll_tx_qdma(struct mtk_e
+ }
+ 
+ static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget,
+-			    unsigned int *done, unsigned int *bytes)
++			    struct mtk_poll_state *state)
+ {
+ 	struct mtk_tx_ring *ring = &eth->tx_ring;
+ 	struct mtk_tx_buf *tx_buf;
+@@ -2008,12 +2121,8 @@ static int mtk_poll_tx_pdma(struct mtk_e
+ 			break;
+ 
+ 		if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {
+-			if (tx_buf->type == MTK_TYPE_SKB) {
+-				struct sk_buff *skb = tx_buf->data;
+-
+-				bytes[0] += skb->len;
+-				done[0]++;
+-			}
++			if (tx_buf->type == MTK_TYPE_SKB)
++				mtk_poll_tx_done(eth, state, 0, tx_buf->data);
+ 			budget--;
+ 		}
+ 		mtk_tx_unmap(eth, tx_buf, true);
+@@ -2034,26 +2143,15 @@ static int mtk_poll_tx(struct mtk_eth *e
+ {
+ 	struct mtk_tx_ring *ring = &eth->tx_ring;
+ 	struct dim_sample dim_sample = {};
+-	unsigned int done[MTK_MAX_DEVS];
+-	unsigned int bytes[MTK_MAX_DEVS];
+-	int total = 0, i;
+-
+-	memset(done, 0, sizeof(done));
+-	memset(bytes, 0, sizeof(bytes));
++	struct mtk_poll_state state = {};
+ 
+ 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+-		budget = mtk_poll_tx_qdma(eth, budget, done, bytes);
++		budget = mtk_poll_tx_qdma(eth, budget, &state);
+ 	else
+-		budget = mtk_poll_tx_pdma(eth, budget, done, bytes);
++		budget = mtk_poll_tx_pdma(eth, budget, &state);
+ 
+-	for (i = 0; i < MTK_MAC_COUNT; i++) {
+-		if (!eth->netdev[i] || !done[i])
+-			continue;
+-		netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+-		total += done[i];
+-		eth->tx_packets += done[i];
+-		eth->tx_bytes += bytes[i];
+-	}
++	if (state.txq)
++		netdev_tx_completed_queue(state.txq, state.done, state.bytes);
+ 
+ 	dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes,
+ 			  &dim_sample);
+@@ -2063,7 +2161,7 @@ static int mtk_poll_tx(struct mtk_eth *e
+ 	    (atomic_read(&ring->free_count) > ring->thresh))
+ 		mtk_wake_queue(eth);
+ 
+-	return total;
++	return state.total;
+ }
+ 
+ static void mtk_handle_status_irq(struct mtk_eth *eth)
+@@ -2149,6 +2247,7 @@ static int mtk_tx_alloc(struct mtk_eth *
+ 	int i, sz = soc->txrx.txd_size;
+ 	struct mtk_tx_dma_v2 *txd;
+ 	int ring_size;
++	u32 ofs, val;
+ 
+ 	if (MTK_HAS_CAPS(soc->caps, MTK_QDMA))
+ 		ring_size = MTK_QDMA_RING_SIZE;
+@@ -2216,8 +2315,25 @@ static int mtk_tx_alloc(struct mtk_eth *
+ 			ring->phys + ((ring_size - 1) * sz),
+ 			soc->reg_map->qdma.crx_ptr);
+ 		mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr);
+-		mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,
+-			soc->reg_map->qdma.qtx_cfg);
++
++		for (i = 0, ofs = 0; i < MTK_QDMA_NUM_QUEUES; i++) {
++			val = (QDMA_RES_THRES << 8) | QDMA_RES_THRES;
++			mtk_w32(eth, val, soc->reg_map->qdma.qtx_cfg + ofs);
++
++			val = MTK_QTX_SCH_MIN_RATE_EN |
++			      /* minimum: 10 Mbps */
++			      FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
++			      FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
++			      MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
++			if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++				val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
++			mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
++			ofs += MTK_QTX_OFFSET;
++		}
++		val = MTK_QDMA_TX_SCH_MAX_WFQ | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
++		mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate);
++		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++			mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate + 4);
+ 	} else {
+ 		mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
+ 		mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0);
+@@ -2882,7 +2998,7 @@ static int mtk_start_dma(struct mtk_eth
+ 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ 			val |= MTK_MUTLI_CNT | MTK_RESV_BUF |
+ 			       MTK_WCOMP_EN | MTK_DMAD_WR_WDONE |
+-			       MTK_CHK_DDONE_EN;
++			       MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN;
+ 		else
+ 			val |= MTK_RX_BT_32DWORDS;
+ 		mtk_w32(eth, val, reg_map->qdma.glo_cfg);
+@@ -2928,6 +3044,45 @@ static void mtk_gdm_config(struct mtk_et
+ 	mtk_w32(eth, 0, MTK_RST_GL);
+ }
+ 
++static int mtk_device_event(struct notifier_block *n, unsigned long event, void *ptr)
++{
++	struct mtk_mac *mac = container_of(n, struct mtk_mac, device_notifier);
++	struct mtk_eth *eth = mac->hw;
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++	struct ethtool_link_ksettings s;
++	struct net_device *ldev;
++	struct list_head *iter;
++	struct dsa_port *dp;
++
++	if (event != NETDEV_CHANGE)
++		return NOTIFY_DONE;
++
++	netdev_for_each_lower_dev(dev, ldev, iter) {
++		if (netdev_priv(ldev) == mac)
++			goto found;
++	}
++
++	return NOTIFY_DONE;
++
++found:
++	if (!dsa_slave_dev_check(dev))
++		return NOTIFY_DONE;
++
++	if (__ethtool_get_link_ksettings(dev, &s))
++		return NOTIFY_DONE;
++
++	if (s.base.speed == 0 || s.base.speed == ((__u32)-1))
++		return NOTIFY_DONE;
++
++	dp = dsa_port_from_netdev(dev);
++	if (dp->index >= MTK_QDMA_NUM_QUEUES)
++		return NOTIFY_DONE;
++
++	mtk_set_queue_speed(eth, dp->index + 3, s.base.speed);
++
++	return NOTIFY_DONE;
++}
++
+ static int mtk_open(struct net_device *dev)
+ {
+ 	struct mtk_mac *mac = netdev_priv(dev);
+@@ -2970,7 +3125,8 @@ static int mtk_open(struct net_device *d
+ 		refcount_inc(&eth->dma_refcnt);
+ 
+ 	phylink_start(mac->phylink);
+-	netif_start_queue(dev);
++	netif_tx_start_all_queues(dev);
++
+ 	return 0;
+ }
+ 
+@@ -3486,8 +3642,12 @@ static int mtk_unreg_dev(struct mtk_eth
+ 	int i;
+ 
+ 	for (i = 0; i < MTK_MAC_COUNT; i++) {
++		struct mtk_mac *mac;
+ 		if (!eth->netdev[i])
+ 			continue;
++		mac = netdev_priv(eth->netdev[i]);
++		if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
++			unregister_netdevice_notifier(&mac->device_notifier);
+ 		unregister_netdev(eth->netdev[i]);
+ 	}
+ 
+@@ -3703,6 +3863,23 @@ static int mtk_set_rxnfc(struct net_devi
+ 	return ret;
+ }
+ 
++static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
++			    struct net_device *sb_dev)
++{
++	struct mtk_mac *mac = netdev_priv(dev);
++	unsigned int queue = 0;
++
++	if (netdev_uses_dsa(dev))
++		queue = skb_get_queue_mapping(skb) + 3;
++	else
++		queue = mac->id;
++
++	if (queue >= dev->num_tx_queues)
++		queue = 0;
++
++	return queue;
++}
++
+ static const struct ethtool_ops mtk_ethtool_ops = {
+ 	.get_link_ksettings	= mtk_get_link_ksettings,
+ 	.set_link_ksettings	= mtk_set_link_ksettings,
+@@ -3738,6 +3915,7 @@ static const struct net_device_ops mtk_n
+ 	.ndo_setup_tc		= mtk_eth_setup_tc,
+ 	.ndo_bpf		= mtk_xdp,
+ 	.ndo_xdp_xmit		= mtk_xdp_xmit,
++	.ndo_select_queue	= mtk_select_queue,
+ };
+ 
+ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -3747,6 +3925,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ 	struct phylink *phylink;
+ 	struct mtk_mac *mac;
+ 	int id, err;
++	int txqs = 1;
+ 
+ 	if (!_id) {
+ 		dev_err(eth->dev, "missing mac id\n");
+@@ -3764,7 +3943,10 @@ static int mtk_add_mac(struct mtk_eth *e
+ 		return -EINVAL;
+ 	}
+ 
+-	eth->netdev[id] = alloc_etherdev(sizeof(*mac));
++	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
++		txqs = MTK_QDMA_NUM_QUEUES;
++
++	eth->netdev[id] = alloc_etherdev_mqs(sizeof(*mac), txqs, 1);
+ 	if (!eth->netdev[id]) {
+ 		dev_err(eth->dev, "alloc_etherdev failed\n");
+ 		return -ENOMEM;
+@@ -3861,6 +4043,11 @@ static int mtk_add_mac(struct mtk_eth *e
+ 	else
+ 		eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN;
+ 
++	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
++		mac->device_notifier.notifier_call = mtk_device_event;
++		register_netdevice_notifier(&mac->device_notifier);
++	}
++
+ 	return 0;
+ 
+ free_netdev:
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -22,6 +22,7 @@
+ #include <linux/bpf_trace.h>
+ #include "mtk_ppe.h"
+ 
++#define MTK_QDMA_NUM_QUEUES	16
+ #define MTK_QDMA_PAGE_SIZE	2048
+ #define MTK_MAX_RX_LENGTH	1536
+ #define MTK_MAX_RX_LENGTH_2K	2048
+@@ -203,8 +204,26 @@
+ #define MTK_RING_MAX_AGG_CNT_H		((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3)
+ 
+ /* QDMA TX Queue Configuration Registers */
++#define MTK_QTX_OFFSET		0x10
+ #define QDMA_RES_THRES		4
+ 
++/* QDMA Tx Queue Scheduler Configuration Registers */
++#define MTK_QTX_SCH_TX_SEL		BIT(31)
++#define MTK_QTX_SCH_TX_SEL_V2		GENMASK(31, 30)
++
++#define MTK_QTX_SCH_LEAKY_BUCKET_EN	BIT(30)
++#define MTK_QTX_SCH_LEAKY_BUCKET_SIZE	GENMASK(29, 28)
++#define MTK_QTX_SCH_MIN_RATE_EN		BIT(27)
++#define MTK_QTX_SCH_MIN_RATE_MAN	GENMASK(26, 20)
++#define MTK_QTX_SCH_MIN_RATE_EXP	GENMASK(19, 16)
++#define MTK_QTX_SCH_MAX_RATE_WEIGHT	GENMASK(15, 12)
++#define MTK_QTX_SCH_MAX_RATE_EN		BIT(11)
++#define MTK_QTX_SCH_MAX_RATE_MAN	GENMASK(10, 4)
++#define MTK_QTX_SCH_MAX_RATE_EXP	GENMASK(3, 0)
++
++/* QDMA TX Scheduler Rate Control Register */
++#define MTK_QDMA_TX_SCH_MAX_WFQ		BIT(15)
++
+ /* QDMA Global Configuration Register */
+ #define MTK_RX_2B_OFFSET	BIT(31)
+ #define MTK_RX_BT_32DWORDS	(3 << 11)
+@@ -223,6 +242,7 @@
+ #define MTK_WCOMP_EN		BIT(24)
+ #define MTK_RESV_BUF		(0x40 << 16)
+ #define MTK_MUTLI_CNT		(0x4 << 12)
++#define MTK_LEAKY_BUCKET_EN	BIT(11)
+ 
+ /* QDMA Flow Control Register */
+ #define FC_THRES_DROP_MODE	BIT(20)
+@@ -251,8 +271,6 @@
+ #define MTK_STAT_OFFSET		0x40
+ 
+ /* QDMA TX NUM */
+-#define MTK_QDMA_TX_NUM		16
+-#define MTK_QDMA_TX_MASK	(MTK_QDMA_TX_NUM - 1)
+ #define QID_BITS_V2(x)		(((x) & 0x3f) << 16)
+ #define MTK_QDMA_GMAC2_QID	8
+ 
+@@ -282,6 +300,7 @@
+ #define TX_DMA_PLEN0(x)		(((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
+ #define TX_DMA_PLEN1(x)		((x) & eth->soc->txrx.dma_max_len)
+ #define TX_DMA_SWC		BIT(14)
++#define TX_DMA_PQID		GENMASK(3, 0)
+ 
+ /* PDMA on MT7628 */
+ #define TX_DMA_DONE		BIT(31)
+@@ -930,6 +949,7 @@ struct mtk_reg_map {
+ 	} pdma;
+ 	struct {
+ 		u32	qtx_cfg;	/* tx queue configuration */
++		u32	qtx_sch;	/* tx queue scheduler configuration */
+ 		u32	rx_ptr;		/* rx base pointer */
+ 		u32	rx_cnt_cfg;	/* rx max count configuration */
+ 		u32	qcrx_ptr;	/* rx cpu pointer */
+@@ -947,6 +967,7 @@ struct mtk_reg_map {
+ 		u32	fq_tail;	/* fq tail pointer */
+ 		u32	fq_count;	/* fq free page count */
+ 		u32	fq_blen;	/* fq free page buffer length */
++		u32	tx_sch_rate;	/* tx scheduler rate control registers */
+ 	} qdma;
+ 	u32	gdm1_cnt;
+ 	u32	gdma_to_ppe0;
+@@ -1139,6 +1160,7 @@ struct mtk_mac {
+ 	__be32				hwlro_ip[MTK_MAX_LRO_IP_CNT];
+ 	int				hwlro_ip_cnt;
+ 	unsigned int			syscfg0;
++	struct notifier_block		device_notifier;
+ };
+ 
+ /* the struct describing the SoC. these are declared in the soc_xyz.c files */
diff --git a/target/linux/generic/pending-5.15/732-05-net-dsa-tag_mtk-assign-per-port-queues.patch b/target/linux/generic/pending-5.15/732-05-net-dsa-tag_mtk-assign-per-port-queues.patch
new file mode 100644
index 0000000000..7739366ade
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-05-net-dsa-tag_mtk-assign-per-port-queues.patch
@@ -0,0 +1,20 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Fri, 28 Oct 2022 18:16:03 +0200
+Subject: [PATCH] net: dsa: tag_mtk: assign per-port queues
+
+Keeps traffic sent to the switch within link speed limits
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -33,6 +33,8 @@ static struct sk_buff *mtk_tag_xmit(stru
+ 	if (__skb_put_padto(skb, ETH_ZLEN + MTK_HDR_LEN, false))
+ 		return NULL;
+ 
++	skb_set_queue_mapping(skb, dp->index);
++
+ 	/* Build the special tag after the MAC Source Address. If VLAN header
+ 	 * is present, it's required that VLAN header and special tag is
+ 	 * being combined. Only in this way we can allow the switch can parse
diff --git a/target/linux/generic/pending-5.15/732-06-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch b/target/linux/generic/pending-5.15/732-06-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch
new file mode 100644
index 0000000000..05161c3479
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-06-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch
@@ -0,0 +1,93 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 3 Nov 2022 17:49:44 +0100
+Subject: [PATCH] net: ethernet: mediatek: ppe: assign per-port queues
+ for offloaded traffic
+
+Keeps traffic sent to the switch within link speed limits
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -445,6 +445,24 @@ static inline bool mtk_foe_entry_usable(
+ 	       FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
+ }
+ 
++int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
++			    unsigned int queue)
++{
++	u32 *ib2 = mtk_foe_entry_ib2(eth, entry);
++
++	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
++		*ib2 &= ~MTK_FOE_IB2_QID_V2;
++		*ib2 |= FIELD_PREP(MTK_FOE_IB2_QID_V2, queue);
++		*ib2 |= MTK_FOE_IB2_PSE_QOS_V2;
++	} else {
++		*ib2 &= ~MTK_FOE_IB2_QID;
++		*ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, queue);
++		*ib2 |= MTK_FOE_IB2_PSE_QOS;
++	}
++
++	return 0;
++}
++
+ static bool
+ mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry,
+ 		     struct mtk_foe_entry *data)
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -69,7 +69,9 @@ enum {
+ #define MTK_FOE_IB2_DSCP		GENMASK(31, 24)
+ 
+ /* CONFIG_MEDIATEK_NETSYS_V2 */
++#define MTK_FOE_IB2_QID_V2			GENMASK(6, 0)
+ #define MTK_FOE_IB2_PORT_MG_V2		BIT(7)
++#define MTK_FOE_IB2_PSE_QOS_V2		BIT(8)
+ #define MTK_FOE_IB2_DEST_PORT_V2	GENMASK(12, 9)
+ #define MTK_FOE_IB2_MULTICAST_V2	BIT(13)
+ #define MTK_FOE_IB2_WDMA_WINFO_V2	BIT(19)
+@@ -369,6 +371,8 @@ int mtk_foe_entry_set_pppoe(struct mtk_e
+ 			    int sid);
+ int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
+ 			   int wdma_idx, int txq, int bss, int wcid);
++int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
++			    unsigned int queue);
+ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -188,7 +188,7 @@ mtk_flow_set_output_device(struct mtk_et
+ 			   int *wed_index)
+ {
+ 	struct mtk_wdma_info info = {};
+-	int pse_port, dsa_port;
++	int pse_port, dsa_port, queue;
+ 
+ 	if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
+ 		mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue,
+@@ -212,8 +212,6 @@ mtk_flow_set_output_device(struct mtk_et
+ 	}
+ 
+ 	dsa_port = mtk_flow_get_dsa_port(&dev);
+-	if (dsa_port >= 0)
+-		mtk_foe_entry_set_dsa(eth, foe, dsa_port);
+ 
+ 	if (dev == eth->netdev[0])
+ 		pse_port = 1;
+@@ -222,6 +220,14 @@ mtk_flow_set_output_device(struct mtk_et
+ 	else
+ 		return -EOPNOTSUPP;
+ 
++	if (dsa_port >= 0) {
++		mtk_foe_entry_set_dsa(eth, foe, dsa_port);
++		queue = 3 + dsa_port;
++	} else {
++		queue = pse_port - 1;
++	}
++	mtk_foe_entry_set_queue(eth, foe, queue);
++
+ out:
+ 	mtk_foe_entry_set_pse_port(eth, foe, pse_port);
+ 
diff --git a/target/linux/generic/pending-5.15/732-07-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch b/target/linux/generic/pending-5.15/732-07-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch
new file mode 100644
index 0000000000..8c711ba802
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-07-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch
@@ -0,0 +1,28 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 27 Oct 2022 23:39:52 +0200
+Subject: [PATCH] net: ethernet: mtk_eth_soc: compile out netsys v2 code
+ on mt7621
+
+Avoid some branches in the hot path on low-end devices with limited CPU power,
+and reduce code size
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -895,7 +895,13 @@ enum mkt_eth_capabilities {
+ #define MTK_MUX_GMAC12_TO_GEPHY_SGMII   \
+ 	(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX)
+ 
+-#define MTK_HAS_CAPS(caps, _x)		(((caps) & (_x)) == (_x))
++#ifdef CONFIG_SOC_MT7621
++#define MTK_CAP_MASK MTK_NETSYS_V2
++#else
++#define MTK_CAP_MASK 0
++#endif
++
++#define MTK_HAS_CAPS(caps, _x)		(((caps) & (_x) & ~(MTK_CAP_MASK)) == (_x))
+ 
+ #define MT7621_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \
+ 		      MTK_GMAC2_RGMII | MTK_SHARED_INT | \
diff --git a/target/linux/generic/pending-5.15/732-08-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch b/target/linux/generic/pending-5.15/732-08-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch
new file mode 100644
index 0000000000..7fe7e5c07d
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-08-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch
@@ -0,0 +1,70 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Tue, 8 Nov 2022 15:03:15 +0100
+Subject: [PATCH] net: dsa: add support for DSA rx offloading via
+ metadata dst
+
+If a metadata dst is present with the type METADATA_HW_PORT_MUX on a dsa cpu
+port netdev, assume that it carries the port number and that there is no DSA
+tag present in the skb data.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/net/core/flow_dissector.c
++++ b/net/core/flow_dissector.c
+@@ -941,11 +941,13 @@ bool __skb_flow_dissect(const struct net
+ 		if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) &&
+ 			     proto == htons(ETH_P_XDSA))) {
+ 			const struct dsa_device_ops *ops;
++			struct metadata_dst *md_dst = skb_metadata_dst(skb);
+ 			int offset = 0;
+ 
+ 			ops = skb->dev->dsa_ptr->tag_ops;
+ 			/* Only DSA header taggers break flow dissection */
+-			if (ops->needed_headroom) {
++			if (ops->needed_headroom &&
++			    (!md_dst || md_dst->type != METADATA_HW_PORT_MUX)) {
+ 				if (ops->flow_dissect)
+ 					ops->flow_dissect(skb, &proto, &offset);
+ 				else
+--- a/net/dsa/dsa.c
++++ b/net/dsa/dsa.c
+@@ -20,6 +20,7 @@
+ #include <linux/phy_fixed.h>
+ #include <linux/ptp_classify.h>
+ #include <linux/etherdevice.h>
++#include <net/dst_metadata.h>
+ 
+ #include "dsa_priv.h"
+ 
+@@ -225,6 +226,7 @@ static bool dsa_skb_defer_rx_timestamp(s
+ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
+ 			  struct packet_type *pt, struct net_device *unused)
+ {
++	struct metadata_dst *md_dst = skb_metadata_dst(skb);
+ 	struct dsa_port *cpu_dp = dev->dsa_ptr;
+ 	struct sk_buff *nskb = NULL;
+ 	struct dsa_slave_priv *p;
+@@ -238,7 +240,21 @@ static int dsa_switch_rcv(struct sk_buff
+ 	if (!skb)
+ 		return 0;
+ 
+-	nskb = cpu_dp->rcv(skb, dev);
++	if (md_dst && md_dst->type == METADATA_HW_PORT_MUX) {
++		unsigned int port = md_dst->u.port_info.port_id;
++
++		dsa_default_offload_fwd_mark(skb);
++		skb_dst_set(skb, NULL);
++		if (!skb_has_extensions(skb))
++			skb->slow_gro = 0;
++
++		skb->dev = dsa_master_find_slave(dev, 0, port);
++		if (skb->dev)
++			nskb = skb;
++	} else {
++		nskb = cpu_dp->rcv(skb, dev);
++	}
++
+ 	if (!nskb) {
+ 		kfree_skb(skb);
+ 		return 0;
diff --git a/target/linux/generic/pending-5.15/732-09-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch b/target/linux/generic/pending-5.15/732-09-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch
new file mode 100644
index 0000000000..d1f82215ca
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-09-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch
@@ -0,0 +1,196 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Fri, 28 Oct 2022 11:01:12 +0200
+Subject: [PATCH] net: ethernet: mtk_eth_soc: fix VLAN rx hardware
+ acceleration
+
+- enable VLAN untagging for PDMA rx
+- make it possible to disable the feature via ethtool
+- pass VLAN tag to the DSA driver
+- untag special tag on PDMA only if no non-DSA devices are in use
+- disable special tag untagging on 7986 for now, since it's not working yet
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -23,6 +23,7 @@
+ #include <linux/jhash.h>
+ #include <linux/bitfield.h>
+ #include <net/dsa.h>
++#include <net/dst_metadata.h>
+ 
+ #include "mtk_eth_soc.h"
+ #include "mtk_wed.h"
+@@ -1960,23 +1961,27 @@ static int mtk_poll_rx(struct napi_struc
+ 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+ 			mtk_ppe_check_skb(eth->ppe[0], skb, hash);
+ 
+-		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+-			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+-				if (trxd.rxd3 & RX_DMA_VTAG_V2)
+-					__vlan_hwaccel_put_tag(skb,
+-						htons(RX_DMA_VPID(trxd.rxd4)),
+-						RX_DMA_VID(trxd.rxd4));
+-			} else if (trxd.rxd2 & RX_DMA_VTAG) {
+-				__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+-						       RX_DMA_VID(trxd.rxd3));
+-			}
++		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
++			if (trxd.rxd3 & RX_DMA_VTAG_V2)
++				__vlan_hwaccel_put_tag(skb,
++					htons(RX_DMA_VPID(trxd.rxd4)),
++					RX_DMA_VID(trxd.rxd4));
++		} else if (trxd.rxd2 & RX_DMA_VTAG) {
++			__vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)),
++					       RX_DMA_VID(trxd.rxd3));
++		}
++
++		/* When using VLAN untagging in combination with DSA, the
++		 * hardware treats the MTK special tag as a VLAN and untags it.
++		 */
++		if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) {
++			unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0);
++
++			if (port < ARRAY_SIZE(eth->dsa_meta) &&
++			    eth->dsa_meta[port])
++				skb_dst_set_noref(skb, &eth->dsa_meta[port]->dst);
+ 
+-			/* If the device is attached to a dsa switch, the special
+-			 * tag inserted in VLAN field by hw switch can * be offloaded
+-			 * by RX HW VLAN offload. Clear vlan info.
+-			 */
+-			if (netdev_uses_dsa(netdev))
+-				__vlan_hwaccel_clear_tag(skb);
++			__vlan_hwaccel_clear_tag(skb);
+ 		}
+ 
+ 		skb_record_rx_queue(skb, 0);
+@@ -2793,15 +2798,19 @@ static netdev_features_t mtk_fix_feature
+ 
+ static int mtk_set_features(struct net_device *dev, netdev_features_t features)
+ {
+-	int err = 0;
+-
+-	if (!((dev->features ^ features) & NETIF_F_LRO))
+-		return 0;
++	struct mtk_mac *mac = netdev_priv(dev);
++	struct mtk_eth *eth = mac->hw;
++	netdev_features_t diff = dev->features ^ features;
+ 
+-	if (!(features & NETIF_F_LRO))
++	if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
+ 		mtk_hwlro_netdev_disable(dev);
+ 
+-	return err;
++	/* Set RX VLAN offloading */
++	if (diff & NETIF_F_HW_VLAN_CTAG_RX)
++		mtk_w32(eth, !!(features & NETIF_F_HW_VLAN_CTAG_RX),
++			MTK_CDMP_EG_CTRL);
++
++	return 0;
+ }
+ 
+ /* wait for DMA to finish whatever it is doing before we start using it again */
+@@ -3083,11 +3092,45 @@ found:
+ 	return NOTIFY_DONE;
+ }
+ 
++static bool mtk_uses_dsa(struct net_device *dev)
++{
++#if IS_ENABLED(CONFIG_NET_DSA)
++	return netdev_uses_dsa(dev) &&
++	       dev->dsa_ptr->tag_ops->proto == DSA_TAG_PROTO_MTK;
++#else
++	return false;
++#endif
++}
++
+ static int mtk_open(struct net_device *dev)
+ {
+ 	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_eth *eth = mac->hw;
+-	int err;
++	int i, err;
++
++	if (mtk_uses_dsa(dev)) {
++		for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) {
++			struct metadata_dst *md_dst = eth->dsa_meta[i];
++
++			if (md_dst)
++				continue;
++
++			md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
++						    GFP_KERNEL);
++			if (!md_dst)
++				return -ENOMEM;
++
++			md_dst->u.port_info.port_id = i;
++			eth->dsa_meta[i] = md_dst;
++		}
++	} else {
++		/* Hardware special tag parsing needs to be disabled if at least
++		 * one MAC does not use DSA.
++		 */
++		u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
++		val &= ~MTK_CDMP_STAG_EN;
++		mtk_w32(eth, val, MTK_CDMP_IG_CTRL);
++	}
+ 
+ 	err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
+ 	if (err) {
+@@ -3417,6 +3460,10 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	 */
+ 	val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+ 	mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
++	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
++		val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
++		mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
++	}
+ 
+ 	/* Enable RX VLan Offloading */
+ 	mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+@@ -3634,6 +3681,12 @@ static int mtk_free_dev(struct mtk_eth *
+ 		free_netdev(eth->netdev[i]);
+ 	}
+ 
++	for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) {
++		if (!eth->dsa_meta[i])
++			break;
++		metadata_dst_free(eth->dsa_meta[i]);
++	}
++
+ 	return 0;
+ }
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -22,6 +22,9 @@
+ #include <linux/bpf_trace.h>
+ #include "mtk_ppe.h"
+ 
++#define MTK_MAX_DSA_PORTS	7
++#define MTK_DSA_PORT_MASK	GENMASK(2, 0)
++
+ #define MTK_QDMA_NUM_QUEUES	16
+ #define MTK_QDMA_PAGE_SIZE	2048
+ #define MTK_MAX_RX_LENGTH	1536
+@@ -93,6 +96,9 @@
+ #define MTK_CDMQ_IG_CTRL	0x1400
+ #define MTK_CDMQ_STAG_EN	BIT(0)
+ 
++/* CDMQ Exgress Control Register */
++#define MTK_CDMQ_EG_CTRL	0x1404
++
+ /* CDMP Ingress Control Register */
+ #define MTK_CDMP_IG_CTRL	0x400
+ #define MTK_CDMP_STAG_EN	BIT(0)
+@@ -1140,6 +1146,8 @@ struct mtk_eth {
+ 
+ 	int				ip_align;
+ 
++	struct metadata_dst		*dsa_meta[MTK_MAX_DSA_PORTS];
++
+ 	struct mtk_ppe			*ppe[2];
+ 	struct rhashtable		flow_table;
+ 
diff --git a/target/linux/generic/pending-5.15/732-10-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch b/target/linux/generic/pending-5.15/732-10-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch
new file mode 100644
index 0000000000..ba86686eeb
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-10-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch
@@ -0,0 +1,78 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 3 Nov 2022 12:38:49 +0100
+Subject: [PATCH] net: ethernet: mtk_eth_soc: work around issue with
+ sending small fragments
+
+When frames are sent with very small fragments, the DMA engine appears to
+lock up and transmit attempts time out. Fix this by detecting the presence
+of small fragments and use skb_gso_segment + skb_linearize to deal with
+them
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1396,12 +1396,28 @@ static void mtk_wake_queue(struct mtk_et
+ 	}
+ }
+ 
++static bool mtk_skb_has_small_frag(struct sk_buff *skb)
++{
++	int min_size = 16;
++	int i;
++
++	if (skb_headlen(skb) < min_size)
++		return true;
++
++	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
++		if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size)
++			return true;
++
++	return false;
++}
++
+ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ 	struct mtk_mac *mac = netdev_priv(dev);
+ 	struct mtk_eth *eth = mac->hw;
+ 	struct mtk_tx_ring *ring = &eth->tx_ring;
+ 	struct net_device_stats *stats = &dev->stats;
++	struct sk_buff *segs, *next;
+ 	bool gso = false;
+ 	int tx_num;
+ 
+@@ -1423,6 +1439,17 @@ static netdev_tx_t mtk_start_xmit(struct
+ 		return NETDEV_TX_BUSY;
+ 	}
+ 
++	if (skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) {
++		segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO);
++		if (IS_ERR(segs))
++			goto drop;
++
++		if (segs) {
++			consume_skb(skb);
++			skb = segs;
++		}
++	}
++
+ 	/* TSO: fill MSS info in tcp checksum field */
+ 	if (skb_is_gso(skb)) {
+ 		if (skb_cow_head(skb, 0)) {
+@@ -1438,8 +1465,13 @@ static netdev_tx_t mtk_start_xmit(struct
+ 		}
+ 	}
+ 
+-	if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
+-		goto drop;
++	skb_list_walk_safe(skb, skb, next) {
++		if ((mtk_skb_has_small_frag(skb) && skb_linearize(skb)) ||
++		    mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) {
++			stats->tx_dropped++;
++			dev_kfree_skb_any(skb);
++		}
++	}
+ 
+ 	if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
+ 		netif_tx_stop_all_queues(dev);
diff --git a/target/linux/generic/pending-5.15/732-11-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch b/target/linux/generic/pending-5.15/732-11-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch
new file mode 100644
index 0000000000..f89ad6adb1
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-11-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch
@@ -0,0 +1,21 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Fri, 28 Oct 2022 12:54:48 +0200
+Subject: [PATCH] net: ethernet: mtk_eth_soc: set NETIF_F_ALL_TSO
+
+Significantly improves performance by avoiding unnecessary segmentation
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -49,8 +49,7 @@
+ 				 NETIF_F_RXCSUM | \
+ 				 NETIF_F_HW_VLAN_CTAG_TX | \
+ 				 NETIF_F_HW_VLAN_CTAG_RX | \
+-				 NETIF_F_SG | NETIF_F_TSO | \
+-				 NETIF_F_TSO6 | \
++				 NETIF_F_SG | NETIF_F_ALL_TSO | \
+ 				 NETIF_F_IPV6_CSUM |\
+ 				 NETIF_F_HW_TC)
+ #define MTK_HW_FEATURES_MT7628	(NETIF_F_SG | NETIF_F_RXCSUM)
diff --git a/target/linux/generic/pending-5.15/732-12-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch b/target/linux/generic/pending-5.15/732-12-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch
new file mode 100644
index 0000000000..85937fa9a0
--- /dev/null
+++ b/target/linux/generic/pending-5.15/732-12-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Thu, 3 Nov 2022 17:46:25 +0100
+Subject: [PATCH] net: ethernet: mtk_eth_soc: drop packets to WDMA if the
+ ring is full
+
+Improves handling of DMA ring overflow.
+Clarify other WDMA drop related comment.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -3516,9 +3516,12 @@ static int mtk_hw_init(struct mtk_eth *e
+ 	mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+ 
+ 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+-		/* PSE should not drop port8 and port9 packets */
++		/* PSE should not drop port8 and port9 packets from WDMA Tx */
+ 		mtk_w32(eth, 0x00000300, PSE_DROP_CFG);
+ 
++		/* PSE should drop packets to port 8/9 on WDMA Rx ring full */
++		mtk_w32(eth, 0x00000300, PSE_PPE0_DROP);
++
+ 		/* PSE Free Queue Flow Control  */
+ 		mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2);
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -127,6 +127,7 @@
+ #define PSE_FQFC_CFG1		0x100
+ #define PSE_FQFC_CFG2		0x104
+ #define PSE_DROP_CFG		0x108
++#define PSE_PPE0_DROP		0x110
+ 
+ /* PSE Input Queue Reservation Register*/
+ #define PSE_IQ_REV(x)		(0x140 + (((x) - 1) << 2))
diff --git a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch
index 9667930aa1..9c8f2746c8 100644
--- a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch
+++ b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch
@@ -20,7 +20,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
 
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -219,13 +219,35 @@ static int _mtk_mdio_write(struct mtk_et
+@@ -224,13 +224,35 @@ static int _mtk_mdio_write(struct mtk_et
  	if (ret < 0)
  		return ret;
  
@@ -63,7 +63,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
  	ret = mtk_mdio_busy_wait(eth);
  	if (ret < 0)
-@@ -242,12 +264,33 @@ static int _mtk_mdio_read(struct mtk_eth
+@@ -247,12 +269,33 @@ static int _mtk_mdio_read(struct mtk_eth
  	if (ret < 0)
  		return ret;
  
@@ -103,7 +103,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
  	ret = mtk_mdio_busy_wait(eth);
  	if (ret < 0)
-@@ -644,6 +687,7 @@ static int mtk_mdio_init(struct mtk_eth
+@@ -720,6 +763,7 @@ static int mtk_mdio_init(struct mtk_eth
  	eth->mii_bus->name = "mdio";
  	eth->mii_bus->read = mtk_mdio_read;
  	eth->mii_bus->write = mtk_mdio_write;
@@ -113,7 +113,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -330,9 +330,12 @@
+@@ -356,9 +356,12 @@
  #define PHY_IAC_ADDR_MASK	GENMASK(24, 20)
  #define PHY_IAC_ADDR(x)		FIELD_PREP(PHY_IAC_ADDR_MASK, (x))
  #define PHY_IAC_CMD_MASK	GENMASK(19, 18)
diff --git a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch
index d8ce3051b7..74e8f999ab 100644
--- a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch
+++ b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch
@@ -14,7 +14,7 @@ Signed-off-by: René van Dorst <opensource at vdorst.com>
 
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3736,6 +3736,7 @@ static const struct net_device_ops mtk_n
+@@ -3918,6 +3918,7 @@ static const struct net_device_ops mtk_n
  
  static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
  {
@@ -22,9 +22,9 @@ Signed-off-by: René van Dorst <opensource at vdorst.com>
  	const __be32 *_id = of_get_property(np, "reg", NULL);
  	phy_interface_t phy_mode;
  	struct phylink *phylink;
-@@ -3855,6 +3856,9 @@ static int mtk_add_mac(struct mtk_eth *e
- 	else
- 		eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN;
+@@ -4046,6 +4047,9 @@ static int mtk_add_mac(struct mtk_eth *e
+ 		register_netdevice_notifier(&mac->device_notifier);
+ 	}
  
 +	if (name)
 +		strlcpy(eth->netdev[id]->name, name, IFNAMSIZ);




More information about the lede-commits mailing list