DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] net/mana: fix transmit burst and add hardware TSO support
@ 2026-10-12  7:36 Tathagat Priyadarshi
  2026-10-12  7:36 ` [PATCH 1/2] net/mana: fix transmit burst error handling Tathagat Priyadarshi
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Tathagat Priyadarshi @ 2026-10-12  7:36 UTC (permalink / raw)
  To: dev; +Cc: Long Li, Wei Hu

This patch series addresses transmit burst error handling and introduces
hardware TCP Segmentation Offload (TSO) support for the Microsoft Azure
MANA PMD.

Patch 1 fixes the transmit burst loop in mana_tx_burst() to terminate
with break instead of continue upon packet errors. Under the DPDK
rte_eth_tx_burst() API contract, callers expect a contiguous prefix of
transmitted packets. Skipping a packet caused unsent packets to be treated
as unsent and freed by caller, followed by a second free upon hardware CQE
arrival.

Patch 2 adds support for hardware TCP Segmentation Offload (TSO),
formatting SGL entries with packet headers in SGE0, handling GDMA work
request flags, advertising RTE_ETH_TX_OFFLOAD_TCP_TSO, and updating
the mana driver feature table.

Tathagat Priyadarshi (2):
  net/mana: fix transmit burst error handling
  net/mana: add hardware TSO support

 doc/guides/nics/features/mana.ini |   1 +
 drivers/net/mana/gdma.c           |   5 +
 drivers/net/mana/mana.h           |   6 +-
 drivers/net/mana/tx.c             | 179 +++++++++++++++++++++++++-----
 4 files changed, 163 insertions(+), 28 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] net/mana: fix transmit burst error handling
  2026-10-12  7:36 [PATCH 0/2] net/mana: fix transmit burst and add hardware TSO support Tathagat Priyadarshi
@ 2026-10-12  7:36 ` Tathagat Priyadarshi
  2026-10-12  7:36 ` [PATCH 2/2] net/mana: add hardware TSO support Tathagat Priyadarshi
  2026-10-12 21:37 ` [PATCH 0/2] net/mana: fix transmit burst and " Stephen Hemminger
  2 siblings, 0 replies; 4+ messages in thread
From: Tathagat Priyadarshi @ 2026-10-12  7:36 UTC (permalink / raw)
  To: dev; +Cc: Long Li, stable, Wei Hu

When a packet exceeds max_send_sge or when populating SGL segments fails,
mana_tx_burst() skipped the failed packet using continue.

Under the DPDK rte_eth_tx_burst() API contract, callers assume that the
returned count represents a contiguous prefix of transmitted packets
(tx_pkts[0 .. nb_tx - 1]). Skipping a packet in the middle of a burst
causes subsequent packets to be transmitted while the caller treats them
as unsent and frees them. When hardware later generates CQEs for those
transmitted packets, they are freed a second time, corrupting mbuf pools
and free caches.

Fix this by terminating the burst loop with break upon packet errors so
that pkt_sent accurately reflects the contiguous prefix sent.

Fixes: 7f322844f427 ("net/mana: send packets")
Cc: stable@dpdk.org

Signed-off-by: Tathagat Priyadarshi <tathagat.dpdk@gmail.com>
---
 drivers/net/mana/tx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mana/tx.c b/drivers/net/mana/tx.c
index 10f2212b5d..d35030cbe5 100644
--- a/drivers/net/mana/tx.c
+++ b/drivers/net/mana/tx.c
@@ -281,7 +281,7 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		if (m_pkt->nb_segs > priv->max_send_sge) {
 			DP_LOG(ERR, "send packet segments %d exceeding max",
 			       m_pkt->nb_segs);
-			continue;
+			break;
 		}
 
 		/* Fill in the oob */
@@ -432,7 +432,7 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 
 		/* Skip this packet if we can't populate all segments */
 		if (seg_idx != m_pkt->nb_segs)
