[openwrt/openwrt] kernel: Backport mvneta crash fix to 5.15

LEDE Commits lede-commits at lists.infradead.org
Thu Jun 8 08:28:52 PDT 2023


chunkeey pushed a commit to openwrt/openwrt.git, branch openwrt-23.05:
https://git.openwrt.org/76cabb95da1994b84a373346c46e52ec836edfc7

commit 76cabb95da1994b84a373346c46e52ec836edfc7
Author: Marek Behún <kabel at kernel.org>
AuthorDate: Wed Apr 12 13:01:25 2023 +0200

    kernel: Backport mvneta crash fix to 5.15
    
    Backport Russell King's series [1]
      net: mvneta: reduce size of TSO header allocation
    to pending-5.15 to fix random crashes on Turris Omnia.
    
    This also backports two patches that are dependencies to this series:
      net: mvneta: Delete unused variable
      net: mvneta: fix potential double-frees in mvneta_txq_sw_deinit()
    
    [1] https://lore.kernel.org/netdev/ZCsbJ4nG+So%2Fn9qY@shell.armlinux.org.uk/
    
    Signed-off-by: Marek Behún <kabel at kernel.org>
    Signed-off-by: Christian Lamparter <chunkeey at gmail.com> (squashed)
    (cherry picked from commit 7b31c2e9ed4da7bfeecbd393c17c249eca870717)
---
 ...1-v5.16-net-mvneta-Delete-unused-variable.patch |  62 +++++++
 ...fix-potential-double-frees-in-mvneta_txq_.patch |  37 +++++
 ...-fix-transmit-path-dma-unmapping-on-error.patch | 111 +++++++++++++
 ...ta-mark-mapped-and-tso-buffers-separately.patch |  42 +++++
 ...use-buf-type-to-determine-whether-to-dma-.patch |  59 +++++++
 ...move-tso_build_hdr-into-mvneta_tso_put_hd.patch |  65 ++++++++
 ...-allocate-TSO-header-DMA-memory-in-chunks.patch | 179 +++++++++++++++++++++
 .../700-mvneta-tx-queue-workaround.patch           |   4 +-
 ...next-ethernet-marvell-mvnetaMQPrioOffload.patch |   4 +-
 ...et-next-ethernet-marvell-mvnetaMQPrioFlag.patch |   2 +-
 ...t-next-ethernet-marvell-mvnetaMQPrioQueue.patch |   8 +-
 ...xt-ethernet-marvell-mvnetaMQPrioTCOffload.patch |   6 +-
 12 files changed, 567 insertions(+), 12 deletions(-)

