DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Gagandeep Singh <g.singh@nxp.com>
To: dev@dpdk.org
Cc: hemant.agrawal@nxp.com, Gagandeep Singh <g.singh@nxp.com>
Subject: [PATCH v6 03/13] net/enetc: add RSC (hardware LRO) support for ENETC4
Date: Tue, 11 Aug 2026 13:10:22 +0530	[thread overview]
Message-ID: <20260811074032.3646324-4-g.singh@nxp.com> (raw)
In-Reply-To: <20260811074032.3646324-1-g.singh@nxp.com>

Add Receive Segment Coalesce (RSC) support, exposed as the DPDK
RTE_ETH_RX_OFFLOAD_TCP_LRO Rx offload, for the ENETC4 PF and VF on
i.MX95. RSC lets the HW coalesce multiple in-order TCP segments of a
flow into a single receive frame, reducing per-packet overhead.

RSC is a port-level offload driven by a dedicated Rx burst
(enetc_recv_pkts_rsc). When TCP LRO is requested the ring is switched
to 32B extended receive descriptors (RBaMR[BDS] = 1), the FCS is
stripped (RBaMR[CRC] = 0, so RSC is incompatible with KEEP_CRC),
interrupt coalescing is enabled (RBaICR0[ICEN] with a non-zero
RBaICR1[ICTT] hold timer that doubles as the RSC flush window), and
RBaRSCR[EN] is set with the coalesced-frame size clamped to the HW
maximum.

Because a 32B descriptor spans two 16B ring slots, the ring length
register (RBaLENR) and the consumer-index register are programmed in
HW-descriptor units (slot count / 2), while the internal SW indices
continue to track 16B slots. Coalesced clusters are delivered with the
RTE_MBUF_F_RX_LRO flag set when RSC_FRAMES > 1.

Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
---
 doc/guides/nics/enetc4.rst             |   4 +
 doc/guides/nics/features/enetc4.ini    |   1 +
 doc/guides/rel_notes/release_26_11.rst |   1 +
 drivers/net/enetc/base/enetc4_hw.h     |  75 ++++++++
 drivers/net/enetc/enetc.h              |   5 +
 drivers/net/enetc/enetc4_ethdev.c      | 112 +++++++++++-
 drivers/net/enetc/enetc4_vf.c          |   1 +
 drivers/net/enetc/enetc_rxtx.c         | 234 +++++++++++++++++++++++++
 8 files changed, 427 insertions(+), 6 deletions(-)

diff --git a/doc/guides/nics/enetc4.rst b/doc/guides/nics/enetc4.rst
index 4d27e4048e..e7f4348603 100644
--- a/doc/guides/nics/enetc4.rst
+++ b/doc/guides/nics/enetc4.rst
@@ -55,6 +55,10 @@ Key functionality includes:
 - 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.
+- Large receive offload (LRO) on the receive path via hardware Receive
+  Segment Coalesce (RSC), enabled when the TCP LRO Rx offload flag is
+  requested. RSC requires the FCS to be stripped, so it cannot be combined
+  with the KEEP_CRC Rx offload.
 
 
 Prerequisites
diff --git a/doc/guides/nics/features/enetc4.ini b/doc/guides/nics/features/enetc4.ini
index 8ec1e8d00f..aae398e210 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
+LRO                  = Y
 TSO                  = Y
 Promiscuous mode     = Y
 Allmulticast mode    = Y
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 6a348ab4e0..0dd08e0259 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -62,6 +62,7 @@ New Features
 
   * 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.
+  * Added Receive Segment Coalesce (RSC / hardware LRO) support for ENETC4 PF and VF.
 
 Removed Items
 -------------