-			continue;
+			break;
 
 		/* If we can at least queue post two WQEs and there are at
 		 * least two packets to send, use TX CQE suppression for the
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] net/mana: add hardware TSO support
  2026-10-12  7:36 [PATCH 0/2] net/mana: fix transmit burst and add hardware TSO support Tathagat Priyadarshi
  2026-10-12  7:36 ` [PATCH 1/2] net/mana: fix transmit burst error handling Tathagat Priyadarshi
@ 2026-10-12  7:36 ` Tathagat Priyadarshi
  2026-10-12 21:37 ` [PATCH 0/2] net/mana: fix transmit burst and " Stephen Hemminger
  2 siblings, 0 replies; 4+ messages in thread
From: Tathagat Priyadarshi @ 2026-10-12  7:36 UTC (permalink / raw)
  To: dev; +Cc: Long Li, Wei Hu

Implement hardware TCP Segmentation Offload (TSO) in Microsoft Azure
MANA PMD:
- Define GDMA_WR_OOB_IN_SGL and GDMA_WR_PAD_BY_SGE0 in mana.h.
- Advertise RTE_ETH_TX_OFFLOAD_TCP_TSO in MANA_DEV_TX_OFFLOAD_SUPPORT.
- Handle GDMA_WR_OOB_IN_SGL and GDMA_WR_PAD_BY_SGE0 in
  write_dma_client_oob() in gdma.c to configure client_oob_in_sgl and
  last_v_bytes.
- In mana_tx_burst() in tx.c:
  * Parse RTE_MBUF_F_TX_TCP_SEG and validate total SGEs against
    priv->max_send_sge and MAX_SGL_ENTRIES_FOR_TRANSMIT.
  * Zero out IPv4 total_length and hdr_checksum (or IPv6 payload_len)
    and compute pseudo-header checksum in the TCP header.
  * Enable tx_compute_TCP_checksum and set tx_transport_header_offset.
  * Format SGL so SGE0 contains packet headers (L2 + L3 + L4) and
    subsequent SGEs carry segment payloads, allocating MRs through
    mana_alloc_pmd_mr().
  * Set GDMA_WR_OOB_IN_SGL | GDMA_WR_PAD_BY_SGE0 work request flags and
    assign client_data_unit to m_pkt->tso_segsz.
- Update mana.ini to advertise TSO feature support.

Signed-off-by: Tathagat Priyadarshi <tathagat.dpdk@gmail.com>
---
 doc/guides/nics/features/mana.ini |   1 +
 drivers/net/mana/gdma.c           |   5 +
 drivers/net/mana/mana.h           |   6 +-
 drivers/net/mana/tx.c             | 177 +++++++++++++++++++++++++-----
 4 files changed, 162 insertions(+), 27 deletions(-)

diff --git a/doc/guides/nics/features/mana.ini b/doc/guides/nics/features/mana.ini
index db555ffe27..edf9469486 100644
--- a/doc/guides/nics/features/mana.ini
+++ b/doc/guides/nics/features/mana.ini
@@ -11,6 +11,7 @@ Rx interrupt         = Y
 RSS hash             = Y
 L3 checksum offload  = Y
 L4 checksum offload  = Y
+TSO                  = Y
 Basic stats          = Y
 MTU update           = Y
 Multiprocess aware   = Y
diff --git a/drivers/net/mana/gdma.c b/drivers/net/mana/gdma.c
index a92aef59d2..65896b6a69 100644
--- a/drivers/net/mana/gdma.c
+++ b/drivers/net/mana/gdma.c
@@ -38,6 +38,11 @@ write_dma_client_oob(uint8_t *work_queue_buffer_pointer,
 	header->inline_client_oob_size_in_dwords =
 		client_oob_size / sizeof(uint32_t);
 	header->client_data_unit = work_request->client_data_unit;
+	if (work_request->flags & GDMA_WR_OOB_IN_SGL) {
+		header->client_oob_in_sgl = 1;
+		if (work_request->flags & GDMA_WR_PAD_BY_SGE0)
+			header->last_v_bytes = work_request->sgl[0].size;
+	}
 
 	DP_LOG(DEBUG, "queue buf %p sgl %u oob_h %u du %u oob_buf %p oob_b %u",
 	       work_queue_buffer_pointer, header->num_sgl_entries,
diff --git a/drivers/net/mana/mana.h b/drivers/net/mana/mana.h
index 79879b7626..17aa4a09ac 100644
--- a/drivers/net/mana/mana.h
+++ b/drivers/net/mana/mana.h
@@ -28,12 +28,16 @@ struct mana_shared_data {
 		RTE_ETH_RX_OFFLOAD_CHECKSUM | \
 		RTE_ETH_RX_OFFLOAD_RSS_HASH)
 
+#define GDMA_WR_OOB_IN_SGL  (1 << 0)
+#define GDMA_WR_PAD_BY_SGE0 (1 << 1)
+
 #define MANA_DEV_TX_OFFLOAD_SUPPORT ( \
 		RTE_ETH_TX_OFFLOAD_VLAN_INSERT | \
 		RTE_ETH_TX_OFFLOAD_MULTI_SEGS | \
 		RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | \
 		RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
-		RTE_ETH_TX_OFFLOAD_UDP_CKSUM)
+		RTE_ETH_TX_OFFLOAD_UDP_CKSUM | \
+		RTE_ETH_TX_OFFLOAD_TCP_TSO)
 
 #define INDIRECTION_TABLE_NUM_ELEMENTS 64
 #define TOEPLITZ_HASH_KEY_SIZE_IN_BYTES 40
diff --git a/drivers/net/mana/tx.c b/drivers/net/mana/tx.c
index d35030cbe5..9401928bad 100644
--- a/drivers/net/mana/tx.c
+++ b/drivers/net/mana/tx.c
@@ -273,14 +273,31 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		struct transmit_oob_v2 tx_oob;
 		struct one_sgl sgl;
 		uint16_t seg_idx;
+		uint16_t num_sge;
+		uint16_t expected_sge;
+		bool is_tso = false;
+		uint32_t gso_hs = 0;
 
 		if (txq->desc_ring_len >= txq->num_desc)
 			break;
 
-		/* Drop the packet if it exceeds max segments */
-		if (m_pkt->nb_segs > priv->max_send_sge) {
+		if (m_pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+			gso_hs = m_pkt->l2_len + m_pkt->l3_len + m_pkt->l4_len;
+			if (unlikely(m_pkt->data_len < gso_hs)) {
+				DP_LOG(ERR, "TSO header cannot be fragmented");
+				break;
+			}
+			if (likely(gso_hs != 0 && m_pkt->pkt_len > gso_hs &&
+				   m_pkt->tso_segsz != 0))
+				is_tso = true;
+		}
+
+		expected_sge = m_pkt->nb_segs +
+			(is_tso && m_pkt->data_len > gso_hs ? 1 : 0);
+		if (expected_sge > priv->max_send_sge ||
+		    expected_sge > MAX_SGL_ENTRIES_FOR_TRANSMIT) {
 			DP_LOG(ERR, "send packet segments %d exceeding max",
-			       m_pkt->nb_segs);
+			       expected_sge);
 			break;
 		}
 