diff --git a/target/linux/generic/backport-5.15/708-01-v5.16-net-mvneta-Delete-unused-variable.patch b/target/linux/generic/backport-5.15/708-01-v5.16-net-mvneta-Delete-unused-variable.patch
new file mode 100644
index 0000000000..421563ef08
--- /dev/null
+++ b/target/linux/generic/backport-5.15/708-01-v5.16-net-mvneta-Delete-unused-variable.patch
@@ -0,0 +1,62 @@
+From 43ed6fff01333868a1d0e19876f67c22d9939952 Mon Sep 17 00:00:00 2001
+From: Yuval Shaia <yshaia at marvell.com>
+Date: Wed, 13 Oct 2021 09:49:21 +0300
+Subject: [PATCH] net: mvneta: Delete unused variable
+
+The variable pp is not in use - delete it.
+
+Signed-off-by: Yuval Shaia <yshaia at marvell.com>
+Link: https://lore.kernel.org/r/20211013064921.26346-1-yshaia@marvell.com
+Signed-off-by: Jakub Kicinski <kuba at kernel.org>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -1914,7 +1914,7 @@ static int mvneta_rx_refill(struct mvnet
+ }
+ 
+ /* Handle tx checksum */
+-static u32 mvneta_skb_tx_csum(struct mvneta_port *pp, struct sk_buff *skb)
++static u32 mvneta_skb_tx_csum(struct sk_buff *skb)
+ {
+ 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ 		int ip_hdr_len = 0;
+@@ -2595,8 +2595,7 @@ err_drop_frame:
+ }
+ 
+ static inline void
+-mvneta_tso_put_hdr(struct sk_buff *skb,
+-		   struct mvneta_port *pp, struct mvneta_tx_queue *txq)
++mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq)
+ {
+ 	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ 	struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+@@ -2604,7 +2603,7 @@ mvneta_tso_put_hdr(struct sk_buff *skb,
+ 
+ 	tx_desc = mvneta_txq_next_desc_get(txq);
+ 	tx_desc->data_size = hdr_len;
+-	tx_desc->command = mvneta_skb_tx_csum(pp, skb);
++	tx_desc->command = mvneta_skb_tx_csum(skb);
+ 	tx_desc->command |= MVNETA_TXD_F_DESC;
+ 	tx_desc->buf_phys_addr = txq->tso_hdrs_phys +
+ 				 txq->txq_put_index * TSO_HEADER_SIZE;
+@@ -2681,7 +2680,7 @@ static int mvneta_tx_tso(struct sk_buff
+ 		hdr = txq->tso_hdrs + txq->txq_put_index * TSO_HEADER_SIZE;
+ 		tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
+ 
+-		mvneta_tso_put_hdr(skb, pp, txq);
++		mvneta_tso_put_hdr(skb, txq);
+ 
+ 		while (data_left > 0) {
+ 			int size;
+@@ -2799,7 +2798,7 @@ static netdev_tx_t mvneta_tx(struct sk_b
+ 	/* Get a descriptor for the first part of the packet */
+ 	tx_desc = mvneta_txq_next_desc_get(txq);
+ 
+-	tx_cmd = mvneta_skb_tx_csum(pp, skb);
++	tx_cmd = mvneta_skb_tx_csum(skb);
+ 
+ 	tx_desc->data_size = skb_headlen(skb);
+ 
diff --git a/target/linux/generic/backport-5.15/708-02-v6.3-net-mvneta-fix-potential-double-frees-in-mvneta_txq_.patch b/target/linux/generic/backport-5.15/708-02-v6.3-net-mvneta-fix-potential-double-frees-in-mvneta_txq_.patch
new file mode 100644
index 0000000000..a16e68ee4f
--- /dev/null
+++ b/target/linux/generic/backport-5.15/708-02-v6.3-net-mvneta-fix-potential-double-frees-in-mvneta_txq_.patch
@@ -0,0 +1,37 @@
+From 0cf39c6543469aae4a30cba354243125514ed568 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
+Date: Wed, 29 Mar 2023 13:11:17 +0100
+Subject: [PATCH] net: mvneta: fix potential double-frees in
+ mvneta_txq_sw_deinit()
+
+Reported on the Turris forum, mvneta provokes kernel warnings in the
+architecture DMA mapping code when mvneta_setup_txqs() fails to
+allocate memory. This happens because when mvneta_cleanup_txqs() is
+called in the mvneta_stop() path, we leave pointers in the structure
+that have been freed.
+
+Then on mvneta_open(), we call mvneta_setup_txqs(), which starts
+allocating memory. On memory allocation failure, mvneta_cleanup_txqs()
+will walk all the queues freeing any non-NULL pointers - which includes
+pointers that were previously freed in mvneta_stop().
+
+Fix this by setting these pointers to NULL to prevent double-freeing
+of the same memory.
+
+Link: https://forum.turris.cz/t/random-kernel-exceptions-on-hbl-tos-7-0/18865/8
+Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -3481,6 +3481,8 @@ static void mvneta_txq_sw_deinit(struct
+ 
+ 	netdev_tx_reset_queue(nq);
+ 
++	txq->buf               = NULL;
++	txq->tso_hdrs          = NULL;
+ 	txq->descs             = NULL;
+ 	txq->last_desc         = 0;
+ 	txq->next_desc_to_proc = 0;
diff --git a/target/linux/generic/pending-5.15/704-01-v6.4-net-mvneta-fix-transmit-path-dma-unmapping-on-error.patch b/target/linux/generic/pending-5.15/704-01-v6.4-net-mvneta-fix-transmit-path-dma-unmapping-on-error.patch
new file mode 100644
index 0000000000..287728ba1d
--- /dev/null
+++ b/target/linux/generic/pending-5.15/704-01-v6.4-net-mvneta-fix-transmit-path-dma-unmapping-on-error.patch
@@ -0,0 +1,111 @@
+From d6d80269cf5c79f9dfe7d69f8b41a72015c89748 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
+Date: Mon, 3 Apr 2023 19:30:20 +0100
+Subject: [PATCH 1/5] net: mvneta: fix transmit path dma-unmapping on error
+
+The transmit code assumes that the transmit descriptors that are used
+begin with the first descriptor in the ring, but this may not be the
+case. Fix this by providing a new function that dma-unmaps a range of
+numbered descriptor entries, and use that to do the unmapping.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 53 +++++++++++++++++----------
+ 1 file changed, 33 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -2647,14 +2647,40 @@ mvneta_tso_put_data(struct net_device *d
+ 	return 0;
+ }
+ 
++static void mvneta_release_descs(struct mvneta_port *pp,
++				 struct mvneta_tx_queue *txq,
++				 int first, int num)
++{
++	int desc_idx, i;
++
++	desc_idx = first + num;
++	if (desc_idx >= txq->size)
++		desc_idx -= txq->size;
++
++	for (i = num; i >= 0; i--) {
++		struct mvneta_tx_desc *tx_desc = txq->descs + desc_idx;
++
++		if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr))
++			dma_unmap_single(pp->dev->dev.parent,
++					 tx_desc->buf_phys_addr,
++					 tx_desc->data_size,
++					 DMA_TO_DEVICE);
++
++		mvneta_txq_desc_put(txq);
++
++		if (desc_idx == 0)
++			desc_idx = txq->size;
++		desc_idx -= 1;
++	}
++}
++
+ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
+ 			 struct mvneta_tx_queue *txq)
+ {
+ 	int hdr_len, total_len, data_left;
+-	int desc_count = 0;
++	int first_desc, desc_count = 0;
+ 	struct mvneta_port *pp = netdev_priv(dev);
+ 	struct tso_t tso;
+-	int i;
+ 
+ 	/* Count needed descriptors */
+ 	if ((txq->count + tso_count_descs(skb)) >= txq->size)
+@@ -2665,6 +2691,8 @@ static int mvneta_tx_tso(struct sk_buff
+ 		return 0;
+ 	}
+ 
++	first_desc = txq->txq_put_index;
++
+ 	/* Initialize the TSO handler, and prepare the first payload */
+ 	hdr_len = tso_start(skb, &tso);
+ 
+@@ -2705,15 +2733,7 @@ err_release:
+ 	/* Release all used data descriptors; header descriptors must not
+ 	 * be DMA-unmapped.
+ 	 */
+-	for (i = desc_count - 1; i >= 0; i--) {
+-		struct mvneta_tx_desc *tx_desc = txq->descs + i;
+-		if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr))
+-			dma_unmap_single(pp->dev->dev.parent,
+-					 tx_desc->buf_phys_addr,
+-					 tx_desc->data_size,
+-					 DMA_TO_DEVICE);
+-		mvneta_txq_desc_put(txq);
+-	}
++	mvneta_release_descs(pp, txq, first_desc, desc_count - 1);
+ 	return 0;
+ }
+ 
+@@ -2723,6 +2743,7 @@ static int mvneta_tx_frag_process(struct
+ {
+ 	struct mvneta_tx_desc *tx_desc;
+ 	int i, nr_frags = skb_shinfo(skb)->nr_frags;
++	int first_desc = txq->txq_put_index;
+ 
+ 	for (i = 0; i < nr_frags; i++) {
+ 		struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+@@ -2761,15 +2782,7 @@ error:
+ 	/* Release all descriptors that were used to map fragments of
+ 	 * this packet, as well as the corresponding DMA mappings
+ 	 */
+-	for (i = i - 1; i >= 0; i--) {
+-		tx_desc = txq->descs + i;
+-		dma_unmap_single(pp->dev->dev.parent,
+-				 tx_desc->buf_phys_addr,
+-				 tx_desc->data_size,
+-				 DMA_TO_DEVICE);
+-		mvneta_txq_desc_put(txq);
+-	}
+-
++	mvneta_release_descs(pp, txq, first_desc, i - 1);
+ 	return -ENOMEM;
+ }
+ 
diff --git a/target/linux/generic/pending-5.15/704-02-v6.4-net-mvneta-mark-mapped-and-tso-buffers-separately.patch b/target/linux/generic/pending-5.15/704-02-v6.4-net-mvneta-mark-mapped-and-tso-buffers-separately.patch
new file mode 100644
index 0000000000..4db3ffe4e1
--- /dev/null
+++ b/target/linux/generic/pending-5.15/704-02-v6.4-net-mvneta-mark-mapped-and-tso-buffers-separately.patch
@@ -0,0 +1,42 @@
+From e3c77d0a1b635d114c147fd2078afb57ed558b81 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
+Date: Mon, 3 Apr 2023 19:30:25 +0100
+Subject: [PATCH 2/5] net: mvneta: mark mapped and tso buffers separately
+
+Mark dma-mapped skbs and TSO buffers separately, so we can use
+buf->type to identify their differences.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -607,6 +607,7 @@ struct mvneta_rx_desc {
+ #endif
+ 
+ enum mvneta_tx_buf_type {
++	MVNETA_TYPE_TSO,
+ 	MVNETA_TYPE_SKB,
+ 	MVNETA_TYPE_XDP_TX,
+ 	MVNETA_TYPE_XDP_NDO,
+@@ -1852,7 +1853,8 @@ static void mvneta_txq_bufs_free(struct
+ 			dma_unmap_single(pp->dev->dev.parent,
+ 					 tx_desc->buf_phys_addr,
+ 					 tx_desc->data_size, DMA_TO_DEVICE);
+-		if (buf->type == MVNETA_TYPE_SKB && buf->skb) {
++		if ((buf->type == MVNETA_TYPE_TSO ||
++		     buf->type == MVNETA_TYPE_SKB) && buf->skb) {
+ 			bytes_compl += buf->skb->len;
+ 			pkts_compl++;
+ 			dev_kfree_skb_any(buf->skb);
+@@ -2607,7 +2609,7 @@ mvneta_tso_put_hdr(struct sk_buff *skb,
+ 	tx_desc->command |= MVNETA_TXD_F_DESC;
+ 	tx_desc->buf_phys_addr = txq->tso_hdrs_phys +
+ 				 txq->txq_put_index * TSO_HEADER_SIZE;
+-	buf->type = MVNETA_TYPE_SKB;
++	buf->type = MVNETA_TYPE_TSO;
+ 	buf->skb = NULL;
+ 
+ 	mvneta_txq_inc_put(txq);
diff --git a/target/linux/generic/pending-5.15/704-03-v6.4-net-mvneta-use-buf-type-to-determine-whether-to-dma-.patch b/target/linux/generic/pending-5.15/704-03-v6.4-net-mvneta-use-buf-type-to-determine-whether-to-dma-.patch
new file mode 100644
index 0000000000..37511ff1dd
--- /dev/null
+++ b/target/linux/generic/pending-5.15/704-03-v6.4-net-mvneta-use-buf-type-to-determine-whether-to-dma-.patch
@@ -0,0 +1,59 @@
+From fe2abc1abc0dfc6c13fe8f189216f00dbbb33044 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
+Date: Mon, 3 Apr 2023 19:30:30 +0100
+Subject: [PATCH 3/5] net: mvneta: use buf->type to determine whether to
+ dma-unmap
+
+Now that we use a different buffer type for TSO headers, we can use
+buf->type to determine whether the original buffer was DMA-mapped or
+not. The rules are:
+
+	MVNETA_TYPE_XDP_TX - from a DMA pool, no unmap is required
+	MVNETA_TYPE_XDP_NDO - dma_map_single()'d
+	MVNETA_TYPE_SKB - normal skbuff, dma_map_single()'d
+	MVNETA_TYPE_TSO - from the TSO buffer area
+
+This means we only need to call dma_unmap_single() on the XDP_NDO and
+SKB types of buffer, and we no longer need the private IS_TSO_HEADER()
+which relies on the TSO region being contiguously allocated.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -334,10 +334,6 @@
+ 			 MVNETA_SKB_HEADROOM))
+ #define MVNETA_MAX_RX_BUF_SIZE	(PAGE_SIZE - MVNETA_SKB_PAD)
+ 
+-#define IS_TSO_HEADER(txq, addr) \
+-	((addr >= txq->tso_hdrs_phys) && \
+-	 (addr < txq->tso_hdrs_phys + txq->size * TSO_HEADER_SIZE))
+-
+ #define MVNETA_RX_GET_BM_POOL_ID(rxd) \
+ 	(((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT)
+ 
+@@ -1848,8 +1844,8 @@ static void mvneta_txq_bufs_free(struct
+ 
+ 		mvneta_txq_inc_get(txq);
+ 
+-		if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr) &&
+-		    buf->type != MVNETA_TYPE_XDP_TX)
++		if (buf->type == MVNETA_TYPE_XDP_NDO ||
++		    buf->type == MVNETA_TYPE_SKB)
+ 			dma_unmap_single(pp->dev->dev.parent,
+ 					 tx_desc->buf_phys_addr,
+ 					 tx_desc->data_size, DMA_TO_DEVICE);
+@@ -2661,8 +2657,9 @@ static void mvneta_release_descs(struct
+ 
+ 	for (i = num; i >= 0; i--) {
+ 		struct mvneta_tx_desc *tx_desc = txq->descs + desc_idx;
++		struct mvneta_tx_buf *buf = &txq->buf[desc_idx];
+ 
+-		if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr))
++		if (buf->type == MVNETA_TYPE_SKB)
+ 			dma_unmap_single(pp->dev->dev.parent,
+ 					 tx_desc->buf_phys_addr,
+ 					 tx_desc->data_size,
diff --git a/target/linux/generic/pending-5.15/704-04-v6.4-net-mvneta-move-tso_build_hdr-into-mvneta_tso_put_hd.patch b/target/linux/generic/pending-5.15/704-04-v6.4-net-mvneta-move-tso_build_hdr-into-mvneta_tso_put_hd.patch
new file mode 100644
index 0000000000..444b60f151
--- /dev/null
+++ b/target/linux/generic/pending-5.15/704-04-v6.4-net-mvneta-move-tso_build_hdr-into-mvneta_tso_put_hd.patch
@@ -0,0 +1,65 @@
+From 210ca75d4949f1ace8ea53a75148806cc28224a0 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
+Date: Mon, 3 Apr 2023 19:30:35 +0100
+Subject: [PATCH 4/5] net: mvneta: move tso_build_hdr() into
+ mvneta_tso_put_hdr()
+
+Move tso_build_hdr() into mvneta_tso_put_hdr() so that all the TSO
+header building code is in one place.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -2592,19 +2592,24 @@ err_drop_frame:
+ 	return rx_done;
+ }
+ 
+-static inline void
+-mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq)
++static void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq,
++			       struct tso_t *tso, int size, bool is_last)
+ {
+-	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
++	int tso_offset, hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ 	struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+ 	struct mvneta_tx_desc *tx_desc;
++	char *hdr;
++
++	tso_offset = txq->txq_put_index * TSO_HEADER_SIZE;
++
++	hdr = txq->tso_hdrs + tso_offset;
++	tso_build_hdr(skb, hdr, tso, size, is_last);
+ 
+ 	tx_desc = mvneta_txq_next_desc_get(txq);
+ 	tx_desc->data_size = hdr_len;
+ 	tx_desc->command = mvneta_skb_tx_csum(skb);
+ 	tx_desc->command |= MVNETA_TXD_F_DESC;
+-	tx_desc->buf_phys_addr = txq->tso_hdrs_phys +
+-				 txq->txq_put_index * TSO_HEADER_SIZE;
++	tx_desc->buf_phys_addr = txq->tso_hdrs_phys + tso_offset;
+ 	buf->type = MVNETA_TYPE_TSO;
+ 	buf->skb = NULL;
+ 
+@@ -2697,17 +2702,12 @@ static int mvneta_tx_tso(struct sk_buff
+ 
+ 	total_len = skb->len - hdr_len;
+ 	while (total_len > 0) {
+-		char *hdr;
+-
+ 		data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
+ 		total_len -= data_left;
+ 		desc_count++;
+ 
+ 		/* prepare packet headers: MAC + IP + TCP */
+-		hdr = txq->tso_hdrs + txq->txq_put_index * TSO_HEADER_SIZE;
+-		tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
+-
+-		mvneta_tso_put_hdr(skb, txq);
++		mvneta_tso_put_hdr(skb, txq, &tso, data_left, total_len == 0);
+ 
+ 		while (data_left > 0) {
+ 			int size;
diff --git a/target/linux/generic/pending-5.15/704-05-v6.4-net-mvneta-allocate-TSO-header-DMA-memory-in-chunks.patch b/target/linux/generic/pending-5.15/704-05-v6.4-net-mvneta-allocate-TSO-header-DMA-memory-in-chunks.patch
new file mode 100644
index 0000000000..395a0bf5d2
--- /dev/null
+++ b/target/linux/generic/pending-5.15/704-05-v6.4-net-mvneta-allocate-TSO-header-DMA-memory-in-chunks.patch
@@ -0,0 +1,179 @@
+From 58d50fb089da553023df5a05f5ae86feaacc7f24 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel at armlinux.org.uk>
+Date: Mon, 3 Apr 2023 19:30:40 +0100
+Subject: [PATCH 5/5] net: mvneta: allocate TSO header DMA memory in chunks
+
+Now that we no longer need to check whether the DMA address is within
+the TSO header DMA memory range for the queue, we can allocate the TSO
+header DMA memory in chunks rather than one contiguous order-6 chunk,
+which can stress the kernel's memory subsystems to allocate.
+
+Instead, use order-1 (8k) allocations, which will result in 32 order-1
+pages containing 32 TSO headers.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel at armlinux.org.uk>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 88 +++++++++++++++++++++------
+ 1 file changed, 70 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -314,6 +314,15 @@
+ 
+ #define MVNETA_MAX_SKB_DESCS (MVNETA_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
+ 
++/* The size of a TSO header page */
++#define MVNETA_TSO_PAGE_SIZE (2 * PAGE_SIZE)
++
++/* Number of TSO headers per page. This should be a power of 2 */
++#define MVNETA_TSO_PER_PAGE (MVNETA_TSO_PAGE_SIZE / TSO_HEADER_SIZE)
++
++/* Maximum number of TSO header pages */
++#define MVNETA_MAX_TSO_PAGES (MVNETA_MAX_TXD / MVNETA_TSO_PER_PAGE)
++
+ /* descriptor aligned size */
+ #define MVNETA_DESC_ALIGNED_SIZE	32
+ 
+@@ -656,10 +665,10 @@ struct mvneta_tx_queue {
+ 	int next_desc_to_proc;
+ 
+ 	/* DMA buffers for TSO headers */
+-	char *tso_hdrs;
++	char *tso_hdrs[MVNETA_MAX_TSO_PAGES];
+ 
+ 	/* DMA address of TSO headers */
+-	dma_addr_t tso_hdrs_phys;
++	dma_addr_t tso_hdrs_phys[MVNETA_MAX_TSO_PAGES];
+ 
+ 	/* Affinity mask for CPUs*/
+ 	cpumask_t affinity_mask;
+@@ -2592,24 +2601,71 @@ err_drop_frame:
+ 	return rx_done;
+ }
+ 
++static void mvneta_free_tso_hdrs(struct mvneta_port *pp,
++				 struct mvneta_tx_queue *txq)
++{
++	struct device *dev = pp->dev->dev.parent;
++	int i;
++
++	for (i = 0; i < MVNETA_MAX_TSO_PAGES; i++) {
++		if (txq->tso_hdrs[i]) {
++			dma_free_coherent(dev, MVNETA_TSO_PAGE_SIZE,
++					  txq->tso_hdrs[i],
++					  txq->tso_hdrs_phys[i]);
++			txq->tso_hdrs[i] = NULL;
++		}
++	}
++}
++
++static int mvneta_alloc_tso_hdrs(struct mvneta_port *pp,
++				 struct mvneta_tx_queue *txq)
++{
++	struct device *dev = pp->dev->dev.parent;
++	int i, num;
++
++	num = DIV_ROUND_UP(txq->size, MVNETA_TSO_PER_PAGE);
++	for (i = 0; i < num; i++) {
++		txq->tso_hdrs[i] = dma_alloc_coherent(dev, MVNETA_TSO_PAGE_SIZE,
++						      &txq->tso_hdrs_phys[i],
++						      GFP_KERNEL);
++		if (!txq->tso_hdrs[i]) {
++			mvneta_free_tso_hdrs(pp, txq);
++			return -ENOMEM;
++		}
++	}
++
++	return 0;
++}
++
++static char *mvneta_get_tso_hdr(struct mvneta_tx_queue *txq, dma_addr_t *dma)
++{
++	int index, offset;
++
++	index = txq->txq_put_index / MVNETA_TSO_PER_PAGE;
++	offset = (txq->txq_put_index % MVNETA_TSO_PER_PAGE) * TSO_HEADER_SIZE;
++
++	*dma = txq->tso_hdrs_phys[index] + offset;
++
++	return txq->tso_hdrs[index] + offset;
++}
++
+ static void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq,
+ 			       struct tso_t *tso, int size, bool is_last)
+ {
+-	int tso_offset, hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
++	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ 	struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+ 	struct mvneta_tx_desc *tx_desc;
++	dma_addr_t hdr_phys;
+ 	char *hdr;
+ 
+-	tso_offset = txq->txq_put_index * TSO_HEADER_SIZE;
+-
+-	hdr = txq->tso_hdrs + tso_offset;
++	hdr = mvneta_get_tso_hdr(txq, &hdr_phys);
+ 	tso_build_hdr(skb, hdr, tso, size, is_last);
+ 
+ 	tx_desc = mvneta_txq_next_desc_get(txq);
+ 	tx_desc->data_size = hdr_len;
+ 	tx_desc->command = mvneta_skb_tx_csum(skb);
+ 	tx_desc->command |= MVNETA_TXD_F_DESC;
+-	tx_desc->buf_phys_addr = txq->tso_hdrs_phys + tso_offset;
++	tx_desc->buf_phys_addr = hdr_phys;
+ 	buf->type = MVNETA_TYPE_TSO;
+ 	buf->skb = NULL;
+ 
+@@ -3401,7 +3457,7 @@ static void mvneta_rxq_deinit(struct mvn
+ static int mvneta_txq_sw_init(struct mvneta_port *pp,
+ 			      struct mvneta_tx_queue *txq)
+ {
+-	int cpu;
++	int cpu, err;
+ 
+ 	txq->size = pp->tx_ring_size;
+ 
+@@ -3426,11 +3482,9 @@ static int mvneta_txq_sw_init(struct mvn
+ 		return -ENOMEM;
+ 
+ 	/* Allocate DMA buffers for TSO MAC/IP/TCP headers */
+-	txq->tso_hdrs = dma_alloc_coherent(pp->dev->dev.parent,
+-					   txq->size * TSO_HEADER_SIZE,
+-					   &txq->tso_hdrs_phys, GFP_KERNEL);
+-	if (!txq->tso_hdrs)
+-		return -ENOMEM;
++	err = mvneta_alloc_tso_hdrs(pp, txq);
++	if (err)
++		return err;
+ 
+ 	/* Setup XPS mapping */
+ 	if (pp->neta_armada3700)
+@@ -3482,10 +3536,7 @@ static void mvneta_txq_sw_deinit(struct
+ 
+ 	kfree(txq->buf);
+ 
+-	if (txq->tso_hdrs)
+-		dma_free_coherent(pp->dev->dev.parent,
+-				  txq->size * TSO_HEADER_SIZE,
+-				  txq->tso_hdrs, txq->tso_hdrs_phys);
++	mvneta_free_tso_hdrs(pp, txq);
+ 	if (txq->descs)
+ 		dma_free_coherent(pp->dev->dev.parent,
+ 				  txq->size * MVNETA_DESC_ALIGNED_SIZE,
+@@ -3494,7 +3545,6 @@ static void mvneta_txq_sw_deinit(struct
+ 	netdev_tx_reset_queue(nq);
+ 
+ 	txq->buf               = NULL;
+-	txq->tso_hdrs          = NULL;
+ 	txq->descs             = NULL;
+ 	txq->last_desc         = 0;
+ 	txq->next_desc_to_proc = 0;
+@@ -5543,6 +5593,8 @@ static int __init mvneta_driver_init(voi
+ {
+ 	int ret;
+ 
++	BUILD_BUG_ON_NOT_POWER_OF_2(MVNETA_TSO_PER_PAGE);
++
+ 	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "net/mvneta:online",
+ 				      mvneta_cpu_online,
+ 				      mvneta_cpu_down_prepare);
diff --git a/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch b/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch
index 826f95d1c2..32e8ef4b7d 100644
--- a/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch
+++ b/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch
@@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
 ---
 --- a/drivers/net/ethernet/marvell/mvneta.c
 +++ b/drivers/net/ethernet/marvell/mvneta.c
-@@ -4943,6 +4943,16 @@ static int mvneta_setup_tc(struct net_de
+@@ -5006,6 +5006,16 @@ static int mvneta_setup_tc(struct net_de
  	}
  }
  
@@ -26,7 +26,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
  static const struct net_device_ops mvneta_netdev_ops = {
  	.ndo_open            = mvneta_open,
  	.ndo_stop            = mvneta_stop,
-@@ -4953,6 +4963,9 @@ static const struct net_device_ops mvnet
+@@ -5016,6 +5026,9 @@ static const struct net_device_ops mvnet
  	.ndo_fix_features    = mvneta_fix_features,
  	.ndo_get_stats64     = mvneta_get_stats64,
  	.ndo_eth_ioctl        = mvneta_ioctl,
diff --git a/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch b/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch
index c3a6d9f4d0..019b9528c3 100644
--- a/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch
+++ b/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch
@@ -26,7 +26,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  #include <linux/bpf_trace.h>
  
  /* Registers */
-@@ -4903,14 +4904,14 @@ static void mvneta_setup_rx_prio_map(str
+@@ -4966,14 +4967,14 @@ static void mvneta_setup_rx_prio_map(str
  }
  
  static int mvneta_setup_mqprio(struct net_device *dev,
@@ -44,7 +44,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
  	if (num_tc > rxq_number)
  		return -EINVAL;
-@@ -4921,13 +4922,15 @@ static int mvneta_setup_mqprio(struct ne
+@@ -4984,13 +4985,15 @@ static int mvneta_setup_mqprio(struct ne
  		return 0;
  	}
  
diff --git a/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch b/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch
index 8ef585be9a..c878a28843 100644
--- a/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch
+++ b/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch
@@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
 
 --- a/drivers/net/ethernet/marvell/mvneta.c
 +++ b/drivers/net/ethernet/marvell/mvneta.c
-@@ -4910,7 +4910,9 @@ static int mvneta_setup_mqprio(struct ne
+@@ -4973,7 +4973,9 @@ static int mvneta_setup_mqprio(struct ne
  	u8 num_tc;
  	int i;
  
diff --git a/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch b/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch
index 196b986541..546a8486ef 100644
--- a/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch
+++ b/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch
@@ -22,7 +22,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
 
 --- a/drivers/net/ethernet/marvell/mvneta.c
 +++ b/drivers/net/ethernet/marvell/mvneta.c
-@@ -493,7 +493,6 @@ struct mvneta_port {
+@@ -498,7 +498,6 @@ struct mvneta_port {
  	u8 mcast_count[256];
  	u16 tx_ring_size;
  	u16 rx_ring_size;
@@ -30,7 +30,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
  	phy_interface_t phy_interface;
  	struct device_node *dn;
-@@ -4892,13 +4891,12 @@ static void mvneta_clear_rx_prio_map(str
+@@ -4955,13 +4954,12 @@ static void mvneta_clear_rx_prio_map(str
  	mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, 0);
  }
  
@@ -48,7 +48,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
  	mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, val);
  }
-@@ -4907,8 +4905,8 @@ static int mvneta_setup_mqprio(struct ne
+@@ -4970,8 +4968,8 @@ static int mvneta_setup_mqprio(struct ne
  			       struct tc_mqprio_qopt_offload *mqprio)
  {
  	struct mvneta_port *pp = netdev_priv(dev);
@@ -58,7 +58,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  
  	if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS)
  		return 0;
-@@ -4918,21 +4916,28 @@ static int mvneta_setup_mqprio(struct ne
+@@ -4981,21 +4979,28 @@ static int mvneta_setup_mqprio(struct ne
  	if (num_tc > rxq_number)
  		return -EINVAL;
  
diff --git a/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch b/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch
index d640da4d44..1d4a055a71 100644
--- a/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch
+++ b/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch
@@ -62,7 +62,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  #define MVNETA_LPI_CTRL_0                        0x2cc0
  #define MVNETA_LPI_CTRL_1                        0x2cc4
  #define      MVNETA_LPI_REQUEST_ENABLE           BIT(0)
-@@ -4901,11 +4928,74 @@ static void mvneta_map_vlan_prio_to_rxq(
+@@ -4964,11 +4991,74 @@ static void mvneta_map_vlan_prio_to_rxq(
  	mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, val);
  }
  
@@ -138,7 +138,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  	u8 num_tc;
  
  	if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS)
-@@ -4919,6 +5009,7 @@ static int mvneta_setup_mqprio(struct ne
+@@ -4982,6 +5072,7 @@ static int mvneta_setup_mqprio(struct ne
  	mvneta_clear_rx_prio_map(pp);
  
  	if (!num_tc) {
@@ -146,7 +146,7 @@ Signed-off-by: David S. Miller <davem at davemloft.net>
  		netdev_reset_tc(dev);
  		return 0;
  	}
-@@ -4939,6 +5030,33 @@ static int mvneta_setup_mqprio(struct ne
+@@ -5002,6 +5093,33 @@ static int mvneta_setup_mqprio(struct ne
  		}
  	}
  




More information about the lede-commits mailing list