diff --git a/drivers/net/enetc/base/enetc4_hw.h b/drivers/net/enetc/base/enetc4_hw.h
index 6bc462a93e..d42c04df4b 100644
--- a/drivers/net/enetc/base/enetc4_hw.h
+++ b/drivers/net/enetc/base/enetc4_hw.h
@@ -102,6 +102,81 @@ struct enetc_tx_bd_ext {
 
 /* RBaMR[CRC]: 0 = FCS removed, 1 = FCS preserved (KEEP_CRC) */
 #define ENETC4_RBMR_CRC			BIT(8)
+/*
+ * RBaMR[BDS]: buffer descriptor size select for a receive ring.
+ * 0 = standard 16B descriptors, 1 = extended 32B descriptors.
+ * RSC requires 32B descriptors (BDS = 1). Matches the Linux enetc
+ * driver definition (ENETC_RBMR_BDS = BIT(2)).
+ */
+#define ENETC4_RBMR_BDS			BIT(2)
+
+/*
+ * Rx BDR a RSC register (RBaRSCR), offset 0x30 from the ring base.
+ * Controls Receive Segment Coalesce (RSC / LRO) for the ring.
+ */
+#define ENETC4_RBRSCR			0x30
+/* Enable RSC on this ring */
+#define ENETC4_RBRSCR_EN		BIT(31)
+/* Permit coalescing of TCP segments that carry the timestamp option */
+#define ENETC4_RBRSCR_CT		BIT(29)
+/* SIZE field (bits 15-0): maximum coalesced frame size produced by RSC */
+#define ENETC4_RBRSCR_SIZE(x)		((uint32_t)((x) & 0xffff))
+
+/*
+ * RBaICR0[ICEN]: interrupt coalescing enable. RSC requires interrupt
+ * coalescing to be enabled; the coalescing timer doubles as the RSC flush
+ * timer. ICPT (bits 8-0) is the packet-count threshold.
+ */
+#define ENETC4_RBICR0			0xa8
+#define ENETC4_RBICR0_ICEN		BIT(31)
+#define ENETC4_RBICR0_ICPT(x)		((uint32_t)((x) & 0x1ff))
+/* Rx BDR a interrupt coalescing register 1 (threshold timer) */
+#define ENETC4_RBICR1			0xac
+
+/*
+ * SI-level Rx interrupt detect register 0 (SIRXIDR0). W1C, one bit per Rx
+ * ring (RX0..RX23). The interrupt-coalescing timer (which also gates RSC
+ * coalescing) does not re-arm while a ring's detect bit stays set, so the
+ * poll-mode driver writes BIT(ring index) here every poll to keep RSC
+ * coalescing. The per-ring RBaIDR (0xa4) is read-only and cannot be used.
+ */
+#define ENETC_SIRXIDR			0xa28
+
+/*
+ * RSC (Receive Segment Coalesce) limits and defaults.
+ * Maximum coalesced frame size the HW will build (programmed in RBaRSCR[SIZE]).
+ * Bounded to 16 bits by the SIZE field width.
+ */
+#define ENETC4_RSC_MAX_FRAME		0xffff
+/* Default interrupt coalescing packet threshold used to satisfy RSC's ICEN
+ * precondition. The PMD is poll-mode, so this only gates the RSC flush timer.
+ */
+#define ENETC4_RSC_DEF_ICPT		1
+/*
+ * Default interrupt coalescing timer threshold (RBaICR1[ICTT]), in NETC
+ * platform clock cycles. This timer is the RSC coalesce-hold window: HW keeps
+ * a coalesced frame open while it runs and appends in-order segments. A value
+ * of 0 disables the timer and flushes every segment separately (no
+ * coalescing), so it must be non-zero for RSC to merge anything.
+ */
+#define ENETC4_RSC_DEF_ICTT		0x10000
+
+/*
+ * Extended 32B receive writeback buffer descriptor. Used only on RSC-enabled
+ * rings (RBaMR[BDS] = 1). The first 16 bytes match the standard descriptor
+ * writeback layout; the second 16 bytes carry the RSC and timestamp fields.
+ * RSC_FRAMES reports how many frames were coalesced (1 to 255; 1 means the
+ * frame was not coalesced).
+ */
+struct enetc_rx_bd_ext {
+	uint32_t timestamp;	/* offset 0x10: PTP timestamp */
+	uint32_t rsc_frames;	/* offset 0x14: RSC_FRAMES in bits 7-0 */
+	uint32_t rsc_abs_ts_delta; /* offset 0x18 */
+	uint32_t reserved;	/* offset 0x1c */
+};
+
+/* RSC_FRAMES occupies bits 7-0 of the rsc_frames word */
+#define ENETC4_RXBD_EXT_RSC_FRAMES(x)	((x) & 0xff)
 
 /* i.MX95 supports jumbo frame, but it is recommended to set the max frame
  * size to 2000 bytes.
diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h
index 6cd031f269..145ebbbb00 100644
--- a/drivers/net/enetc/enetc.h
+++ b/drivers/net/enetc/enetc.h
@@ -100,6 +100,8 @@ struct enetc_bdr {
 	uint8_t rx_deferred_start;
 	uint8_t tx_deferred_start;
 	uint8_t lso_enable;
+	void *rbidr;
+	uint8_t rsc_enable;
 };
 
 struct enetc_eth_hw {
@@ -319,12 +321,15 @@ 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,
 		uint16_t nb_pkts);
+uint16_t enetc_recv_pkts_rsc(void *rxq, struct rte_mbuf **rx_pkts,
+		uint16_t nb_pkts);
 uint16_t enetc_xmit_pkts_cacheable(void *txq, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
 uint16_t enetc_recv_pkts_cacheable(void *rxq, struct rte_mbuf **rx_pkts,
 		uint16_t nb_pkts);
 
 int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt);
+int enetc_refill_rx_ring_rsc(struct enetc_bdr *rx_ring, const int buff_cnt);
 
 /*
  * Cache-maintenance constants for cacheable BD ring mode.
diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c
index 24c454fe28..925da3f68e 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -17,7 +17,8 @@ static uint64_t dev_rx_offloads_sup =
 	RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
 	RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
 	RTE_ETH_RX_OFFLOAD_SCATTER |
-	RTE_ETH_RX_OFFLOAD_KEEP_CRC;
+	RTE_ETH_RX_OFFLOAD_KEEP_CRC |
+	RTE_ETH_RX_OFFLOAD_TCP_LRO;
 
 /* Supported Tx offloads */
 static uint64_t dev_tx_offloads_sup =
@@ -302,6 +303,8 @@ enetc4_dev_infos_get(struct rte_eth_dev *dev,
 	dev_info->max_rx_pktlen = ENETC4_MAC_MAXFRM_SIZE;
 	dev_info->rx_offload_capa = dev_rx_offloads_sup;
 	dev_info->tx_offload_capa = dev_tx_offloads_sup;
+	/* Max RSC (LRO) coalesced frame size; matches RBaRSCR[SIZE]. */
+	dev_info->max_lro_pkt_size = ENETC4_RSC_MAX_FRAME;
 	dev_info->flow_type_rss_offloads = ENETC_RSS_OFFLOAD_ALL;
 
 	return 0;
@@ -512,22 +515,35 @@ static int
 enetc4_alloc_rxbdr(struct enetc_bdr *rxr, uint16_t nb_desc)
 {
 	int size;
+	uint32_t ring_desc;
+
+	/*
+	 * RSC rings use 32B descriptors (RBaMR[BDS] = 1), i.e. two 16B slots
+	 * each, so allocate 2 * nb_desc slots. Non-RSC rings use 16B slots.
+	 */
+	ring_desc = rxr->rsc_enable ? (uint32_t)nb_desc * 2 : (uint32_t)nb_desc;
+	if (ring_desc > MAX_BD_COUNT) {
+		ENETC_PMD_ERR("RSC ring_desc %u > MAX_BD_COUNT %u; "
+			      "reduce nb_desc to <= %u with RSC enabled",
+			      ring_desc, MAX_BD_COUNT, MAX_BD_COUNT / 2);
+		return -EINVAL;
+	}
 
-	size = nb_desc * sizeof(struct enetc_swbd);
+	size = ring_desc * sizeof(struct enetc_swbd);
 	/* Zero q_swbd so buffer_addr is NULL for all uninitialized slots. */
 	rxr->q_swbd = rte_zmalloc(NULL, size, ENETC_BD_RING_ALIGN);
 	if (rxr->q_swbd == NULL)
 		return -ENOMEM;
 
 	/* Allocate the RX BD ring: each BD is union enetc_rx_bd (16 bytes). */
-	size = nb_desc * sizeof(union enetc_rx_bd);
+	size = ring_desc * sizeof(union enetc_rx_bd);
 	rxr->bd_base = rte_zmalloc(NULL, size, ENETC_BD_RING_ALIGN);
 	if (rxr->bd_base == NULL) {
 		rte_free(rxr->q_swbd);
 		rxr->q_swbd = NULL;
 		return -ENOMEM;
 	}
-	rxr->bd_count = nb_desc;
+	rxr->bd_count = ring_desc;
 	rxr->next_to_clean = 0;
 	rxr->next_to_use = 0;
 	rxr->next_to_alloc = 0;
@@ -550,13 +566,30 @@ enetc4_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring,
 		       lower_32_bits((uint64_t)bd_address));
 	enetc4_rxbdr_wr(hw, idx, ENETC_RBBAR1,
 		       upper_32_bits((uint64_t)bd_address));
+	/*
+	 * RBaLENR counts HW descriptors. With RSC (BDS = 1) a descriptor is
+	 * 32B (two 16B slots), so program bd_count / 2; otherwise bd_count.
+	 */
 	enetc4_rxbdr_wr(hw, idx, ENETC_RBLENR,
-		       ENETC_RTBLENR_LEN(rx_ring->bd_count));
+		       ENETC_RTBLENR_LEN(rx_ring->rsc_enable ?
+				rx_ring->bd_count / 2 : rx_ring->bd_count));
 
 	rx_ring->mb_pool = mb_pool;
 	rx_ring->rcir = (void *)((size_t)hw->reg +
 			ENETC_BDR(RX, idx, ENETC_RBCIR));
-	enetc_refill_rx_ring(rx_ring, ENETC_BD_ALIGN_DOWN(enetc_bd_unused(rx_ring)));
+	/* RSC rings clear their Rx interrupt-detect event via SIRXIDR (see
+	 * enetc_clean_rx_ring_rsc); cache the register address here.
+	 */
+	if (rx_ring->rsc_enable)
+		rx_ring->rbidr = (void *)((size_t)hw->reg + ENETC_SIRXIDR);
+
+	/* RSC rings use the 2-slot-stride refill for 32B descriptors. */
+	if (rx_ring->rsc_enable)
+		enetc_refill_rx_ring_rsc(rx_ring,
+			ENETC_BD_ALIGN_DOWN(enetc_bd_unused(rx_ring)));
+	else
+		enetc_refill_rx_ring(rx_ring,
+			ENETC_BD_ALIGN_DOWN(enetc_bd_unused(rx_ring)));
 	buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rx_ring->mb_pool) -
 		   RTE_PKTMBUF_HEADROOM);
 	enetc4_rxbdr_wr(hw, idx, ENETC_RBBSR, buf_size);
