[PATCH v3 01/14] net/enetc: add KEEP_CRC offload support for ENETC4

Gagandeep Singh <[email protected]>
Newsgroups org.dpdk.dev
Message-ID <[email protected]>
The legacy ENETC (LS1028A) driver already supports the
RTE_ETH_RX_OFFLOAD_KEEP_CRC offload, but ENETC4 (i.MX95 NETC) did not.

Add KEEP_CRC support for ENETC4 (both PF and VF):

- Advertise RTE_ETH_RX_OFFLOAD_KEEP_CRC in the supported Rx offloads
  for the ENETC4 PF and VF. The VF reuses the PF Rx queue setup, so the
  HW configuration and datapath handling apply to both.
- Configure the per-ring RBaMR[CRC] bit in the Rx queue setup so that
  HW preserves the Ethernet FCS in the receive buffer when the offload
  is requested (0 = FCS removed, 1 = FCS preserved).
- Follow the DPDK convention used by the legacy ENETC and ixgbe drivers:
  set crc_len to RTE_ETHER_CRC_LEN when KEEP_CRC is enabled and have the
  datapath subtract crc_len from pkt_len/data_len. ENETC and ENETC4 share
  the same datapath (enetc_rxtx.c), so the semantics stay consistent.
- Handle the scatter-gather boundary case where the 4-byte FCS straddles
  the last two segments: drop the trailing segment, decrement nb_segs and
  trim the carry-over from its predecessor.

Update the enetc4 feature matrix to list CRC offload.

Signed-off-by: Gagandeep Singh <[email protected]>
---
 doc/guides/nics/features/enetc4.ini    |  1 +
 doc/guides/rel_notes/release_26_11.rst |  6 ++++
 drivers/net/enetc/base/enetc4_hw.h     |  4 +++
 drivers/net/enetc/enetc4_ethdev.c      | 31 ++++++++++++++++++--
 drivers/net/enetc/enetc4_vf.c          |  1 +
 drivers/net/enetc/enetc_rxtx.c         | 39 +++++++++++++++++++++++---
 6 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/doc/guides/nics/features/enetc4.ini b/doc/guides/nics/features/enetc4.ini
index 698140e30b..91b18d979e 100644
--- a/doc/guides/nics/features/enetc4.ini
+++ b/doc/guides/nics/features/enetc4.ini
@@ -16,6 +16,7 @@ Packet type parsing  = Y
 Basic stats          = Y
 L3 checksum offload  = Y
 L4 checksum offload  = Y
+CRC offload          = Y
 Queue start/stop     = Y
 Scattered Rx         = Y
 Linux                = Y
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index c8cc86295d..3678dd6894 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -56,6 +56,12 @@ New Features
      =======================================================
 
 
+* **Updated NXP ENETC4 PMD.**
+
+  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.
+
 Removed Items
 -------------
 
diff --git a/drivers/net/enetc/base/enetc4_hw.h b/drivers/net/enetc/base/enetc4_hw.h
index 9685e7e1e5..0105549857 100644
--- a/drivers/net/enetc/base/enetc4_hw.h
+++ b/drivers/net/enetc/base/enetc4_hw.h
@@ -68,6 +68,10 @@ struct enetc_msg_swbd {
 #define PM_CMD_CFG_TX_EN		BIT(0)
 #define PM_CMD_CFG_RX_EN		BIT(1)
 
+/* RBaMR[CRC]: 0 = FCS removed, 1 = FCS preserved (KEEP_CRC) */
+#define ENETC4_RBMR_CRC			BIT(8)
+
+
 /* i.MX95 supports jumbo frame, but it is recommended to set the max frame
  * size to 2000 bytes.
  */
diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c
index 2ddd63dafb..1a8056580c 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -11,6 +11,19 @@
 #include "enetc_logs.h"
 #include "enetc.h"
 
+/* Supported Rx offloads */
+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;
+
+/* Supported Tx offloads */
+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;
+
 #define ENETC4_TXQ_PRIORITIES	"enetc4_txq_prior"
 #define ENETC4_NC_MEMORY	"nc"
 
@@ -536,6 +549,8 @@ 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 rx_enable;
+	bool keep_crc;
 
 	PMD_INIT_FUNC_TRACE();
 	if (nb_rx_desc > MAX_BD_COUNT)
@@ -549,6 +564,9 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
 	}
 
 	rx_ring->index = rx_queue_id;
+	keep_crc = !!(rx_offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC);
+	rx_ring->crc_len = (uint8_t)(keep_crc ? RTE_ETHER_CRC_LEN : 0);
+
 	err = enetc4_alloc_rxbdr(rx_ring, nb_rx_desc);
 	if (err)
 		goto fail;
@@ -562,19 +580,25 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
 	data->rx_queues[rx_queue_id] = rx_ring;
 	rx_ring->rx_deferred_start = rx_conf->rx_deferred_start;
 