@@ -305,7 +322,43 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		tx_oob.short_oob.tx_compute_IP_header_checksum =
 			m_pkt->ol_flags & RTE_MBUF_F_TX_IP_CKSUM ? 1 : 0;
 
-		if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) ==
+		if (is_tso) {
+			struct rte_tcp_hdr *tcp_hdr =
+				rte_pktmbuf_mtod_offset(m_pkt,
+					struct rte_tcp_hdr *,
+					m_pkt->l2_len + m_pkt->l3_len);
+
+			if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4) {
+				struct rte_ipv4_hdr *ip_hdr =
+					rte_pktmbuf_mtod_offset(m_pkt,
+						struct rte_ipv4_hdr *,
+						m_pkt->l2_len);
+
+				ip_hdr->total_length = 0;
+				ip_hdr->hdr_checksum = 0;
+				tcp_hdr->cksum = rte_ipv4_phdr_cksum(ip_hdr,
+							m_pkt->ol_flags);
+			} else if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6) {
+				struct rte_ipv6_hdr *ip_hdr =
+					rte_pktmbuf_mtod_offset(m_pkt,
+						struct rte_ipv6_hdr *,
+						m_pkt->l2_len);
+
+				ip_hdr->payload_len = 0;
+				tcp_hdr->cksum = rte_ipv6_phdr_cksum(ip_hdr,
+							m_pkt->ol_flags);
+			} else {
+				DP_LOG(ERR, "Invalid IP version for TSO");
+				break;
+			}
+
+			tx_oob.short_oob.tx_compute_IP_header_checksum =
+				(m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4) ? 1 : 0;
+			tx_oob.short_oob.tx_compute_TCP_checksum = 1;
+			tx_oob.short_oob.tx_compute_UDP_checksum = 0;
+			tx_oob.short_oob.tx_transport_header_offset =
+				m_pkt->l2_len + m_pkt->l3_len;
+		} else if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) ==
 				RTE_MBUF_F_TX_TCP_CKSUM) {
 			struct rte_tcp_hdr *tcp_hdr;
 
@@ -405,34 +458,100 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		       m_pkt->pkt_len);
 
 		/* Create SGL for packet data buffers */
