From: Gagandeep Singh <g.singh@nxp.com>
To: dev@dpdk.org
Cc: hemant.agrawal@nxp.com, Gagandeep Singh <g.singh@nxp.com>
Subject: [PATCH v4 03/14] net/enetc: add RSC (hardware LRO) support for ENETC4
Date: Fri, 7 Aug 2026 16:56:12 +0530 [thread overview]
Message-ID: <20260807112623.1402493-4-g.singh@nxp.com> (raw)
In-Reply-To: <20260807112623.1402493-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 | 74 ++++++++
drivers/net/enetc/enetc.h | 5 +
drivers/net/enetc/enetc4_ethdev.c | 102 ++++++++++-
drivers/net/enetc/enetc4_vf.c | 1 +
drivers/net/enetc/enetc_rxtx.c | 239 ++++++++++++++++++++++++-
8 files changed, 418 insertions(+), 9 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 64c1a5e750..8ad8f169d2 100644
--- a/drivers/net/enetc/base/enetc4_hw.h
+++ b/drivers/net/enetc/base/enetc4_hw.h
@@ -103,7 +103,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 db349e051b..67f8ce1919 100644
--- a/drivers/net/enetc/enetc.h
+++ b/drivers/net/enetc/enetc.h
@@ -101,6 +101,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 {
@@ -321,12 +323,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 897e12e21f..7f95171b6d 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -16,7 +16,8 @@ static uint64_t dev_rx_offloads_sup =
RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
- 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 =
@@ -314,6 +315,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;
@@ -520,22 +523,29 @@ 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;
- 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;
@@ -558,13 +568,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);
@@ -587,7 +614,9 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
ENETC_DEV_PRIVATE(data->dev_private);
uint64_t rx_offloads = data->dev_conf.rxmode.offloads;
uint32_t rx_enable;
+ uint32_t rsc_size;
bool keep_crc;
+ bool rsc_enable;
PMD_INIT_FUNC_TRACE();
if (nb_rx_desc > MAX_BD_COUNT)
@@ -604,6 +633,23 @@ 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;
+ }
+ 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;
@@ -622,6 +668,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;
@@ -643,7 +732,6 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
return err;
}
-
void
enetc4_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
{
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 f19f32eace..3f2e85b871 100644
--- a/drivers/net/enetc/enetc_rxtx.c
+++ b/drivers/net/enetc/enetc_rxtx.c
@@ -816,7 +816,7 @@ enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring,
int cleaned_cnt, i;
struct enetc_swbd *rx_swbd;
union enetc_rx_bd *rxbd, rxbd_temp;
- struct rte_mbuf *first_seg = NULL, *cur_seg = NULL;
+ struct rte_mbuf *first_seg = NULL, *cur_seg = NULL, *prev_seg = NULL;
uint32_t bd_status;
uint8_t *data;
uint32_t j;
@@ -905,6 +905,241 @@ 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)
@@ -1041,7 +1276,7 @@ enetc_clean_rx_ring_cacheable(struct enetc_bdr *rx_ring,
int cleaned_cnt, i;
struct enetc_swbd *rx_swbd;
union enetc_rx_bd *rxbd;
- struct rte_mbuf *first_seg = NULL, *cur_seg = NULL;
+ struct rte_mbuf *first_seg = NULL, *cur_seg = NULL, *prev_seg = NULL;
uint32_t bd_status;
uint8_t *data;
uint32_t j;
--
2.25.1
next prev parent reply other threads:[~2026-08-07 11:26 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 ` Gagandeep Singh [this message]
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 ` [PATCH v6 03/13] net/enetc: add RSC (hardware LRO) support for ENETC4 Gagandeep Singh
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=20260807112623.1402493-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