@@ -578,7 +611,9 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
 	struct enetc_eth_adapter *adapter =
 			ENETC_DEV_PRIVATE(data->dev_private);
 	uint64_t rx_offloads = data->dev_conf.rxmode.offloads;
+	uint32_t rsc_size;
 	bool keep_crc;
+	bool rsc_enable;
 
 	PMD_INIT_FUNC_TRACE();
 	if (nb_rx_desc > MAX_BD_COUNT)
@@ -595,6 +630,28 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
 	keep_crc = !!(rx_offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC);
 	rx_ring->crc_len = (uint8_t)(keep_crc ? RTE_ETHER_CRC_LEN : 0);
 
+	/*
+	 * RSC (LRO) is a port-level offload: the Rx burst is a single device
+	 * function pointer, so decide from port offloads (not per-queue
+	 * rx_conf) to keep all rings consistent. RSC needs HW FCS stripping
+	 * (RBaMR[CRC] = 0), so it is incompatible with KEEP_CRC.
+	 */
+	rsc_enable = !!(rx_offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO);
+	if (rsc_enable) {
+		if (keep_crc) {
+			ENETC_PMD_ERR("RSC (LRO) is incompatible with KEEP_CRC");
+			rte_free(rx_ring);
+			return -EINVAL;
+		}
+		if (adapter->hw.nc_mode) {
+			ENETC_PMD_ERR("RSC (LRO) is incompatible with nc=1 (non-cacheable mode)");
+			rte_free(rx_ring);
+			return -EINVAL;
+		}
+		rx_ring->rsc_enable = 1;
+		dev->rx_pkt_burst = &enetc_recv_pkts_rsc;
+	}
+
 	err = enetc4_alloc_rxbdr(rx_ring, nb_rx_desc);
 	if (err)
 		goto fail;