-		for (seg_idx = 0; seg_idx < m_pkt->nb_segs; seg_idx++) {
+		if (is_tso) {
 			struct mana_mr_cache *mr =
-				mana_alloc_pmd_mr(&txq->mr_btree, priv, m_seg);
+				mana_alloc_pmd_mr(&txq->mr_btree, priv, m_pkt);
 
-			if (!mr) {
-				DP_LOG(ERR, "failed to get MR, pkt_idx %u",
+			if (unlikely(!mr)) {
+				DP_LOG(ERR, "failed to get MR for TSO hdr, pkt_idx %u",
 				       pkt_idx);
 				break;
 			}
 
-			sgl.gdma_sgl[seg_idx].address =
-				rte_cpu_to_le_64(rte_pktmbuf_mtod(m_seg,
-								  uint64_t));
-			sgl.gdma_sgl[seg_idx].size = m_seg->data_len;
-			sgl.gdma_sgl[seg_idx].memory_key = mr->lkey;
+			/* SGE0: packet header only (L2 + L3 + L4) */
+			sgl.gdma_sgl[0].address =
+				rte_cpu_to_le_64(rte_pktmbuf_mtod(m_pkt, uint64_t));
+			sgl.gdma_sgl[0].size = gso_hs;
+			sgl.gdma_sgl[0].memory_key = mr->lkey;
+			num_sge = 1;
+
+			/* If first mbuf has payload data beyond the header */
+			if (m_pkt->data_len > gso_hs) {
+				sgl.gdma_sgl[1].address =
+					rte_cpu_to_le_64(rte_pktmbuf_mtod(m_pkt,
+									  uint64_t) +
+							 gso_hs);
+				sgl.gdma_sgl[1].size = m_pkt->data_len - gso_hs;
+				sgl.gdma_sgl[1].memory_key = mr->lkey;
+				num_sge = 2;
+			}
 
-			DP_LOG(DEBUG,
-			       "seg idx %u addr 0x%" PRIx64 " size %x key %x",
-			       seg_idx, sgl.gdma_sgl[seg_idx].address,
-			       sgl.gdma_sgl[seg_idx].size,
-			       sgl.gdma_sgl[seg_idx].memory_key);
+			/* Subsequent mbuf segments */
+			m_seg = m_pkt->next;
+			while (m_seg) {
+				if (unlikely(num_sge >=
+					     MAX_SGL_ENTRIES_FOR_TRANSMIT)) {
+					DP_LOG(ERR,
+					       "TSO SGL entries exceed max %d",
+					       MAX_SGL_ENTRIES_FOR_TRANSMIT);
+					break;
+				}
+				mr = mana_alloc_pmd_mr(&txq->mr_btree, priv,
+						       m_seg);
+				if (unlikely(!mr)) {
+					DP_LOG(ERR,
+					       "failed to get MR for TSO seg, pkt_idx %u",
+					       pkt_idx);
+					break;
+				}
+				sgl.gdma_sgl[num_sge].address =
+					rte_cpu_to_le_64(rte_pktmbuf_mtod(m_seg,
+									  uint64_t));
+				sgl.gdma_sgl[num_sge].size = m_seg->data_len;
+				sgl.gdma_sgl[num_sge].memory_key = mr->lkey;
+				num_sge++;
+				m_seg = m_seg->next;
+			}
 
-			m_seg = m_seg->next;
-		}
+			if (unlikely(m_seg != NULL || num_sge < 2)) {
+				DP_LOG(ERR, "failed to build TSO SGL, num_sge %u",
+				       num_sge);
+				break;
+			}
+		} else {
+			for (seg_idx = 0; seg_idx < m_pkt->nb_segs; seg_idx++) {
+				struct mana_mr_cache *mr =
+					mana_alloc_pmd_mr(&txq->mr_btree, priv,
+							  m_seg);
+
+				if (!mr) {
+					DP_LOG(ERR,
+					       "failed to get MR, pkt_idx %u",
+					       pkt_idx);
+					break;
+				}
+
+				sgl.gdma_sgl[seg_idx].address =
+					rte_cpu_to_le_64(rte_pktmbuf_mtod(m_seg,
+									  uint64_t));
+				sgl.gdma_sgl[seg_idx].size = m_seg->data_len;
+				sgl.gdma_sgl[seg_idx].memory_key = mr->lkey;
+
+				DP_LOG(DEBUG,
+				       "seg idx %u addr 0x%" PRIx64 " size %x key %x",
+				       seg_idx, sgl.gdma_sgl[seg_idx].address,
+				       sgl.gdma_sgl[seg_idx].size,
+				       sgl.gdma_sgl[seg_idx].memory_key);
+
+				m_seg = m_seg->next;
+			}
 
-		/* Skip this packet if we can't populate all segments */
-		if (seg_idx != m_pkt->nb_segs)
-			break;
+			/* Skip this packet if we can't populate all segments */
+			if (seg_idx != m_pkt->nb_segs)
+				break;
+
+			num_sge = m_pkt->nb_segs;
+		}
 
 		/* If we can at least queue post two WQEs and there are at
 		 * least two packets to send, use TX CQE suppression for the
@@ -450,7 +569,7 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		work_req.gdma_header.struct_size = sizeof(work_req);
 
 		work_req.sgl = sgl.gdma_sgl;
-		work_req.num_sgl_elements = m_pkt->nb_segs;
+		work_req.num_sgl_elements = num_sge;
 		if (tx_oob.short_oob.packet_format == SHORT_PACKET_FORMAT)
 			work_req.inline_oob_size_in_bytes =
 				sizeof(struct transmit_short_oob_v2);
@@ -458,8 +577,14 @@ mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			work_req.inline_oob_size_in_bytes =
 				sizeof(struct transmit_oob_v2);
 		work_req.inline_oob_data = &tx_oob;
-		work_req.flags = 0;
-		work_req.client_data_unit = NOT_USING_CLIENT_DATA_UNIT;
+		if (is_tso) {
+			work_req.flags = GDMA_WR_OOB_IN_SGL |
+					 GDMA_WR_PAD_BY_SGE0;
+			work_req.client_data_unit = m_pkt->tso_segsz;
+		} else {
+			work_req.flags = 0;
+			work_req.client_data_unit = NOT_USING_CLIENT_DATA_UNIT;
+		}
 
 		ret = gdma_post_work_request(&txq->gdma_sq, &work_req,
 					     &wqe_size_in_bu);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] net/mana: fix transmit burst and add hardware TSO support
  2026-10-12  7:36 [PATCH 0/2] net/mana: fix transmit burst and add hardware TSO support Tathagat Priyadarshi
  2026-10-12  7:36 ` [PATCH 1/2] net/mana: fix transmit burst error handling Tathagat Priyadarshi
  2026-10-12  7:36 ` [PATCH 2/2] net/mana: add hardware TSO support Tathagat Priyadarshi
@ 2026-10-12 21:37 ` Stephen Hemminger
  2 siblings, 0 replies; 4+ messages in thread
From: Stephen Hemminger @ 2026-10-12 21:37 UTC (permalink / raw)
  To: Tathagat Priyadarshi; +Cc: dev, Long Li, Wei Hu

On Mon, 12 Oct 2026 07:36:24 +0000
Tathagat Priyadarshi <tathagat.dpdk@gmail.com> wrote:

> This patch series addresses transmit burst error handling and introduces
> hardware TCP Segmentation Offload (TSO) support for the Microsoft Azure
> MANA PMD.
> 
> Patch 1 fixes the transmit burst loop in mana_tx_burst() to terminate
> with break instead of continue upon packet errors. Under the DPDK
> rte_eth_tx_burst() API contract, callers expect a contiguous prefix of
> transmitted packets. Skipping a packet caused unsent packets to be treated
> as unsent and freed by caller, followed by a second free upon hardware CQE
> arrival.
> 
> Patch 2 adds support for hardware TCP Segmentation Offload (TSO),
> formatting SGL entries with packet headers in SGE0, handling GDMA work
> request flags, advertising RTE_ETH_TX_OFFLOAD_TCP_TSO, and updating
> the mana driver feature table.
> 
> Tathagat Priyadarshi (2):
>   net/mana: fix transmit burst error handling
>   net/mana: add hardware TSO support


Several problems with this patch series.

Review: [PATCH 1/2] net/mana: fix transmit burst error handling
        [PATCH 2/2] net/mana: add hardware TSO support

Series summary
--------------
Patch 1 correctly identifies the bug (continue breaks the prefix
contract and leads to double free) but the fix trades it for a
head-of-line block. Patch 2 carries a stable-worthy bounds fix that
should be in patch 1, and adds more break-on-bad-packet paths.


Patch 1/2
---------

Error: break on a per-packet validation failure stalls the queue.

A packet that exceeds max_send_sge, or whose MR lookup fails, will
fail again on every retry. Applications that loop until all packets
are sent (testpmd with retry, most forwarding apps) spin forever on
it. Short return from tx_burst is for ring full / backpressure only;
a bad packet must be dropped, counted, and consumed so the prefix
contract still holds.

Keep pkt_sent for the doorbell, and return a separate count of
consumed packets:

	uint16_t nb_done = 0;
	...
	if (unlikely(m_pkt->nb_segs > priv->max_send_sge)) {
		DP_LOG(ERR, "send packet segments %d exceeding max",
		       m_pkt->nb_segs);
		goto drop;
	}
	...
	if (seg_idx != m_pkt->nb_segs)
		goto drop;
	...
	if (!ret) {
		...
		pkt_sent++;
		nb_done++;
		...
	} else {
		break;		/* ring full: real backpressure */
	}
	continue;
drop:
	txq->stats.errors++;
	rte_pktmbuf_free(m_pkt);
	nb_done++;
	}
	...
	return nb_done;

