[PATCH v3 02/14] net/enetc: add TSO support for ENETC4 VF

Gagandeep Singh g.singh at nxp.com
Fri Aug 7 09:02:29 CEST 2026


Add TCP and UDP segmentation offload (TSO) for the ENETC4 virtual
function. The offload is advertised through the VF Tx capabilities and
is enabled on a per-queue basis when an application requests the TSO
offload flags during Tx queue setup.

A dedicated Tx burst, enetc_xmit_pkts_lso(), builds the large-send
descriptor chain: a standard header BD, a 16B extension BD carrying the
segment size and frame length extension, and one BD per payload buffer
with the final-frame flag on the last BD. To make room for the extra
extension BD, an LSO-enabled Tx ring is allocated with twice the number
of descriptors. The existing non-TSO Tx paths are left unchanged.

Update the ENETC4 feature list and documentation accordingly.

Signed-off-by: Gagandeep Singh <g.singh at nxp.com>
---
 doc/guides/nics/enetc4.rst             |   2 +
 doc/guides/nics/features/enetc4.ini    |   1 +
 doc/guides/rel_notes/release_26_11.rst |   1 +
 drivers/net/enetc/base/enetc4_hw.h     |  35 +++-
 drivers/net/enetc/enetc.h              |   5 +
 drivers/net/enetc/enetc4_ethdev.c      |  45 ++++-
 drivers/net/enetc/enetc4_vf.c          |   2 +
 drivers/net/enetc/enetc_rxtx.c         | 255 +++++++++++++++++++++++++
 8 files changed, 341 insertions(+), 5 deletions(-)

diff --git a/doc/guides/nics/enetc4.rst b/doc/guides/nics/enetc4.rst
index f0dd039f6e..4d27e4048e 100644
--- a/doc/guides/nics/enetc4.rst
+++ b/doc/guides/nics/enetc4.rst
@@ -53,6 +53,8 @@ Key functionality includes:
 - Receive processing: Upon packet reception, the BD Ring status bit is set,
   facilitating packet processing.
 - Transmission: Packet transmission precedes reception, ensuring efficient data transfer.
+- TCP and UDP segmentation offload (TSO) on VFs, enabled per Tx queue
+  when the TSO offload flag is requested.
 
 
 Prerequisites
diff --git a/doc/guides/nics/features/enetc4.ini b/doc/guides/nics/features/enetc4.ini
index 91b18d979e..8ec1e8d00f 100644
--- a/doc/guides/nics/features/enetc4.ini
+++ b/doc/guides/nics/features/enetc4.ini
@@ -7,6 +7,7 @@
 Link status event    = Y
 Speed capabilities   = Y
 Link status          = Y
+TSO                  = Y
 Promiscuous mode     = Y
 Allmulticast mode    = Y
 Unicast MAC filter   = Y
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 3678dd6894..6a348ab4e0 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -61,6 +61,7 @@ New Features
   Updated the NXP ENETC4 poll mode driver for i.MX95:
 
   * Added KEEP_CRC Rx offload support for the ENETC4 PMD to preserve the Ethernet FCS.
+  * Added TCP Segmentation Offload (TSO) support for the ENETC4 VF.
 
 Removed Items
 -------------
diff --git a/drivers/net/enetc/base/enetc4_hw.h b/drivers/net/enetc/base/enetc4_hw.h
index 0105549857..64c1a5e750 100644
--- a/drivers/net/enetc/base/enetc4_hw.h
+++ b/drivers/net/enetc/base/enetc4_hw.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2024 NXP
+ * Copyright 2024-2026 NXP
  *
  * This header file defines the register offsets and bit fields
  * of ENETC4 PF and VFs.