@@ -613,6 +670,49 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
 	else
 		rx_enable &= ~ENETC4_RBMR_CRC;
 
+	if (rsc_enable) {
+		/*
+		 * RSC preconditions (all must hold or RBaRSCR[EN] is ignored):
+		 * BDS = 1 (32B descriptors), CRC = 0 (FCS stripped, enforced
+		 * above), ICEN = 1 (its timer doubles as the RSC flush timer),
+		 * and RBaRSCR[EN] with CT for timestamped segments. SIZE caps
+		 * the coalesced frame; honor rxmode.max_lro_pkt_size clamped to
+		 * the HW max, falling back to the HW max when unset.
+		 */
+		rx_enable |= ENETC4_RBMR_BDS;
+
+		/*
+		 * Commit RBMR[BDS] to HW now (ring still disabled, EN clear)
+		 * so the 32B descriptor mode is active before RBaRSCR[EN] is
+		 * set. BDS = 1 is a hard RSC precondition: if RBaRSCR[EN] is
+		 * written while BDS is still 0 in HW, RSC may be silently
+		 * ignored. The ring-enable step below writes RBMR again with
+		 * EN added.
+		 */
+		enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index, ENETC_RBMR,
+			       rx_enable);
+
+		rsc_size = data->dev_conf.rxmode.max_lro_pkt_size;
+		if (rsc_size == 0 || rsc_size > ENETC4_RSC_MAX_FRAME)
+			rsc_size = ENETC4_RSC_MAX_FRAME;
+
+		/*
+		 * Program ICTT FIRST (with ICEN = 0) then enable ICEN, as the
+		 * RM requires. ICTT is the RSC coalesce-hold window; a zero
+		 * value disables the timer and forces HW to flush every frame
+		 * (no coalescing), so use a non-zero default.
+		 */
+		enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index,
+			       ENETC4_RBICR1, ENETC4_RSC_DEF_ICTT);
+		enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index,
+			       ENETC4_RBICR0, ENETC4_RBICR0_ICEN |
+			       ENETC4_RBICR0_ICPT(ENETC4_RSC_DEF_ICPT));
+		enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index,
+			       ENETC4_RBRSCR, ENETC4_RBRSCR_EN |
+			       ENETC4_RBRSCR_CT |
+			       ENETC4_RBRSCR_SIZE(rsc_size));
+	}
+
 	if (!rx_conf->rx_deferred_start) {
 		/* enable ring */
 		rx_enable |= ENETC_RBMR_EN;
diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index 3083a56335..be79a18a39 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -53,6 +53,7 @@ static uint64_t dev_rx_offloads_sup =
 	RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
 	RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
 	RTE_ETH_RX_OFFLOAD_KEEP_CRC |
+	RTE_ETH_RX_OFFLOAD_TCP_LRO |
 	RTE_ETH_RX_OFFLOAD_SCATTER;
 
 /* Supported Tx offloads */
diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c
index 0bb5a86dd8..8d3008843c 100644
--- a/drivers/net/enetc/enetc_rxtx.c
+++ b/drivers/net/enetc/enetc_rxtx.c
@@ -907,6 +907,240 @@ enetc_recv_pkts_nc(void *rxq, struct rte_mbuf **rx_pkts,
 	return enetc_clean_rx_ring_nc(rx_ring, rx_pkts, nb_pkts);
 }
 
+/*
+ * RSC (LRO) refill. buff_cnt is in 16B slots; each 32B descriptor is two
+ * slots. The even slot takes a fresh mbuf, the odd extension slot never owns
+ * a buffer, so walk the ring two slots at a time. Cache maintenance mirrors
+ * enetc_refill_rx_ring (dcbf per 64B line, i.e. two descriptors).
+ */
+int
+enetc_refill_rx_ring_rsc(struct enetc_bdr *rx_ring, const int buff_cnt)
+{
+	struct enetc_swbd *rx_swbd;
+	union enetc_rx_bd *rxbd, *grp_start_rxbd;
+	int i, j, k = ENETC_RXBD_BUNDLE;
+	struct rte_mbuf *m[ENETC_RXBD_BUNDLE];
+	struct rte_mempool *mb_pool;
+
+	i = rx_ring->next_to_use;
+	mb_pool = rx_ring->mb_pool;
+	rx_swbd = &rx_ring->q_swbd[i];
+	rxbd = ENETC_RXBD(*rx_ring, i);
+	grp_start_rxbd = rxbd;
+
+	for (j = 0; j < buff_cnt; j += 2) {
+		/* Bulk alloc one mbuf per descriptor (every two slots). */
+		if (k == ENETC_RXBD_BUNDLE) {
+			int want = (buff_cnt - j) / 2;
+			int m_cnt = RTE_MIN(want, ENETC_RXBD_BUNDLE);
+
+			k = 0;
+			if (rte_pktmbuf_alloc_bulk(mb_pool, m, m_cnt))
+				return -1;
+		}
+
+		rx_swbd->buffer_addr = m[k];
+		rxbd->w.addr = (uint64_t)(uintptr_t)
+			       rx_swbd->buffer_addr->buf_iova +
+			       rx_swbd->buffer_addr->data_off;
+		/* clear 'R' as well */
+		rxbd->r.lstatus = 0;
+		k++;
+
+		/* Extension (odd) slot never owns a buffer. */
+		rx_swbd[1].buffer_addr = NULL;
+
+		rx_swbd += 2;
+		rxbd += 2;
+		i += 2;
+
+		if (unlikely(i == rx_ring->bd_count)) {
+			/* Ring wrap: flush partial/full group before reset. */
+			dcbf((void *)grp_start_rxbd);
+			i = 0;
+			rxbd = ENETC_RXBD(*rx_ring, i);
+			rx_swbd = &rx_ring->q_swbd[i];
+			grp_start_rxbd = rxbd;
+		} else if ((i & ENETC_BD_PER_CL_MASK) == 0) {
+			/* Completed a full 4-slot (2-descriptor) cache line. */
+			dcbf((void *)grp_start_rxbd);
+			grp_start_rxbd = rxbd;
+		}
+	}
+
+	/* Flush any remaining partial group at the end of the fill. */
+	if (j && (i & ENETC_BD_PER_CL_MASK) != 0)
+		dcbf((void *)grp_start_rxbd);
+
+	if (likely(j)) {
+		rx_ring->next_to_alloc = i;
+		rx_ring->next_to_use = i;
+		/*
+		 * Internal indices track 16B slots, but the HW consumer-index
+		 * register counts 32B descriptors, so program i / 2.
+		 */
+		enetc_wr_reg(rx_ring->rcir, i / 2);
+	}
+
+	return j;
+}
+
+/*
+ * RSC (LRO) clean. Same non-cache-coherent discipline as
+ * enetc_clean_rx_ring_cacheable but walks 32B descriptors (two 16B slots
+ * each); the extension half at slot i+1 carries the RSC coalesce count.
+ * RSC_FRAMES > 1 flags the cluster RTE_MBUF_F_RX_LRO. RSC always strips the
+ * FCS (RBaMR[CRC] = 0), so no CRC trim is needed.
+ */
+static int
+enetc_clean_rx_ring_rsc(struct enetc_bdr *rx_ring,
+		    struct rte_mbuf **rx_pkts,
+		    int work_limit)
+{
+	int rx_frm_cnt = 0;
+	int cleaned_cnt, i;
+	struct enetc_swbd *rx_swbd;
+	union enetc_rx_bd *rxbd, rxbd_temp;
+	struct enetc_rx_bd_ext *rxbd_ext;
+	struct rte_mbuf *first_seg = NULL, *cur_seg = NULL;
+	uint32_t bd_status;
+	uint8_t *data;
+	uint32_t j;
+	struct rte_mbuf *seg;
+	uint16_t data_len;
+	uint8_t rsc_frames;
+
+	/* next descriptor to process */
+	i = rx_ring->next_to_clean;
+	rxbd = ENETC_RXBD(*rx_ring, i);
+	cleaned_cnt = enetc_bd_unused(rx_ring);
+	rx_swbd = &rx_ring->q_swbd[i];
+
+	/*
+	 * Always invalidate the cache line that contains next_to_clean before
+	 * the first status read. On RSC rings a 64B line holds two 32B
+	 * descriptors. See enetc_clean_rx_ring_cacheable for the full rationale
+	 * on why dccivac (clean+invalidate) is used from EL0 instead of DC IVAC.
+	 */
+	dccivac((void *)ENETC_RXBD(*rx_ring,
+			  (i & ~(int)ENETC_BD_PER_CL_MASK)));
+
+	while (likely(rx_frm_cnt < work_limit)) {
+		/* Atomically snapshot the 16B writeback half of the BD. */
+#ifdef RTE_ARCH_32
+		rte_memcpy(&rxbd_temp, rxbd, 16);
+#else
+		__uint128_t *dst128 = (__uint128_t *)&rxbd_temp;
+		const __uint128_t *src128 = (const __uint128_t *)rxbd;
+		*dst128 = *src128;
+#endif
+		bd_status = rte_le_to_cpu_32(rxbd_temp.r.lstatus);
+
+		if (!(bd_status & ENETC_RXBD_LSTATUS_R))
+			break;
+		if (rxbd_temp.r.error)
+			rx_ring->ierrors++;
+
+		/*
+		 * Extension half (odd slot) carries the RSC coalesce count.
+		 * Invariant: an RSC ring is allocated with bd_count = nb_desc * 2
+		 * (always even), next_to_clean starts at 0, and i only ever
+		 * advances by 2 with a wrap at i == bd_count. So i is always the
+		 * even (writeback) slot of a 32B descriptor and never exceeds
+		 * bd_count - 2; i + 1 is therefore always the matching odd
+		 * extension slot and stays in bounds (never wraps past the ring).
+		 */
+		rxbd_ext = (struct enetc_rx_bd_ext *)
+			   ENETC_RXBD(*rx_ring, i + 1);
+		rsc_frames = ENETC4_RXBD_EXT_RSC_FRAMES(rte_le_to_cpu_32(rxbd_ext->rsc_frames));
+
+		seg = rx_swbd->buffer_addr;
+		data_len = rte_le_to_cpu_16(rxbd_temp.r.buf_len);
+		seg->data_len = data_len;
+		if (!first_seg) {
+			first_seg = seg;
+			cur_seg = seg;
+			first_seg->pkt_len = data_len;
+			first_seg->ol_flags = 0;
+			enetc_dev_rx_parse(first_seg,
+						rxbd_temp.r.parse_summary);
+			first_seg->hash.rss = rxbd_temp.r.rss_hash;
+			/* RSC_FRAMES > 1 means HW coalesced segments (LRO). */
+			if (rsc_frames > 1)
+				first_seg->ol_flags |= RTE_MBUF_F_RX_LRO;
+		} else {
+			first_seg->pkt_len += data_len;
+			first_seg->nb_segs++;
+			cur_seg->next = seg;
+			cur_seg = seg;
+		}
+
+		/* Invalidate packet data so the CPU reads HW-DMA'd payload. */
+		data = rte_pktmbuf_mtod(seg, void *);
+		for (j = 0; j < data_len; j += RTE_CACHE_LINE_SIZE)
+			dccivac(data + j);
+		/*
+		 * Cover the last byte of an unaligned buffer. Guard against a
+		 * zero-length BD so data_len - 1 does not step before the
+		 * payload start.
+		 */
+		if (likely(data_len))
+			dccivac(data + (data_len - 1));
+
+		if (bd_status & ENETC_RXBD_LSTATUS_F) {
+			seg->next = NULL;
+			ENETC_PMD_DP_DEBUG("RSC_FRAMES=%u pkt_len=%u nb_segs=%u",
+					   rsc_frames, first_seg->pkt_len,
+					   first_seg->nb_segs);
+			rx_pkts[rx_frm_cnt] = first_seg;
+			rx_frm_cnt++;
+			first_seg = NULL;
+		}
+
+		/* Two 16B slots per 32B RSC descriptor. */
+		cleaned_cnt += 2;
+		rx_swbd += 2;
+		i += 2;
+		if (unlikely(i == rx_ring->bd_count)) {
+			i = 0;
+			rx_swbd = &rx_ring->q_swbd[i];
+		}
+		rxbd = ENETC_RXBD(*rx_ring, i);
+
+		/*
+		 * Crossed a 4-slot (cache-line, two-descriptor) boundary:
+		 * invalidate the new group so subsequent status reads fetch
+		 * fresh DDR data written by HW.
+		 */
+		if ((i & ENETC_BD_PER_CL_MASK) == 0 &&
+		    likely(rx_frm_cnt < work_limit))
+			dccivac((void *)rxbd);
+	}
+
+	rx_ring->next_to_clean = i;
+	enetc_refill_rx_ring_rsc(rx_ring, ENETC_BD_ALIGN_DOWN(cleaned_cnt));
+
+	/*
+	 * Write-1-to-clear this ring's event in SIRXIDR. Without this the
+	 * interrupt-coalescing timer never re-arms and HW stops coalescing
+	 * after the first RSC frame (this PMD is poll-mode and never services
+	 * the interrupt). SIRXIDR is W1C, one bit per ring; RBaIDR is
+	 * read-only. Matches the Linux driver's enetc_wr_reg_hot(idr, BIT()).
+	 */
+	enetc4_wr_reg(rx_ring->rbidr, BIT(rx_ring->index));
+
+	return rx_frm_cnt;
+}
+
+uint16_t
+enetc_recv_pkts_rsc(void *rxq, struct rte_mbuf **rx_pkts,
+		uint16_t nb_pkts)
+{
+	struct enetc_bdr *rx_ring = (struct enetc_bdr *)rxq;
+
+	return enetc_clean_rx_ring_rsc(rx_ring, rx_pkts, nb_pkts);
+}
+
 uint16_t
 enetc_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts,
 		uint16_t nb_pkts)