+	if (keep_crc)
+		rx_enable |= ENETC4_RBMR_CRC;
+	else
+		rx_enable &= ~ENETC4_RBMR_CRC;
+
 	if (!rx_conf->rx_deferred_start) {
 		/* enable ring */
+		rx_enable |= ENETC_RBMR_EN;
 		enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index, ENETC_RBMR,
-			       ENETC_RBMR_EN);
+			       rx_enable);
 		dev->data->rx_queue_state[rx_ring->index] =
 			       RTE_ETH_QUEUE_STATE_STARTED;
 	} else {
+		enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index, ENETC_RBMR,
+			       rx_enable);
 		dev->data->rx_queue_state[rx_ring->index] =
 			       RTE_ETH_QUEUE_STATE_STOPPED;
 	}
 
-	rx_ring->crc_len = (uint8_t)((rx_offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC) ?
-				     RTE_ETHER_CRC_LEN : 0);
 	return 0;
 fail:
 	rte_free(rx_ring);
@@ -582,6 +606,7 @@ 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 ef5f1e6d66..83a1e4931f 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -52,6 +52,7 @@ static uint64_t dev_rx_offloads_sup =
 	RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
 	RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
 	RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
+	RTE_ETH_RX_OFFLOAD_KEEP_CRC |
 	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 8678bafece..e3bef607dd 100644
--- a/drivers/net/enetc/enetc_rxtx.c
+++ b/drivers/net/enetc/enetc_rxtx.c
@@ -530,6 +530,28 @@ enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
 	return rx_frm_cnt;
 }
 
+/*
+ * Trim the Ethernet FCS from a received cluster when HW CRC strip is
+ * disabled. pkt_len is reduced by crc_len. If the FCS straddles the last
+ * two segments (last seg holds fewer bytes than crc_len), drop the trailing
+ * segment and trim the carry-over from its predecessor. prev_seg is the
+ * segment preceding last_seg in the chain (the caller already tracks it).
+ */
+static inline void
+enetc_rx_crc_trim(struct rte_mbuf *first_seg, struct rte_mbuf *prev_seg,
+		  struct rte_mbuf *last_seg, uint16_t crc_len)
+{
+	first_seg->pkt_len -= crc_len;
+	if (likely(last_seg->data_len > crc_len)) {
+		last_seg->data_len -= crc_len;
+	} else if (prev_seg != NULL) {
+		first_seg->nb_segs--;
+		prev_seg->data_len -= crc_len - last_seg->data_len;
+		prev_seg->next = NULL;
+		rte_pktmbuf_free_seg(last_seg);
+	}
+}
+
 static int
 enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring,
 		    struct rte_mbuf **rx_pkts,
@@ -539,7 +561,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, *cur_seg;
+	struct rte_mbuf *first_seg = NULL, *cur_seg = NULL;
 	uint32_t bd_status;
 	uint8_t *data;
 	uint32_t j;
@@ -572,6 +594,7 @@ enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring,
 		if (!first_seg) {
 			first_seg = seg;
 			cur_seg = seg;
+			prev_seg = NULL;
 			first_seg->pkt_len = data_len;
 			enetc_dev_rx_parse(first_seg, rxbd_temp.r.parse_summary);
 			first_seg->hash.rss = rxbd_temp.r.rss_hash;
@@ -579,6 +602,7 @@ enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring,
 			first_seg->pkt_len += data_len;
 			first_seg->nb_segs++;
 			cur_seg->next = seg;
+			prev_seg = cur_seg;
 			cur_seg = seg;
 		}
 
@@ -590,7 +614,9 @@ enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring,
 
 		if (bd_status & ENETC_RXBD_LSTATUS_F) {
 			seg->next = NULL;
-			first_seg->pkt_len -= rx_ring->crc_len;
+			if (rx_ring->crc_len)
+				enetc_rx_crc_trim(first_seg, prev_seg, seg,
+						  rx_ring->crc_len);
 			rx_pkts[rx_frm_cnt] = first_seg;
 			rx_frm_cnt++;
 			first_seg = NULL;
@@ -760,7 +786,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, *cur_seg;
+	struct rte_mbuf *first_seg = NULL, *cur_seg = NULL;
 	uint32_t bd_status;
 	uint8_t *data;
 	uint32_t j;
@@ -815,6 +841,7 @@ enetc_clean_rx_ring_cacheable(struct enetc_bdr *rx_ring,
 		if (!first_seg) {
 			first_seg = seg;
 			cur_seg = seg;
+			prev_seg = NULL;
 			first_seg->pkt_len = data_len;
 			enetc_dev_rx_parse(first_seg,
 					   rxbd->r.parse_summary);
@@ -823,6 +850,7 @@ enetc_clean_rx_ring_cacheable(struct enetc_bdr *rx_ring,
 			first_seg->pkt_len += data_len;
 			first_seg->nb_segs++;
 			cur_seg->next = seg;
+			prev_seg = cur_seg;
 			cur_seg = seg;
 		}
 
@@ -838,7 +866,10 @@ enetc_clean_rx_ring_cacheable(struct enetc_bdr *rx_ring,
 
 		if (bd_status & ENETC_RXBD_LSTATUS_F) {
 			seg->next = NULL;
-			first_seg->pkt_len -= rx_ring->crc_len;
+			if (rx_ring->crc_len)
+				enetc_rx_crc_trim(first_seg, prev_seg, seg,
+						  rx_ring->crc_len);
+
 			rx_pkts[rx_frm_cnt] = first_seg;
 			rx_frm_cnt++;
 			first_seg = NULL;
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.