Note the RTE_ARCH_32 short doorbell break happens after nb_done is
incremented, so the count stays correct there.

Info: CQE suppression is decided before the next packet is known to
be valid. If the packet after a suppressed WQE fails, no completion
is generated until a later burst posts an unsuppressed WQE; with no
further traffic those mbufs are held indefinitely. This existed
before, but break makes it reachable from any mid-burst failure
rather than only the last packet. With drop-and-continue it is back
to the last-packet case only.


Patch 2/2
---------

Error: same as 1/2. The new "TSO header cannot be fragmented",
"Invalid IP version for TSO" and "failed to build TSO SGL" paths
all break and leave the packet at the head of the burst. They are
permanent per-packet failures; use the drop path.

Warning: the MAX_SGL_ENTRIES_FOR_TRANSMIT check fixes an existing
bug and does not belong in a feature patch. sgl.gdma_sgl[] is sized
MAX_SGL_ENTRIES_FOR_TRANSMIT (30) but the old non-TSO loop writes up
to nb_segs <= max_send_sge entries, and max_send_sge comes from the
device with nothing clamping it to 30. Move that check to patch 1
(or its own fix with Fixes/Cc stable), and clamp what is advertised:

	dev_info->tx_desc_lim.nb_seg_max =
		RTE_MIN(priv->max_send_sge, MAX_SGL_ENTRIES_FOR_TRANSMIT);
	dev_info->tx_desc_lim.nb_mtu_seg_max =
		RTE_MIN(priv->max_send_sge, MAX_SGL_ENTRIES_FOR_TRANSMIT);