-- 
2.25.1


  parent reply	other threads:[~2026-08-11  7:41 UTC|newest]

Thread overview: 110+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-06 11:28 [PATCH 00/14] net/enetc: add new features for ENETC4 VF on i.MX95 Gagandeep Singh
2026-08-06 11:28 ` [PATCH 01/14] net/enetc: add KEEP_CRC offload support for ENETC4 Gagandeep Singh
2026-08-06 11:28 ` [PATCH 02/14] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-06 11:28 ` [PATCH 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
2026-08-06 11:28 ` [PATCH 04/14] net/enetc: extend link speed code field to 8-bit for PF-to-VF message Gagandeep Singh
2026-08-06 11:28 ` [PATCH 05/14] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-06 11:28 ` [PATCH 06/14] net/enetc: support registers dump Gagandeep Singh
2026-08-06 11:28 ` [PATCH 07/14] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-06 11:28 ` [PATCH 08/14] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-06 11:28 ` [PATCH 09/14] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-06 11:28 ` [PATCH 10/14] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-06 11:28 ` [PATCH 11/14] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-06 11:28 ` [PATCH 12/14] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-06 11:28 ` [PATCH 13/14] net/enetc4: enable TX PAUSE via VF RX congestion mode Gagandeep Singh
2026-08-06 11:28 ` [PATCH 14/14] net/enetc4: add WRR Tx scheduler devarg for VF rings Gagandeep Singh
2026-08-06 17:00 ` [PATCH 00/14] net/enetc: add new features for ENETC4 VF on i.MX95 Stephen Hemminger
2026-08-07  3:48 ` [PATCH v2 00/14] net/enetc: add new features for ENETC4 VF on i.MX9 Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 01/14] net/enetc: add KEEP_CRC offload support for ENETC4 Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 02/14] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 04/14] net/enetc: extend link speed code field to 8-bit for PF-to-VF message Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 05/14] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 06/14] net/enetc: support registers dump Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 07/14] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 08/14] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 09/14] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 10/14] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 11/14] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 12/14] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 13/14] net/enetc4: enable TX PAUSE via VF RX congestion mode Gagandeep Singh
2026-08-07  3:48   ` [PATCH v2 14/14] net/enetc4: add WRR Tx scheduler devarg for VF rings Gagandeep Singh
2026-08-07  7:02   ` [PATCH v3 00/14] net/enetc: add new features for ENETC4 VF on i.MX9 Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 01/14] net/enetc: add KEEP_CRC offload support for ENETC4 Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 02/14] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 04/14] net/enetc: extend link speed code field to 8-bit for PF-to-VF message Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 05/14] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 06/14] net/enetc: support registers dump Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 07/14] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 08/14] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 09/14] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 10/14] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 11/14] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 12/14] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 13/14] net/enetc4: enable TX PAUSE via VF RX congestion mode Gagandeep Singh
2026-08-07  7:02     ` [PATCH v3 14/14] net/enetc4: add WRR Tx scheduler devarg for VF rings Gagandeep Singh
2026-08-07 11:26     ` [PATCH v4 00/14] net/enetc: add new features for ENETC4 on i.MX95 Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 01/14] net/enetc: add KEEP_CRC offload support for ENETC4 Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 02/14] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 04/14] net/enetc: extend link speed code field to 8-bit for PF-to-VF message Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 05/14] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 06/14] net/enetc: support registers dump Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 07/14] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 08/14] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 09/14] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 10/14] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 11/14] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 12/14] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 13/14] net/enetc4: enable TX PAUSE via VF RX congestion mode Gagandeep Singh
2026-08-07 11:26       ` [PATCH v4 14/14] net/enetc4: add WRR Tx scheduler devarg for VF rings Gagandeep Singh
2026-08-09 21:00       ` [PATCH v4 00/14] net/enetc: add new features for ENETC4 on i.MX95 Stephen Hemminger
2026-08-10 10:58         ` Gagandeep Singh
2026-08-10 10:48       ` [PATCH v5 " Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 01/14] net/enetc: add keep-CRC Rx offload for ENETC4 Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 02/14] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 04/14] net/enetc: extend PF-VF link speed field to 8 bits Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 05/14] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 06/14] net/enetc: support registers dump Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 07/14] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 08/14] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 09/14] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 10/14] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 11/14] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 12/14] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 13/14] net/enetc4: enable Tx PAUSE via VF Rx congestion mode Gagandeep Singh
2026-08-10 10:48         ` [PATCH v5 14/14] net/enetc4: add WRR Tx scheduler devarg for VF rings Gagandeep Singh
2026-08-10 15:25         ` [PATCH v5 00/14] net/enetc: add new features for ENETC4 on i.MX95 Stephen Hemminger
2026-08-10 15:40         ` Stephen Hemminger
2026-08-11  7:40         ` [PATCH v6 00/13] " Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 01/13] net/enetc: add keep-CRC Rx offload for ENETC4 Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 02/13] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-11  7:40           ` Gagandeep Singh [this message]
2026-08-11  7:40           ` [PATCH v6 04/13] net/enetc: extend PF-VF link speed field to 8 bits Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 05/13] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 06/13] net/enetc: support registers dump Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 07/13] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 08/13] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 09/13] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 10/13] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 11/13] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 12/13] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-11  7:40           ` [PATCH v6 13/13] net/enetc4: enable Tx PAUSE via VF Rx congestion mode Gagandeep Singh
2026-08-11  7:47           ` [PATCH v7 00/14] net/enetc: add new features for ENETC4 on i.MX95 Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 01/14] net/enetc: add keep-CRC Rx offload for ENETC4 Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 02/14] net/enetc: add TSO support for ENETC4 VF Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 04/14] net/enetc: extend PF-VF link speed field to 8 bits Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 05/14] net/enetc: support firmware version get for VF Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 06/14] net/enetc: support registers dump Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 07/14] net/enetc: support ethtool ring parameters Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 08/14] net/enetc: refresh link speed on VF link-up interrupt Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 09/14] net/enetc: support stats reset for VF Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 10/14] net/enetc4: add per-queue Rx interrupt support " Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 11/14] net/enetc4: add SI-based port VLAN insertion and removal Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 12/14] net/enetc4: update VF link status to bitmask encoding Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 13/14] net/enetc4: enable Tx PAUSE via VF Rx congestion mode Gagandeep Singh
2026-08-11  7:47             ` [PATCH v7 14/14] net/enetc4: add WRR Tx scheduler devarg for VF rings Gagandeep Singh
2026-08-11 15:39             ` [PATCH v7 00/14] net/enetc: add new features for ENETC4 on i.MX95 Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260811074032.3646324-4-g.singh@nxp.com \
    --to=g.singh@nxp.com \
    --cc=dev@dpdk.org \
    --cc=hemant.agrawal@nxp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox