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