@@ -24,8 +24,14 @@ struct enetc_msg_swbd {
 
 /* enetc4 txbd flags */
 #define ENETC4_TXBD_FLAGS_L4CS		BIT(0)
+/* Request LSO (Large Send Offload) segmentation for this frame */
+#define ENETC4_TXBD_FLAGS_LSO		BIT(1)
+/* L4 checksum insertion (also used for checksum update on LSO) */
 #define ENETC4_TXBD_FLAGS_L_TX_CKSUM	BIT(3)
+/* Extended descriptor: the next 16B ring entry is an extension BD */
+#define ENETC4_TXBD_FLAGS_EXT		BIT(6)
 #define ENETC4_TXBD_FLAGS_F		BIT(7)
+
 /* L4 type */
 #define ENETC4_TXBD_L4T_UDP		BIT(0)
 #define ENETC4_TXBD_L4T_TCP		BIT(1)
@@ -34,6 +40,33 @@ struct enetc_msg_swbd {
 /* IPv4 checksum */
 #define ENETC4_TXBD_IPCS		1
 
+/*
+ * Extension Transmit Buffer Descriptor (16B). When the standard BD has the
+ * extended flag set, this occupies the next ring entry and carries the extra
+ * fields required by LSO.
+ */
+struct enetc_tx_bd_ext {
+	uint32_t timestamp;	/* PTP timestamp, unused for LSO */
+	uint32_t vlan;		/* VLAN insert, unused for LSO */
+	uint32_t lso;		/* LSO_MAX_SEG_SIZE and FRM_LEN_EXT */
+	uint32_t flags;		/* extension flags */
+};
+
+/* LSO_MAX_SEG_SIZE occupies bits 13-0 of the LSO word */
+#define ENETC4_TXBD_EXT_LSO_SEG_MASK	0x3fff
+#define ENETC4_TXBD_EXT_LSO_SEG(mss) \
+		((uint32_t)((mss) & ENETC4_TXBD_EXT_LSO_SEG_MASK))
+/* FRM_LEN_EXT occupies bits 19-16 of the LSO word (top 4 bits of data len) */
+#define ENETC4_TXBD_EXT_FRM_LEN_EXT(x) \
+		(((uint32_t)((x) & 0xf)) << 16)
+/* Final flag in the extension flags word (bit 127 -> local bit 31) */
+#define ENETC4_TXBD_EXT_FLAGS_F		BIT(31)
+
+/* NETC does not create LSO frames larger than this many bytes */
+#define ENETC4_LSO_MAX_FRAME		9600
+/* Maximum LSO data unit (payload to be segmented) supported by HW: 256KB */
+#define ENETC4_LSO_MAX_DATA_UNIT	(256 * 1024)
+
 /***************************ENETC port registers**************************/
 #define ENETC4_PMR		0x10
 #define ENETC4_PMR_EN		(BIT(16) | BIT(17) | BIT(18))
diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h
index d3a8b8e34a..db349e051b 100644
--- a/drivers/net/enetc/enetc.h
+++ b/drivers/net/enetc/enetc.h
@@ -91,6 +91,7 @@ struct enetc_bdr {
 		void *tcisr; /* Tx */
 		int next_to_alloc; /* Rx */
 	};
+
 	struct rte_mempool *mb_pool;   /* mbuf pool to populate RX ring. */
 	/* Partial scatter-gather chain persisted across burst calls. */
 	struct rte_mbuf *pkt_first_seg; /* first segment of in-progress frame */
@@ -99,6 +100,7 @@ struct enetc_bdr {
 	uint64_t ierrors;
 	uint8_t rx_deferred_start;
 	uint8_t tx_deferred_start;
+	uint8_t lso_enable;
 };
 
 struct enetc_eth_hw {
@@ -312,6 +314,9 @@ uint16_t enetc_xmit_pkts(void *txq, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
 uint16_t enetc_xmit_pkts_nc(void *txq, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
+uint16_t enetc_xmit_pkts_lso(void *txq, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
+
 uint16_t enetc_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts,
 		uint16_t nb_pkts);
 uint16_t enetc_recv_pkts_nc(void *rxq, struct rte_mbuf **rx_pkts,
diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c
index 1a8056580c..897e12e21f 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -22,7 +22,9 @@ static uint64_t dev_rx_offloads_sup =
 static uint64_t dev_tx_offloads_sup =
 	RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
 	RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
-	RTE_ETH_TX_OFFLOAD_TCP_CKSUM;
+	RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+	RTE_ETH_TX_OFFLOAD_TCP_TSO |
+	RTE_ETH_TX_OFFLOAD_UDP_TSO;
 
 #define ENETC4_TXQ_PRIORITIES	"enetc4_txq_prior"
 #define ENETC4_NC_MEMORY	"nc"
@@ -321,28 +323,38 @@ static int
 enetc4_alloc_txbdr(struct enetc_bdr *txr, uint16_t nb_desc)
 {
 	int size;
+	uint32_t ring_desc;
 
-	size = nb_desc * sizeof(struct enetc_swbd);
+	/*
+	 * On LSO-enabled rings each frame uses an extra 16B extension BD
+	 * (logical 32B descriptor) plus the payload BDs.  Size the ring with
+	 * twice the requested entries so the effective frame capacity is
+	 * preserved.  Non-LSO rings are sized exactly as requested.
+	 */
+	ring_desc = txr->lso_enable ? (uint32_t)nb_desc * 2 : (uint32_t)nb_desc;
+
+	size = ring_desc * sizeof(struct enetc_swbd);
 	/* Zero q_swbd so buffer_addr is NULL for all uninitialized slots. */
 	txr->q_swbd = rte_zmalloc(NULL, size, ENETC_BD_RING_ALIGN);
 	if (txr->q_swbd == NULL)
 		return -ENOMEM;
 
 	/* Allocate the TX BD ring: each BD is struct enetc_tx_bd (16 bytes). */
-	size = nb_desc * sizeof(struct enetc_tx_bd);
+	size = ring_desc * sizeof(struct enetc_tx_bd);
 	txr->bd_base = rte_zmalloc(NULL, size, ENETC_BD_RING_ALIGN);
 	if (txr->bd_base == NULL) {
 		rte_free(txr->q_swbd);
 		txr->q_swbd = NULL;
 		return -ENOMEM;
 	}
-	txr->bd_count = nb_desc;
+	txr->bd_count = ring_desc;
 	txr->next_to_clean = 0;
 	txr->next_to_use = 0;
 
 	return 0;
 }
 
+
 static void
 enetc4_free_bdr(struct enetc_bdr *rxr)
 {
@@ -352,6 +364,7 @@ enetc4_free_bdr(struct enetc_bdr *rxr)
 	rxr->bd_base = NULL;
 }
 
+
 static void
 enetc4_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
 {
@@ -388,6 +401,7 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev,
 	struct rte_eth_dev_data *data = dev->data;
 	struct enetc_eth_adapter *priv =
 			ENETC_DEV_PRIVATE(data->dev_private);
+	uint64_t tx_offloads;
 
 	PMD_INIT_FUNC_TRACE();
 	if (nb_desc > MAX_BD_COUNT)
@@ -401,6 +415,29 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev,
 	}
 
 	tx_ring->index = queue_idx;
+	/*
+	 * LSO (TCP/UDP segmentation) is a port-level offload. The Tx burst is
+	 * a single device-level function pointer, so it must be consistent for
+	 * all queues; likewise every ring must be sized the same way. Decide
+	 * from the port offloads only (not the per-queue tx_conf) so that all
+	 * queues either use the LSO burst with a doubled ring, or none do.
+	 * The LSO burst also handles non-TSO packets, so it is safe on queues
+	 * that never carry TSO traffic. LSO needs HW FCS insertion, so it is
+	 * incompatible with KEEP_CRC on Rx.
+	 */
+	tx_offloads = data->dev_conf.txmode.offloads;
+	if (tx_offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO |
+			   RTE_ETH_TX_OFFLOAD_UDP_TSO)) {
+		if (data->dev_conf.rxmode.offloads &
+		    RTE_ETH_RX_OFFLOAD_KEEP_CRC) {
+			ENETC_PMD_ERR("LSO (TSO) is incompatible with KEEP_CRC");
+			rte_free(tx_ring);
+			return -EINVAL;
+		}
+		tx_ring->lso_enable = 1;
+		dev->tx_pkt_burst = &enetc_xmit_pkts_lso;
+	}
+
 	err = enetc4_alloc_txbdr(tx_ring, nb_desc);
 	if (err)
 		goto fail;
diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index 83a1e4931f..3083a56335 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -60,6 +60,8 @@ static uint64_t dev_tx_offloads_sup =
 	RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
 	RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
 	RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+	RTE_ETH_TX_OFFLOAD_TCP_TSO |
+	RTE_ETH_TX_OFFLOAD_UDP_TSO |
 	RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
 
 static void
diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c
index e3bef607dd..f19f32eace 100644
--- a/drivers/net/enetc/enetc_rxtx.c
+++ b/drivers/net/enetc/enetc_rxtx.c
@@ -221,6 +221,261 @@ enetc_xmit_pkts_nc(void *tx_queue,
 	return start;
 }
 
+/*
+ * LSO (Large Send Offload) Tx burst.
+ *
+ * Dedicated burst used on Tx rings with LSO enabled (txr->lso_enable). It
+ * follows the same non-cache-coherent discipline as enetc_xmit_pkts_cacheable:
+ * payload lines are flushed with dcbf before handing the frame to HW and the
+ * written BD cache lines are flushed at the end of the batch.
+ *
+ * A TSO/USO frame uses an extended Tx descriptor: the standard BD points at
+ * the L2/L3/L4 header template (BUF_LEN = header length, FRM_LEN = payload
+ * length), followed by an extension BD in the next ring slot holding the
+ * segment size, then one BD per payload buffer with the F flag on the last.
+ * Non-TSO packets fall through to the normal encoding so mixed traffic works.
+ */
+uint16_t
+enetc_xmit_pkts_lso(void *tx_queue,
+		struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	int i, start, bds_to_use;
+	struct enetc_tx_bd *txbd = NULL;
+	struct enetc_tx_bd_ext *txbd_ext;
+	struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue;
+	unsigned int j;
+	uint8_t *data;
+	struct rte_mbuf *seg;
+	uint16_t seg_len, segs_per_pkt;
+	bool is_first_seg;
+	int first_bd_idx, bd_count;
+
+	i = tx_ring->next_to_use;
+	bds_to_use = enetc_bd_unused(tx_ring);
+	bd_count = tx_ring->bd_count;
+	start = 0;
+
+	first_bd_idx = i;
+
+	while (start < nb_pkts) {
+		seg = tx_pkts[start];
+		segs_per_pkt = seg->nb_segs;
+
+		if (seg->ol_flags &
+		    (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
+			bool is_udp_seg =
+				!!(seg->ol_flags & RTE_MBUF_F_TX_UDP_SEG);
+			uint32_t hdr_len = seg->l2_len + seg->l3_len +
+					   seg->l4_len;
+			uint32_t data_unit;
+			uint16_t first_payload;
+			struct rte_mbuf *dseg;
+			int bds_needed;
+
+			/* Header BD + extension BD + one BD per segment. */
+			bds_needed = 2 + segs_per_pkt;
+			if (bds_to_use < bds_needed)
+				break;
+
+			/*
+			 * Skip frames with nothing to segment, or whose
+			 * headers are not fully contained in the first
+			 * segment. The first BD carries the header template
+			 * and first_payload is computed as (first segment
+			 * data_len - hdr_len), so the L2/L3/L4 headers must
+			 * reside contiguously in the first mbuf; otherwise the
+			 * unsigned subtraction would underflow.
+			 */
+			if (unlikely(hdr_len >= rte_pktmbuf_pkt_len(seg) ||
+				     hdr_len > rte_pktmbuf_data_len(seg))) {
+				start++;
+				continue;
+			}
+			data_unit = rte_pktmbuf_pkt_len(seg) - hdr_len;
+
+			/*
+			 * Skip frames that violate HW LSO limits: a zero
+			 * segment size, a payload larger than the HW data
+			 * unit, or a per-segment frame (headers + segment)
+			 * bigger than the maximum LSO frame size.
+			 */
+			if (unlikely(seg->tso_segsz == 0 ||
+				     data_unit > ENETC4_LSO_MAX_DATA_UNIT ||
+				     hdr_len + seg->tso_segsz >
+					     ENETC4_LSO_MAX_FRAME)) {
+				start++;
+				continue;
+			}
+
+			/* Standard (first) BD: header template only. */
+			data = rte_pktmbuf_mtod(seg, void *);
+
+			seg_len = rte_pktmbuf_data_len(seg);
+			for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE)
+				dcbf(data + j);
+			dcbf(data + (seg_len - 1));
+
+			txbd = ENETC_TXBD(*tx_ring, i);
+			memset(txbd, 0, sizeof(*txbd));
+			tx_ring->q_swbd[i].buffer_addr = seg;
+
+			/* FRM_LEN low 16 bits = payload length, BUF_LEN = hdr. */
+			txbd->frm_len = rte_cpu_to_le_16(data_unit & 0xffff);
+			txbd->buf_len = rte_cpu_to_le_16((uint16_t)hdr_len);
+			txbd->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(seg));
+
+			/* Checksum control for the per-segment L3/L4 rewrite. */
+			txbd->l3_start = seg->l2_len;
+			txbd->l3_hdr_size = seg->l3_len / 4;
+			if (seg->ol_flags & RTE_MBUF_F_TX_IPV6) {
+				txbd->l3t = 1;
+			} else {
+				txbd->l3t = ENETC4_TXBD_L3T;
+				txbd->ipcs = ENETC4_TXBD_IPCS;
+			}
+			txbd->l4t = is_udp_seg ? ENETC4_TXBD_L4T_UDP :
+						 ENETC4_TXBD_L4T_TCP;
+			txbd->flags = ENETC4_TXBD_FLAGS_L_TX_CKSUM |
+				      ENETC4_TXBD_FLAGS_L4CS |
+				      ENETC4_TXBD_FLAGS_LSO |
+				      ENETC4_TXBD_FLAGS_EXT;
+
+			i++;
+			bds_to_use--;
+			if (unlikely(i == bd_count))
+				i = 0;
+
+			/* Extension BD occupies the next ring slot. */
+			tx_ring->q_swbd[i].buffer_addr = NULL;
+			txbd_ext = (struct enetc_tx_bd_ext *)
+				   ENETC_TXBD(*tx_ring, i);
+			memset(txbd_ext, 0, sizeof(*txbd_ext));
+			txbd_ext->lso = rte_cpu_to_le_32(ENETC4_TXBD_EXT_LSO_SEG(seg->tso_segsz) |
+					ENETC4_TXBD_EXT_FRM_LEN_EXT(data_unit >> 16));
+
+			i++;
+			bds_to_use--;
+			if (unlikely(i == bd_count))
+				i = 0;
+
+			/*
+			 * Payload BDs. The first segment's payload starts after
+			 * the header template; remaining segments are pure
+			 * payload.
+			 */
+			first_payload = (uint16_t)(seg_len - hdr_len);
+			dseg = seg;
+			is_first_seg = true;
+			while (dseg) {
+				uint16_t dlen;
+				uint64_t daddr;
+
+				if (is_first_seg) {
+					dlen = first_payload;
+					daddr = rte_mbuf_data_iova(dseg) +
+						hdr_len;
+					is_first_seg = false;
+				} else {
+					dlen = rte_pktmbuf_data_len(dseg);
+					data = rte_pktmbuf_mtod(dseg, void *);
+					for (j = 0; j < dlen;
+					     j += RTE_CACHE_LINE_SIZE)
+						dcbf(data + j);
+					dcbf(data + (dlen - 1));
+					daddr = rte_mbuf_data_iova(dseg);
+				}
+
+				if (dlen == 0) {
+					dseg = dseg->next;
+					continue;
+				}
+
+				tx_ring->q_swbd[i].buffer_addr = NULL;
+				txbd = ENETC_TXBD(*tx_ring, i);
+				memset(txbd, 0, sizeof(*txbd));
+				txbd->buf_len = rte_cpu_to_le_16(dlen);
+				txbd->addr = rte_cpu_to_le_64(daddr);
+				i++;
+				bds_to_use--;
+				if (unlikely(i == bd_count))
+					i = 0;
+				dseg = dseg->next;
+			}
+
+			/* Mark the last written BD as frame-last. */
+			txbd->flags |= ENETC4_TXBD_FLAGS_F;
+			start++;
+			continue;
+		}
+
+		/* Non-TSO packet: standard single/multi-seg encoding. */
+		if (bds_to_use < segs_per_pkt)
+			break;
+
+		is_first_seg = true;
+		while (seg) {
+			tx_ring->q_swbd[i].buffer_addr = NULL;
+			seg_len = rte_pktmbuf_data_len(seg);
+			data = rte_pktmbuf_mtod(seg, void *);
+
+			for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE)
+				dcbf(data + j);
+			dcbf(data + (seg_len - 1));
+
+			txbd = ENETC_TXBD(*tx_ring, i);
+			txbd->flags = 0;
+			if (is_first_seg) {
+				tx_ring->q_swbd[i].buffer_addr = seg;
+				txbd->frm_len = rte_pktmbuf_pkt_len(seg);
+				if (seg->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK)
+					enetc4_tx_offload_checksum(seg, txbd);
+				is_first_seg = false;
+			}
+
+			txbd->buf_len = rte_cpu_to_le_16(seg_len);
+			txbd->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(seg));
+			seg = seg->next;
+			i++;
+			bds_to_use--;
+
+			if (unlikely(i == bd_count))
+				i = 0;
+		}
+
+		txbd->flags |= rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_F);
+		start++;
+	}
+
+	/*
+	 * Flush TX BDs to PoC so HW (non-cache-coherent i.MX95) can read the
+	 * descriptors from memory.  Same discipline as enetc_xmit_pkts_cacheable:
+	 * walk from the cache-line-aligned start of first_bd_idx to just past
+	 * the last written BD, one dcbf per 64-byte (4-BD) line.
+	 */
+	if (likely(start > 0)) {
+		int n = first_bd_idx & ~ENETC_BD_PER_CL_MASK;
+		int written = (i - n + bd_count) % bd_count;
+
+		if (written == 0)
+			written = bd_count;
+		written = (written + ENETC_BD_PER_CL_MASK) &
+			  ~ENETC_BD_PER_CL_MASK;
+
+		while (written > 0) {
+			dcbf((void *)ENETC_TXBD(*tx_ring, n));
+			n = (n + ENETC_BD_PER_CL) % bd_count;
+			written -= ENETC_BD_PER_CL;
+		}
+	}
+
+	enetc_clean_tx_ring(tx_ring);
+	tx_ring->next_to_use = i;
+	enetc_wr_reg(tx_ring->tcir, i);
+
+	return start;
+}
+
 int
 enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
 {
-- 
2.25.1



More information about the dev mailing list