Also, a TSO packet with payload in the first segment needs one
extra SGE. An application that honours nb_seg_max will still get
drops; either advertise nb_seg_max - 1 when TSO is enabled or
document the limit in mana.rst.

Warning: RTE_MBUF_F_TX_TCP_SEG implies RTE_MBUF_F_TX_TCP_CKSUM
(rte_mbuf_core.h). When TCP_SEG is set but the packet falls back to
the non-TSO path (tso_segsz == 0 or no payload), the TCP checksum
is only offloaded if the application also set TCP_CKSUM. Make the
fallback honour the implied flag:

	} else if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) ==
			RTE_MBUF_F_TX_TCP_CKSUM ||
		   (m_pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {

Warning: no release note. New driver features go in
doc/guides/rel_notes/release_26_11.rst under New Features.

Warning: commit message is a bullet list restating the diff (which
macro is defined where, which field is zeroed). Say what is added
and why, and how it was tested: which Azure SKU / MANA firmware,
IPv4 and IPv6, single and multi-segment mbufs, e.g. testpmd
"csum set tcp hw" + "tso set <mss>" with iperf through the VM.

Info: the num_sge >= MAX_SGL_ENTRIES_FOR_TRANSMIT check inside the
TSO segment loop cannot trigger; expected_sge was already checked
against the same limit and nb_segs bounds the walk. Drop it.

Info: GDMA_WR_OOB_IN_SGL and GDMA_WR_PAD_BY_SGE0 are hardware work
request flags. Put them next to struct gdma_work_request (the flags
member comment already refers to them) rather than between the
offload capability macros.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-12 21:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-12  7:36 [PATCH 0/2] net/mana: fix transmit burst and add hardware TSO support Tathagat Priyadarshi
2026-10-12  7:36 ` [PATCH 1/2] net/mana: fix transmit burst error handling Tathagat Priyadarshi
2026-10-12  7:36 ` [PATCH 2/2] net/mana: add hardware TSO support Tathagat Priyadarshi
2026-10-12 21:37 ` [PATCH 0/2] net/mana: fix transmit burst and " Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox