* [PATCH 00/10] NXP ENETC driver related changes
@ 2026-06-19 18:44 Gagandeep Singh
2026-06-19 18:44 ` [PATCH 01/10] net/enetc: fix TX BD structure Gagandeep Singh
` (11 more replies)
0 siblings, 12 replies; 24+ messages in thread
From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal
ENETC driver related changes series
Gagandeep Singh (8):
net/enetc: fix TX BD structure
net/enetc: fix TX BDs flag overwrite issue
net/enetc: fix queue initialization
net/enetc: support ESP packet type in packet parsing
net/enetc: update random MAC generation code
net/enetc: add option to disable VSI messaging
net/enetc: add devargs to control VSI-PSI timeout and delay
net/enetc4: add cacheable BD ring support with SW cache maintenance
Vanshika Shukla (2):
net/enetc: support scatter-gather
net/enetc: set user configurable priority to TX rings
drivers/net/enetc/base/enetc_hw.h | 13 +-
drivers/net/enetc/enetc.h | 28 +-
drivers/net/enetc/enetc4_ethdev.c | 123 +++++++--
drivers/net/enetc/enetc4_vf.c | 159 ++++++++++--
drivers/net/enetc/enetc_ethdev.c | 26 +-
drivers/net/enetc/enetc_rxtx.c | 411 ++++++++++++++++++++++++++----
6 files changed, 649 insertions(+), 111 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 01/10] net/enetc: fix TX BD structure 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 02/10] net/enetc: fix TX BDs flag overwrite issue Gagandeep Singh ` (10 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, stable The flags field in struct enetc_tx_bd was declared as uint16_t but ENETC4 TX BDs only use an 8-bit flags byte. Fix the type to uint8_t to match the hardware descriptor layout. Fixes: 696fa399d797 ("net/enetc: add PMD with basic operations") Cc: stable@dpdk.org Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/base/enetc_hw.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h index 173d677..19efadd 100644 --- a/drivers/net/enetc/base/enetc_hw.h +++ b/drivers/net/enetc/base/enetc_hw.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2024 NXP + * Copyright 2018-2026 NXP */ #ifndef _ENETC_HW_H_ @@ -198,8 +198,7 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_TX_ADDR(txq, addr) ((void *)((txq)->enetc_txbdr + (addr))) -#define ENETC_TXBD_FLAGS_IE BIT(13) -#define ENETC_TXBD_FLAGS_F BIT(15) +#define ENETC_TXBD_FLAGS_F BIT(7) /* ENETC Parsed values (Little Endian) */ #define ENETC_PARSE_ERROR 0x8000 @@ -262,7 +261,7 @@ struct enetc_tx_bd { uint8_t l3t:1; uint8_t resv:5; uint8_t l4t:3; - uint16_t flags; + uint8_t flags; };/* default layout */ uint32_t txstart; uint32_t lstatus; -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 02/10] net/enetc: fix TX BDs flag overwrite issue 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh 2026-06-19 18:44 ` [PATCH 01/10] net/enetc: fix TX BD structure Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 03/10] net/enetc: fix queue initialization Gagandeep Singh ` (9 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, stable Zero the flags field before setting offload bits and set the frame-last flag (F) after all descriptor fields are written. This prevents stale flag bits from a previous packet corrupting the current descriptor. Fixes: 72f491f1e53c ("net/enetc: optimize ENETC4 data path") Cc: stable@dpdk.org Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc_rxtx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index a2b8153..b44e6f3 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2024 NXP + * Copyright 2018-2026 NXP */ #include <stdbool.h> @@ -172,7 +172,7 @@ enetc_xmit_pkts_nc(void *tx_queue, dcbf(data + j); txbd = ENETC_TXBD(*tx_ring, i); - txbd->flags = rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_F); + txbd->flags = 0; if (tx_ring->q_swbd[i].buffer_addr->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK) enetc4_tx_offload_checksum(tx_ring->q_swbd[i].buffer_addr, txbd); @@ -182,6 +182,7 @@ enetc_xmit_pkts_nc(void *tx_queue, txbd->addr = (uint64_t)(uintptr_t) rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova + tx_swbd->buffer_addr->data_off); + txbd->flags |= rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_F); i++; start++; if (unlikely(i == tx_ring->bd_count)) -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 03/10] net/enetc: fix queue initialization 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh 2026-06-19 18:44 ` [PATCH 01/10] net/enetc: fix TX BD structure Gagandeep Singh 2026-06-19 18:44 ` [PATCH 02/10] net/enetc: fix TX BDs flag overwrite issue Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 04/10] net/enetc: support ESP packet type in packet parsing Gagandeep Singh ` (8 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, stable Hardware can misbehave if the user tries to reset the consumer and producer indexes without resetting the ring. This patch adds the ring reset step before resetting the indexes. Fixes: 6c9c5aadc0e0 ("net/enetc: support ENETC4 queue API") Cc: stable@dpdk.org Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc4_ethdev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index 78eba70..154fc09 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2024 NXP + * Copyright 2024-2026 NXP */ #include <stdbool.h> @@ -279,6 +279,7 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev, const struct rte_eth_txconf *tx_conf) { int err; + uint32_t tx_data; struct enetc_bdr *tx_ring; struct rte_eth_dev_data *data = dev->data; struct enetc_eth_adapter *priv = @@ -301,6 +302,10 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev, goto fail; tx_ring->ndev = dev; + /* reset queue */ + tx_data = enetc4_txbdr_rd(&priv->hw.hw, tx_ring->index, ENETC_TBMR); + tx_data &= ~ENETC_TBMR_EN; + enetc4_txbdr_wr(&priv->hw.hw, tx_ring->index, ENETC_TBMR, tx_data); enetc4_setup_txbdr(&priv->hw.hw, tx_ring); data->tx_queues[queue_idx] = tx_ring; tx_ring->tx_deferred_start = tx_conf->tx_deferred_start; @@ -427,6 +432,7 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev, struct rte_mempool *mb_pool) { int err = 0; + uint32_t rx_enable; struct enetc_bdr *rx_ring; struct rte_eth_dev_data *data = dev->data; struct enetc_eth_adapter *adapter = @@ -450,6 +456,10 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev, goto fail; rx_ring->ndev = dev; + /* reset queue */ + rx_enable = enetc4_rxbdr_rd(&adapter->hw.hw, rx_ring->index, ENETC_RBMR); + rx_enable &= ~ENETC_RBMR_EN; + enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index, ENETC_RBMR, rx_enable); enetc4_setup_rxbdr(&adapter->hw.hw, rx_ring, mb_pool); data->rx_queues[rx_queue_id] = rx_ring; rx_ring->rx_deferred_start = rx_conf->rx_deferred_start; -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 04/10] net/enetc: support ESP packet type in packet parsing 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (2 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 03/10] net/enetc: fix queue initialization Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 05/10] net/enetc: update random MAC generation code Gagandeep Singh ` (7 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal Add ESP (Encapsulating Security Payload) packet type definitions and handling to the RX packet parsing path. Also update the supported ptypes array to advertise ESP tunnel type support. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/base/enetc_hw.h | 4 ++++ drivers/net/enetc/enetc_ethdev.c | 4 +++- drivers/net/enetc/enetc_rxtx.c | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h index 19efadd..f79c950 100644 --- a/drivers/net/enetc/base/enetc_hw.h +++ b/drivers/net/enetc/base/enetc_hw.h @@ -226,6 +226,10 @@ enum enetc_bdr_type {TX, RX}; (0x0003 | ENETC_PKT_TYPE_IPV4) #define ENETC_PKT_TYPE_IPV6_ICMP \ (0x0003 | ENETC_PKT_TYPE_IPV6) +#define ENETC_PKT_TYPE_IPV4_ESP \ + (0x0005 | ENETC_PKT_TYPE_IPV4) +#define ENETC_PKT_TYPE_IPV6_ESP \ + (0x0005 | ENETC_PKT_TYPE_IPV6) /* PCI device info */ struct enetc_hw { diff --git a/drivers/net/enetc/enetc_ethdev.c b/drivers/net/enetc/enetc_ethdev.c index f41f3c1..407179f 100644 --- a/drivers/net/enetc/enetc_ethdev.c +++ b/drivers/net/enetc/enetc_ethdev.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2024 NXP + * Copyright 2018-2026 NXP */ #include <stdbool.h> @@ -95,6 +95,8 @@ enetc_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP, + RTE_PTYPE_TUNNEL_ESP, + RTE_PTYPE_UNKNOWN, }; *no_of_elements = RTE_DIM(ptypes); diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index b44e6f3..c87349f 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -370,6 +370,16 @@ enetc_dev_rx_parse(struct rte_mbuf *m, uint16_t parse_results) RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_UDP; return; + case ENETC_PKT_TYPE_IPV4_ESP: + m->packet_type = RTE_PTYPE_L2_ETHER | + RTE_PTYPE_L3_IPV4 | + RTE_PTYPE_TUNNEL_ESP; + return; + case ENETC_PKT_TYPE_IPV6_ESP: + m->packet_type = RTE_PTYPE_L2_ETHER | + RTE_PTYPE_L3_IPV6 | + RTE_PTYPE_TUNNEL_ESP; + return; case ENETC_PKT_TYPE_IPV4_SCTP: m->packet_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4 | -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 05/10] net/enetc: update random MAC generation code 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (3 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 04/10] net/enetc: support ESP packet type in packet parsing Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 06/10] net/enetc: support scatter-gather Gagandeep Singh ` (6 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal Use rte_eth_random_addr() instead of manual rte_rand() based MAC generation. Also handle VF path by writing to ENETC_SIPMAR0/1 instead of ENETC_PSIPMAR0/1 when running as a VF. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc_ethdev.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/enetc/enetc_ethdev.c b/drivers/net/enetc/enetc_ethdev.c index 407179f..427da87 100644 --- a/drivers/net/enetc/enetc_ethdev.c +++ b/drivers/net/enetc/enetc_ethdev.c @@ -196,20 +196,18 @@ enetc_hardware_init(struct enetc_eth_hw *hw) } if ((high_mac | low_mac) == 0) { - char *first_byte; - ENETC_PMD_NOTICE("MAC is not available for this SI, " "set random MAC"); - mac = (uint32_t *)hw->mac.addr; - *mac = (uint32_t)rte_rand(); - first_byte = (char *)mac; - *first_byte &= 0xfe; /* clear multicast bit */ - *first_byte |= 0x02; /* set local assignment bit (IEEE802) */ - - enetc_port_wr(enetc_hw, ENETC_PSIPMAR0(0), *mac); - mac++; - *mac = (uint16_t)rte_rand(); - enetc_port_wr(enetc_hw, ENETC_PSIPMAR1(0), *mac); + rte_eth_random_addr(hw->mac.addr); + high_mac = *(uint32_t *)hw->mac.addr; + low_mac = *(uint16_t *)(hw->mac.addr + 4); + if (hw->device_id == ENETC_DEV_ID_VF) { + enetc_wr(enetc_hw, ENETC_SIPMAR0, high_mac); + enetc_wr(enetc_hw, ENETC_SIPMAR1, low_mac); + } else { + enetc_port_wr(enetc_hw, ENETC_PSIPMAR0(0), high_mac); + enetc_port_wr(enetc_hw, ENETC_PSIPMAR1(0), low_mac); + } enetc_print_ethaddr("New address: ", (const struct rte_ether_addr *)hw->mac.addr); } -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 06/10] net/enetc: support scatter-gather 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (4 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 05/10] net/enetc: update random MAC generation code Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 07/10] net/enetc: add option to disable VSI messaging Gagandeep Singh ` (5 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Vanshika Shukla From: Vanshika Shukla <vanshika.shukla@nxp.com> Add scatter-gather support for ENETC4 PMD: - Add ENETC_RXBD_LSTATUS_R/F bits for RX BD status - Add ENETC4_MAX_SEGS (63) for max segments per TX packet - Update enetc4_vf_dev_infos_get to fill nb_seg_max, offloads, max queues and packet length - Extend enetc_xmit_pkts_nc to handle multi-segment mbufs - Extend enetc_clean_rx_ring_nc to chain scatter-gather segments using LSTATUS_R/F bits Signed-off-by: Vanshika Shukla <vanshika.shukla@nxp.com> --- drivers/net/enetc/base/enetc_hw.h | 2 + drivers/net/enetc/enetc.h | 4 +- drivers/net/enetc/enetc4_vf.c | 46 ++++++++--- drivers/net/enetc/enetc_rxtx.c | 124 +++++++++++++++++++----------- 4 files changed, 119 insertions(+), 57 deletions(-) diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h index f79c950..6e96562 100644 --- a/drivers/net/enetc/base/enetc_hw.h +++ b/drivers/net/enetc/base/enetc_hw.h @@ -230,6 +230,8 @@ enum enetc_bdr_type {TX, RX}; (0x0005 | ENETC_PKT_TYPE_IPV4) #define ENETC_PKT_TYPE_IPV6_ESP \ (0x0005 | ENETC_PKT_TYPE_IPV6) +#define ENETC_RXBD_LSTATUS_R BIT(30) +#define ENETC_RXBD_LSTATUS_F BIT(31) /* PCI device info */ struct enetc_hw { diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 4d99b5b..439d2d6 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2019,2024 NXP + * Copyright 2018-2019,2024-2026 NXP */ #ifndef _ENETC_H_ @@ -28,6 +28,8 @@ #define MIN_BD_COUNT 32 /* BD ALIGN */ #define BD_ALIGN 8 +/* Max segments per ENETC4 TX packet (scatter-gather) */ +#define ENETC4_MAX_SEGS 63 /* minimum frame size supported */ #define ENETC_MAC_MINFRM_SIZE 68 diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index bec7128..9dc4e1d 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2024 NXP + * Copyright 2024-2026 NXP */ #include <stdbool.h> @@ -18,8 +18,19 @@ uint16_t enetc_crc_table[ENETC_CRC_TABLE_SIZE]; bool enetc_crc_gen; /* Supported Rx offloads */ -static uint64_t dev_vf_rx_offloads_sup = - RTE_ETH_RX_OFFLOAD_VLAN_FILTER; +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_VLAN_FILTER | + RTE_ETH_RX_OFFLOAD_SCATTER; + +/* 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 | + RTE_ETH_TX_OFFLOAD_MULTI_SEGS; static void enetc_gen_crc_table(void) @@ -61,21 +72,38 @@ static int enetc4_vf_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { - int ret = 0; + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); PMD_INIT_FUNC_TRACE(); - ret = enetc4_dev_infos_get(dev, dev_info); - if (ret) - return ret; - + dev_info->rx_desc_lim = (struct rte_eth_desc_lim) { + .nb_max = MAX_BD_COUNT, + .nb_min = MIN_BD_COUNT, + .nb_align = BD_ALIGN, + .nb_seg_max = ENETC4_MAX_SEGS, + .nb_mtu_seg_max = ENETC4_MAX_SEGS, + }; + dev_info->tx_desc_lim = (struct rte_eth_desc_lim) { + .nb_max = MAX_BD_COUNT, + .nb_min = MIN_BD_COUNT, + .nb_align = BD_ALIGN, + .nb_seg_max = ENETC4_MAX_SEGS, + .nb_mtu_seg_max = ENETC4_MAX_SEGS, + }; + dev_info->max_rx_queues = hw->max_rx_queues; + dev_info->max_tx_queues = hw->max_tx_queues; + dev_info->max_rx_pktlen = ENETC4_MAC_MAXFRM_SIZE; dev_info->max_mtu = dev_info->max_rx_pktlen - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN); dev_info->max_mac_addrs = ENETC4_MAC_ENTRIES; - dev_info->rx_offload_capa |= dev_vf_rx_offloads_sup; + dev_info->rx_offload_capa = dev_rx_offloads_sup; + dev_info->tx_offload_capa = dev_tx_offloads_sup; + dev_info->flow_type_rss_offloads = ENETC_RSS_OFFLOAD_ALL; return 0; } + int enetc4_vf_dev_stop(struct rte_eth_dev *dev __rte_unused) { diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index c87349f..a37c835 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -149,54 +149,64 @@ enetc_xmit_pkts_nc(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) { - struct enetc_swbd *tx_swbd; - int i, start, bds_to_use; - struct enetc_tx_bd *txbd; struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue; - unsigned int buflen, j; + int i, start, bds_to_use, bd_count; + struct enetc_tx_bd *txbd; + struct rte_mbuf *seg; + uint16_t seg_len, segs_per_pkt; + bool is_first_seg; + unsigned int j; uint8_t *data; i = tx_ring->next_to_use; - bds_to_use = enetc_bd_unused(tx_ring); - if (bds_to_use < nb_pkts) - nb_pkts = bds_to_use; - + bd_count = tx_ring->bd_count; start = 0; - while (nb_pkts--) { - tx_ring->q_swbd[i].buffer_addr = tx_pkts[start]; - buflen = rte_pktmbuf_pkt_len(tx_ring->q_swbd[i].buffer_addr); - data = rte_pktmbuf_mtod(tx_ring->q_swbd[i].buffer_addr, void *); - for (j = 0; j <= buflen; j += RTE_CACHE_LINE_SIZE) - dcbf(data + j); + while (start < nb_pkts) { + seg = tx_pkts[start]; + segs_per_pkt = seg->nb_segs; - txbd = ENETC_TXBD(*tx_ring, i); - txbd->flags = 0; - if (tx_ring->q_swbd[i].buffer_addr->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK) - enetc4_tx_offload_checksum(tx_ring->q_swbd[i].buffer_addr, txbd); + if (bds_to_use < segs_per_pkt) + break; - tx_swbd = &tx_ring->q_swbd[i]; - txbd->frm_len = buflen; - txbd->buf_len = txbd->frm_len; - txbd->addr = (uint64_t)(uintptr_t) - rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova + - tx_swbd->buffer_addr->data_off); + 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 *); + + /* Flush payload to PoC so HW DMA reads the correct data. */ + for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE) + dcbf(data + j); + /* Cover the last byte of an unaligned buffer. */ + 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 = tx_pkts[start]; + 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; + } + + /* Set the frame-last flag on the final BD of this packet. */ txbd->flags |= rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_F); - i++; start++; - if (unlikely(i == tx_ring->bd_count)) - i = 0; } - /* we're only cleaning up the Tx ring here, on the assumption that - * software is slower than hardware and hardware completed sending - * older frames out by now. - * We're also cleaning up the ring before kicking off Tx for the new - * batch to minimize chances of contention on the Tx ring - */ enetc_clean_tx_ring(tx_ring); - tx_ring->next_to_use = i; enetc_wr_reg(tx_ring->tcir, i); return start; @@ -501,38 +511,59 @@ 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; uint32_t bd_status; uint8_t *data; uint32_t j; + struct rte_mbuf *seg; + uint16_t data_len; /* next descriptor to process */ i = rx_ring->next_to_clean; - /* next descriptor to process */ rxbd = ENETC_RXBD(*rx_ring, i); - cleaned_cnt = enetc_bd_unused(rx_ring); rx_swbd = &rx_ring->q_swbd[i]; while (likely(rx_frm_cnt < work_limit)) { rxbd_temp = *rxbd; bd_status = rte_le_to_cpu_32(rxbd_temp.r.lstatus); - if (!bd_status) + /* LSTATUS_R indicates this BD has been written by HW */ + if (!(bd_status & ENETC_RXBD_LSTATUS_R)) break; if (rxbd_temp.r.error) rx_ring->ierrors++; - rx_swbd->buffer_addr->pkt_len = rxbd_temp.r.buf_len - - rx_ring->crc_len; - rx_swbd->buffer_addr->data_len = rx_swbd->buffer_addr->pkt_len; - rx_swbd->buffer_addr->hash.rss = rxbd_temp.r.rss_hash; - enetc_dev_rx_parse(rx_swbd->buffer_addr, - rxbd_temp.r.parse_summary); + 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; + enetc_dev_rx_parse(first_seg, rxbd_temp.r.parse_summary); + first_seg->hash.rss = rxbd_temp.r.rss_hash; + } else { + first_seg->pkt_len += data_len; + first_seg->nb_segs++; + cur_seg->next = seg; + cur_seg = seg; + } - data = rte_pktmbuf_mtod(rx_swbd->buffer_addr, void *); - for (j = 0; j <= rx_swbd->buffer_addr->pkt_len; j += RTE_CACHE_LINE_SIZE) + /* Invalidate packet data cache lines so CPU reads HW-written data. */ + data = rte_pktmbuf_mtod(seg, void *); + for (j = 0; j < data_len; j += RTE_CACHE_LINE_SIZE) dccivac(data + j); + dccivac(data + (data_len - 1)); + + if (bd_status & ENETC_RXBD_LSTATUS_F) { + seg->next = NULL; + first_seg->pkt_len -= rx_ring->crc_len; + rx_pkts[rx_frm_cnt] = first_seg; + rx_frm_cnt++; + first_seg = NULL; + } - rx_pkts[rx_frm_cnt] = rx_swbd->buffer_addr; cleaned_cnt++; rx_swbd++; i++; @@ -541,7 +572,6 @@ enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring, rx_swbd = &rx_ring->q_swbd[i]; } rxbd = ENETC_RXBD(*rx_ring, i); - rx_frm_cnt++; } rx_ring->next_to_clean = i; -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 07/10] net/enetc: add option to disable VSI messaging 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (5 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 06/10] net/enetc: support scatter-gather Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 08/10] net/enetc: add devargs to control VSI-PSI timeout and delay Gagandeep Singh ` (4 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal Add devarg 'enetc4_vsi_disable' to allow disabling features dependent on VSI-PSI messaging. This is useful for testing DPDK with a PF driver that does not support VSI-PSI messages. When the devarg is present, a reduced ops table (enetc4_vf_ops_no_vsi_m) is used that replaces link_update with a no-op stub and omits MAC/VLAN filter ops that require VSI msgs. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc4_vf.c | 61 +++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index 9dc4e1d..44c0dc0 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -3,11 +3,14 @@ */ #include <stdbool.h> +#include <rte_kvargs.h> #include <rte_random.h> #include <dpaax_iova_table.h> #include "enetc_logs.h" #include "enetc.h" +#define ENETC4_VSI_DISABLE "enetc4_vsi_disable" + #define ENETC_CRC_TABLE_SIZE 256 #define ENETC_POLY 0x1021 #define ENETC_CRC_INIT 0xffff @@ -687,6 +690,13 @@ enetc4_vf_get_link_speed(struct rte_eth_dev *dev, struct enetc_psi_reply_msg *re return err; } +static int +enetc4_vf_link_update_dummy(struct rte_eth_dev *dev __rte_unused, + int wait_to_complete __rte_unused) +{ + return 0; +} + static int enetc4_vf_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused) { @@ -1148,6 +1158,27 @@ static const struct rte_pci_id pci_vf_id_enetc4_map[] = { }; /* Features supported by this driver */ +/* ops table used when VSI messaging is disabled */ +static const struct eth_dev_ops enetc4_vf_ops_no_vsi_m = { + .dev_configure = enetc4_dev_configure, + .dev_start = enetc4_vf_dev_start, + .dev_stop = enetc4_vf_dev_stop, + .dev_close = enetc4_dev_close, + .stats_get = enetc4_vf_stats_get, + .dev_infos_get = enetc4_vf_dev_infos_get, + .mtu_set = enetc4_vf_mtu_set, + .link_update = enetc4_vf_link_update_dummy, + .rx_queue_setup = enetc4_rx_queue_setup, + .rx_queue_start = enetc4_rx_queue_start, + .rx_queue_stop = enetc4_rx_queue_stop, + .rx_queue_release = enetc4_rx_queue_release, + .tx_queue_setup = enetc4_tx_queue_setup, + .tx_queue_start = enetc4_tx_queue_start, + .tx_queue_stop = enetc4_tx_queue_stop, + .tx_queue_release = enetc4_tx_queue_release, + .dev_supported_ptypes_get = enetc4_supported_ptypes_get, +}; + static const struct eth_dev_ops enetc4_vf_ops = { .dev_configure = enetc4_dev_configure, .dev_start = enetc4_vf_dev_start, @@ -1283,7 +1314,28 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) struct enetc_hw *enetc_hw = &hw->hw; PMD_INIT_FUNC_TRACE(); - eth_dev->dev_ops = &enetc4_vf_ops; + + /* check if VSI messaging should be disabled via devarg */ + if (eth_dev->device->devargs) { + struct rte_kvargs *kvlist; + + kvlist = rte_kvargs_parse(eth_dev->device->devargs->args, + NULL); + if (kvlist) { + if (rte_kvargs_count(kvlist, ENETC4_VSI_DISABLE) != 0) { + ENETC_PMD_NOTICE("VSI messaging disabled by devarg"); + eth_dev->dev_ops = &enetc4_vf_ops_no_vsi_m; + } else { + eth_dev->dev_ops = &enetc4_vf_ops; + } + rte_kvargs_free(kvlist); + } else { + eth_dev->dev_ops = &enetc4_vf_ops; + } + } else { + eth_dev->dev_ops = &enetc4_vf_ops; + } + enetc4_dev_hw_init(eth_dev); si_cap = enetc_rd(enetc_hw, ENETC_SICAPR0); @@ -1304,8 +1356,9 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) ENETC_PMD_DEBUG("port_id %d vendorID=0x%x deviceID=0x%x", eth_dev->data->port_id, pci_dev->id.vendor_id, pci_dev->id.device_id); - /* update link */ - enetc4_vf_link_update(eth_dev, 0); + /* update link if VSI messaging is enabled */ + if (eth_dev->dev_ops == &enetc4_vf_ops) + enetc4_vf_link_update(eth_dev, 0); return 0; } @@ -1389,4 +1442,6 @@ static struct rte_pci_driver rte_enetc4_vf_pmd = { RTE_PMD_REGISTER_PCI(net_enetc4_vf, rte_enetc4_vf_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4_vf, pci_vf_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4_vf, "* igb_uio | uio_pci_generic"); +RTE_PMD_REGISTER_PARAM_STRING(net_enetc4_vf, + ENETC4_VSI_DISABLE "=<any>"); RTE_LOG_REGISTER_DEFAULT(enetc4_vf_logtype_pmd, NOTICE); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 08/10] net/enetc: add devargs to control VSI-PSI timeout and delay 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (6 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 07/10] net/enetc: add option to disable VSI messaging Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 09/10] net/enetc: set user configurable priority to TX rings Gagandeep Singh ` (3 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal Add two new devargs for ENETC4 VF: - enetc4_vsi_timeout: VSI-PSI message wait timeout (iteration count) - enetc4_vsi_delay: VSI-PSI message wait delay in microseconds Store the values in struct enetc_eth_hw and use them in enetc4_msg_vsi_send() instead of the hardcoded defaults. Fall back to ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE / ENETC4_DEF_VSI_WAIT_DELAY_UPDATE when not set. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc.h | 2 ++ drivers/net/enetc/enetc4_vf.c | 54 ++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 439d2d6..2cdb3c7 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -109,6 +109,8 @@ struct enetc_eth_hw { uint32_t num_rss; uint32_t max_rx_queues; uint32_t max_tx_queues; + uint32_t vsi_timeout; /* VSI-PSI message wait timeout (iterations) */ + uint32_t vsi_delay; /* VSI-PSI message wait delay (us) */ }; /* diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index 44c0dc0..79a08b3 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -10,6 +10,8 @@ #include "enetc.h" #define ENETC4_VSI_DISABLE "enetc4_vsi_disable" +#define ENETC4_VSI_TIMEOUT "enetc4_vsi_timeout" +#define ENETC4_VSI_DELAY "enetc4_vsi_delay" #define ENETC_CRC_TABLE_SIZE 256 #define ENETC_POLY 0x1021 @@ -262,10 +264,13 @@ enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw) } static int -enetc4_msg_vsi_send(struct enetc_hw *enetc_hw, struct enetc_msg_swbd *msg) +enetc4_msg_vsi_send(struct enetc_eth_hw *hw, struct enetc_msg_swbd *msg) { - int timeout = ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE; - int delay_us = ENETC4_DEF_VSI_WAIT_DELAY_UPDATE; + struct enetc_hw *enetc_hw = &hw->hw; + int timeout = hw->vsi_timeout ? (int)hw->vsi_timeout : + ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE; + int delay_us = hw->vsi_delay ? (int)hw->vsi_delay : + ENETC4_DEF_VSI_WAIT_DELAY_UPDATE; uint8_t class_id = 0; int err = 0; int vsimsgsr; @@ -382,7 +387,7 @@ enetc4_vf_set_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *addr) ENETC_CMD_ID_SET_PRIMARY_MAC, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -426,7 +431,6 @@ static int enetc4_vf_promisc_send_message(struct rte_eth_dev *dev, bool promisc_en) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_cmd_set_promisc *cmd; struct enetc_msg_swbd *msg; uint32_t msg_size; @@ -466,7 +470,7 @@ enetc4_vf_promisc_send_message(struct rte_eth_dev *dev, bool promisc_en) ENETC_CMD_ID_SET_MAC_PROMISCUOUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -483,7 +487,6 @@ static int enetc4_vf_allmulti_send_message(struct rte_eth_dev *dev, bool mc_promisc) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_cmd_set_promisc *cmd; struct enetc_msg_swbd *msg; uint32_t msg_size; @@ -524,7 +527,7 @@ enetc4_vf_allmulti_send_message(struct rte_eth_dev *dev, bool mc_promisc) ENETC_CMD_ID_SET_MAC_PROMISCUOUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -630,7 +633,7 @@ enetc4_vf_get_link_status(struct rte_eth_dev *dev, struct enetc_psi_reply_msg *r ENETC_CMD_ID_GET_LINK_STATUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -676,7 +679,7 @@ enetc4_vf_get_link_speed(struct rte_eth_dev *dev, struct enetc_psi_reply_msg *re ENETC_CMD_ID_GET_LINK_SPEED, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -819,7 +822,6 @@ static int enetc4_vf_vlan_promisc(struct rte_eth_dev *dev, bool promisc_en) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_cmd_set_vlan_promisc *cmd; struct enetc_msg_swbd *msg; uint32_t msg_size; @@ -858,7 +860,7 @@ enetc4_vf_vlan_promisc(struct rte_eth_dev *dev, bool promisc_en) ENETC_CMD_ID_SET_VLAN_PROMISCUOUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -921,7 +923,7 @@ enetc4_vf_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *addr, ENETC_MSG_ADD_EXACT_MAC_ENTRIES, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -1021,7 +1023,7 @@ static int enetc4_vf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, } /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -1104,7 +1106,6 @@ static int enetc4_vf_link_register_notif(struct rte_eth_dev *dev, bool enable) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_swbd *msg; struct rte_eth_link link; uint32_t msg_size; @@ -1138,7 +1139,7 @@ enetc4_vf_link_register_notif(struct rte_eth_dev *dev, bool enable) cmd, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) ENETC_PMD_ERR("VSI msg error for link status notification"); @@ -1322,12 +1323,29 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) kvlist = rte_kvargs_parse(eth_dev->device->devargs->args, NULL); if (kvlist) { + const char *val; + if (rte_kvargs_count(kvlist, ENETC4_VSI_DISABLE) != 0) { ENETC_PMD_NOTICE("VSI messaging disabled by devarg"); eth_dev->dev_ops = &enetc4_vf_ops_no_vsi_m; } else { eth_dev->dev_ops = &enetc4_vf_ops; } + + /* parse optional VSI-PSI timeout devarg */ + val = rte_kvargs_get(kvlist, ENETC4_VSI_TIMEOUT); + if (val) { + hw->vsi_timeout = (uint32_t)strtoul(val, NULL, 0); + ENETC_PMD_NOTICE("VSI timeout set to %u", hw->vsi_timeout); + } + + /* parse optional VSI-PSI delay devarg */ + val = rte_kvargs_get(kvlist, ENETC4_VSI_DELAY); + if (val) { + hw->vsi_delay = (uint32_t)strtoul(val, NULL, 0); + ENETC_PMD_NOTICE("VSI delay set to %u us", hw->vsi_delay); + } + rte_kvargs_free(kvlist); } else { eth_dev->dev_ops = &enetc4_vf_ops; @@ -1443,5 +1461,7 @@ RTE_PMD_REGISTER_PCI(net_enetc4_vf, rte_enetc4_vf_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4_vf, pci_vf_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4_vf, "* igb_uio | uio_pci_generic"); RTE_PMD_REGISTER_PARAM_STRING(net_enetc4_vf, - ENETC4_VSI_DISABLE "=<any>"); + ENETC4_VSI_DISABLE "=<any> " + ENETC4_VSI_TIMEOUT "=<uint> " + ENETC4_VSI_DELAY "=<uint>"); RTE_LOG_REGISTER_DEFAULT(enetc4_vf_logtype_pmd, NOTICE); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 09/10] net/enetc: set user configurable priority to TX rings 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (7 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 08/10] net/enetc: add devargs to control VSI-PSI timeout and delay Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 18:44 ` [PATCH 10/10] net/enetc4: add cacheable BD ring support with SW cache maintenance Gagandeep Singh ` (2 subsequent siblings) 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Vanshika Shukla From: Vanshika Shukla <vanshika.shukla@nxp.com> Add devarg 'enetc4_txq_prior' to allow per-queue TX ring priority configuration. The value is a '|'-separated list of TBMR priority bits, one per TX queue (e.g. 'enetc4_txq_prior=1|2|3'). Store the parsed priorities in hw->txq_prior and apply them in enetc4_tx_queue_setup() when enabling the ring. Signed-off-by: Vanshika Shukla <vanshika.shukla@nxp.com> --- drivers/net/enetc/enetc.h | 1 + drivers/net/enetc/enetc4_ethdev.c | 71 ++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 2cdb3c7..99b1e91 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -111,6 +111,7 @@ struct enetc_eth_hw { uint32_t max_tx_queues; uint32_t vsi_timeout; /* VSI-PSI message wait timeout (iterations) */ uint32_t vsi_delay; /* VSI-PSI message wait delay (us) */ + uint32_t *txq_prior; /* per-queue TX priority (TBMR priority bits) */ }; /* diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index 154fc09..d54051f 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -3,6 +3,7 @@ */ #include <stdbool.h> +#include <rte_kvargs.h> #include <rte_random.h> #include <dpaax_iova_table.h> @@ -10,6 +11,65 @@ #include "enetc_logs.h" #include "enetc.h" +#define ENETC4_TXQ_PRIORITIES "enetc4_txq_prior" + +static int +parse_txq_prior(const char *key __rte_unused, const char *value, void *opaque) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)opaque; + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); + char *input_str = strdup(value); + char *str; + uint32_t i = 0; + + hw->txq_prior = rte_zmalloc(NULL, + hw->max_tx_queues * sizeof(uint32_t), 0); + if (!hw->txq_prior) { + free(input_str); + return -1; + } + + str = strtok(input_str, "|"); + while (str != NULL && i < hw->max_tx_queues) { + hw->txq_prior[i++] = (uint32_t)atoi(str); + str = strtok(NULL, "|"); + } + + free(input_str); + return 0; +} + +static int +enetc4_get_devargs(struct rte_eth_dev *dev, const char *key) +{ + struct rte_devargs *devargs = dev->device->devargs; + struct rte_kvargs *kvlist; + + if (!devargs) + return 0; + + kvlist = rte_kvargs_parse(devargs->args, NULL); + if (!kvlist) + return 0; + + if (!rte_kvargs_count(kvlist, key)) { + rte_kvargs_free(kvlist); + return 0; + } + + if (!strcmp(key, ENETC4_TXQ_PRIORITIES)) { + if (rte_kvargs_process(kvlist, key, + parse_txq_prior, (void *)dev) < 0) { + rte_kvargs_free(kvlist); + return 0; + } + } + + rte_kvargs_free(kvlist); + return 0; +} + /* Supported Rx offloads */ static uint64_t dev_rx_offloads_sup = RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | @@ -310,9 +370,14 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev, data->tx_queues[queue_idx] = tx_ring; tx_ring->tx_deferred_start = tx_conf->tx_deferred_start; if (!tx_conf->tx_deferred_start) { + uint32_t tx_en = ENETC_TBMR_EN; + + /* apply TX queue priority if configured */ + if (priv->hw.txq_prior) + tx_en |= priv->hw.txq_prior[tx_ring->index]; /* enable ring */ enetc4_txbdr_wr(&priv->hw.hw, tx_ring->index, - ENETC_TBMR, ENETC_TBMR_EN); + ENETC_TBMR, tx_en); dev->data->tx_queue_state[tx_ring->index] = RTE_ETH_QUEUE_STATE_STARTED; } else { @@ -1009,6 +1074,8 @@ enetc4_dev_init(struct rte_eth_dev *eth_dev) hw->max_tx_queues = si_cap & ENETC_SICAPR0_BDR_MASK; hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK; + enetc4_get_devargs(eth_dev, ENETC4_TXQ_PRIORITIES); + ENETC_PMD_DEBUG("Max RX queues = %d Max TX queues = %d", hw->max_rx_queues, hw->max_tx_queues); error = enetc4_mac_init(hw, eth_dev); @@ -1065,4 +1132,6 @@ static struct rte_pci_driver rte_enetc4_pmd = { RTE_PMD_REGISTER_PCI(net_enetc4, rte_enetc4_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4, pci_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4, "* vfio-pci"); +RTE_PMD_REGISTER_PARAM_STRING(net_enetc4, + ENETC4_TXQ_PRIORITIES "=<string>"); RTE_LOG_REGISTER_DEFAULT(enetc4_logtype_pmd, NOTICE); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 10/10] net/enetc4: add cacheable BD ring support with SW cache maintenance 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (8 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 09/10] net/enetc: set user configurable priority to TX rings Gagandeep Singh @ 2026-06-19 18:44 ` Gagandeep Singh 2026-06-19 21:43 ` [PATCH 00/10] NXP ENETC driver related changes Stephen Hemminger 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh 11 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-19 18:44 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal On non-cache-coherent platforms such as i.MX95, the BD ring memory may be mapped as cacheable (normal memory) while the ENETC hardware DMA engine writes and reads descriptors without CPU cache snooping. SW must therefore perform explicit cache maintenance to keep CPU caches and DDR coherent. TX path (enetc_xmit_pkts_cacheable): - Flush each segment's payload cache lines to PoC (dcbf) before the BD is handed to HW, so HW DMA reads the correct data. - After all BDs for a burst are written, flush the BD cache lines (dcbf, one per 64-byte group of 4 BDs) so HW can read the updated descriptors. RX refill (enetc_refill_rx_ring): - After writing each full 4-BD cache-line group, dcbf that group so HW sees the buffer addresses and cleared lstatus fields. - Flush any partial trailing group before updating the ring tail. RX receive (enetc_recv_pkts_cacheable via enetc_clean_rx_ring_cacheable): - Before reading BD status, dccivac the current BD cache line so stale CPU-cached BD data is discarded and fresh HW-written content is fetched from DDR. - After a BD is consumed, dccivac each payload cache line so the CPU reads the DMA'd packet data, not stale cached bytes. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc.h | 21 +++ drivers/net/enetc/enetc4_ethdev.c | 40 +++-- drivers/net/enetc/enetc_rxtx.c | 274 ++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 15 deletions(-) diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 99b1e91..9f98480 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -96,6 +96,7 @@ struct enetc_bdr { uint64_t ierrors; uint8_t rx_deferred_start; uint8_t tx_deferred_start; + uint64_t bd_base_p; }; struct enetc_eth_hw { @@ -312,8 +313,28 @@ 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_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); + +/* + * Cache-maintenance constants for cacheable BD ring mode. + * + * BD = 16 bytes, cache line = 64 bytes => 4 BDs per cache line. + * Every dcbf in enetc_refill_rx_ring() flushes a full 64-byte cache line. + * To ensure each dcbf covers only fully-written BDs the caller + * must pass a count rounded DOWN to a multiple of ENETC_BD_PER_CL so that + * the last partial group is left in cache to be completed and flushed in + * the next call. + */ +#define ENETC_BD_PER_CL (RTE_CACHE_LINE_SIZE / sizeof(union enetc_rx_bd)) +#define ENETC_BD_PER_CL_MASK (ENETC_BD_PER_CL - 1) +/* Round n DOWN to the nearest multiple of ENETC_BD_PER_CL. */ +#define ENETC_BD_ALIGN_DOWN(n) ((n) & ~(unsigned int)ENETC_BD_PER_CL_MASK) + void enetc4_dev_hw_init(struct rte_eth_dev *eth_dev); void enetc_print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr); diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index d54051f..04dc306 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -281,12 +281,14 @@ enetc4_alloc_txbdr(struct enetc_bdr *txr, uint16_t nb_desc) int size; size = nb_desc * sizeof(struct enetc_swbd); - txr->q_swbd = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* 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; - size = nb_desc * sizeof(struct enetc_bdr); - txr->bd_base = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* Allocate the TX BD ring: each BD is struct enetc_tx_bd (16 bytes). */ + size = nb_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; @@ -441,12 +443,14 @@ enetc4_alloc_rxbdr(struct enetc_bdr *rxr, uint16_t nb_desc) int size; size = nb_desc * sizeof(struct enetc_swbd); - rxr->q_swbd = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* 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; - size = nb_desc * sizeof(struct enetc_bdr); - rxr->bd_base = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* Allocate the RX BD ring: each BD is union enetc_rx_bd (16 bytes). */ + size = nb_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; @@ -481,7 +485,7 @@ enetc4_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring, 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_unused(rx_ring))); + 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); @@ -743,12 +747,17 @@ enetc4_dev_configure(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); - max_len = dev->data->dev_conf.rxmode.mtu + RTE_ETHER_HDR_LEN + - RTE_ETHER_CRC_LEN; - enetc4_port_wr(enetc_hw, ENETC4_PM_MAXFRM(0), ENETC_SET_MAXFRM(max_len)); + /* Port-level register writes are PF-only; skip for VF devices */ + if (hw->device_id != ENETC4_DEV_ID_VF) { + max_len = dev->data->dev_conf.rxmode.mtu + RTE_ETHER_HDR_LEN + + RTE_ETHER_CRC_LEN; + enetc4_port_wr(enetc_hw, ENETC4_PM_MAXFRM(0), + ENETC_SET_MAXFRM(max_len)); - val = ENETC4_MAC_MAXFRM_SIZE | SDU_TYPE_MPDU; - enetc4_port_wr(enetc_hw, ENETC4_PTCTMSDUR(0), val | SDU_TYPE_MPDU); + val = ENETC4_MAC_MAXFRM_SIZE | SDU_TYPE_MPDU; + enetc4_port_wr(enetc_hw, ENETC4_PTCTMSDUR(0), + val | SDU_TYPE_MPDU); + } /* Rx offloads which are enabled by default */ if (dev_rx_offloads_sup & ~rx_offloads) { @@ -770,7 +779,8 @@ enetc4_dev_configure(struct rte_eth_dev *dev) if (rx_offloads & (RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM)) checksum &= ~L4_CKSUM; - enetc4_port_wr(enetc_hw, ENETC4_PARCSCR, checksum); + if (hw->device_id != ENETC4_DEV_ID_VF) + enetc4_port_wr(enetc_hw, ENETC4_PARCSCR, checksum); /* Enable interrupts */ if (hw->device_id == ENETC4_DEV_ID_VF) { @@ -1033,8 +1043,8 @@ enetc4_dev_hw_init(struct rte_eth_dev *eth_dev) ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev); - eth_dev->rx_pkt_burst = &enetc_recv_pkts_nc; - eth_dev->tx_pkt_burst = &enetc_xmit_pkts_nc; + eth_dev->rx_pkt_burst = &enetc_recv_pkts_cacheable; + eth_dev->tx_pkt_burst = &enetc_xmit_pkts_cacheable; /* Retrieving and storing the HW base address of device */ hw->hw.reg = (void *)pci_dev->mem_resource[0].addr; diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index a37c835..c737b22 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -26,6 +26,7 @@ enetc_clean_tx_ring(struct enetc_bdr *tx_ring) struct enetc_swbd *tx_swbd, *tx_swbd_base; int i, hwci, bd_count; struct rte_mbuf *m[ENETC_RXBD_BUNDLE]; + struct enetc_tx_bd *txbd; /* we don't need barriers here, we just want a relatively current value * from HW. @@ -51,6 +52,13 @@ enetc_clean_tx_ring(struct enetc_bdr *tx_ring) /* It seems calling rte_pktmbuf_free is wasting a lot of cycles, * make a list and call _free when it's done. */ + /* Clear flags on the reclaimed BD so that dcbf in the + * cacheable TX path never flushes a stale flags_F to memory + * before the new BD fields are fully written. + */ + txbd = ENETC_TXBD(*tx_ring, i); + txbd->flags = 0; + if (tx_frm_cnt == ENETC_RXBD_BUNDLE) { rte_pktmbuf_free_bulk(m, tx_frm_cnt); tx_frm_cnt = 0; @@ -217,6 +225,7 @@ enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) { struct enetc_swbd *rx_swbd; union enetc_rx_bd *rxbd; + union enetc_rx_bd *grp_start_rxbd; int i, j, k = ENETC_RXBD_BUNDLE; struct rte_mbuf *m[ENETC_RXBD_BUNDLE]; struct rte_mempool *mb_pool; @@ -225,6 +234,7 @@ enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) 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++) { /* bulk alloc for the next up to 8 BDs */ if (k == ENETC_RXBD_BUNDLE) { @@ -246,12 +256,29 @@ enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) i++; k++; if (unlikely(i == rx_ring->bd_count)) { + /* + * Ring wrap: flush the current partial or full group + * before resetting the pointer to index 0. + */ + 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-BD group (one cache line). + * Flush it to PoC so HW sees the updated descriptors. + */ + 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; @@ -597,3 +624,250 @@ enetc_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts, return enetc_clean_rx_ring(rx_ring, rx_pkts, nb_pkts); } + +/* --- Cacheable BD ring TX path with SW cache maintenance (dcbf) --- */ + +uint16_t +enetc_xmit_pkts_cacheable(void *tx_queue, + struct rte_mbuf **tx_pkts, + uint16_t nb_pkts) +{ + int i, start, bds_to_use; + struct enetc_tx_bd *txbd; + 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; + + /* + * Remember the first BD index of this batch so we can flush the + * BD cache lines to PoC after all descriptors are written. + */ + first_bd_idx = i; + + while (start < nb_pkts) { + seg = tx_pkts[start]; + segs_per_pkt = seg->nb_segs; + + 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 *); + + /* + * Flush packet data cache lines to PoC so HW DMA + * reads the correct payload from memory. + */ + for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE) + dcbf(data + j); + + /* + * Cover the last byte of an unaligned buffer to + * ensure the full payload is clean to the Point of + * Coherency. + */ + 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; + } + + /* + * Set the frame-last flag on the final BD of this packet. + * This is the last write to the BD group; the cache flush + * below will push all BDs to memory afterwards. + */ + 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. TX BDs are 16 B each; 4 BDs share + * one 64-byte cache line. Walk from the cache-line-aligned start + * of first_bd_idx to just past the last written BD, one dcbf per + * cache line. + * + * The flush must happen AFTER all BD fields (including flags_F) are + * written, so HW never sees a partial descriptor. + */ + 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; +} + +/* --- Cacheable BD ring RX path with SW cache maintenance (dccivac) --- */ + +static int +enetc_clean_rx_ring_cacheable(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 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; + + 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]; + + /* + * On i.MX95 the BD ring is in cacheable hugepage memory but the + * platform is non-cache-coherent. HW writes RX BDs to DDR + * without snooping the CPU cache, so stale cached copies of BD + * status fields must be discarded before the CPU reads them. + * + * Ideal instruction: DC IVAC (invalidate only, no writeback). + * ARM64 constraint: DC IVAC requires EL1 privilege; executing it + * from EL0 (DPDK userspace) raises a fault. The only EL0-safe + * cache maintenance instruction that invalidates is DC CIVAC + * (clean + invalidate, dccivac). + * + * Safety of using dccivac here: + * enetc_refill_rx_ring() issues dcbf() on every BD group before + * returning ownership to HW. After dcbf the CPU cache lines are + * marked clean (no dirty data). When dccivac runs, the "clean" + * phase finds nothing dirty to write back, so it behaves as a + * pure invalidate - exactly what we need. + * + * Granularity: BD = 16 B, cache line = 64 B, so one dccivac + * covers exactly 4 BDs. Invalidate at each 4-BD boundary. + */ + dccivac((void *)ENETC_RXBD(*rx_ring, + (i & ~(int)ENETC_BD_PER_CL_MASK))); + + while (likely(rx_frm_cnt < work_limit)) { +#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++; + + 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; + enetc_dev_rx_parse(first_seg, + rxbd_temp.r.parse_summary); + first_seg->hash.rss = rxbd_temp.r.rss_hash; + } else { + first_seg->pkt_len += data_len; + first_seg->nb_segs++; + cur_seg->next = seg; + cur_seg = seg; + } + + /* + * Invalidate packet data cache lines so the CPU reads the + * payload that HW DMA'd into memory, not stale cached bytes. + */ + 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. */ + dccivac(data + (data_len - 1)); + + if (bd_status & ENETC_RXBD_LSTATUS_F) { + seg->next = NULL; + first_seg->pkt_len -= rx_ring->crc_len; + rx_pkts[rx_frm_cnt] = first_seg; + rx_frm_cnt++; + first_seg = NULL; + } + + cleaned_cnt++; + rx_swbd++; + i++; + 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-BD (cache-line) boundary: invalidate the new + * group so the next four 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(rx_ring, ENETC_BD_ALIGN_DOWN(cleaned_cnt)); + + return rx_frm_cnt; +} + +uint16_t +enetc_recv_pkts_cacheable(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_cacheable(rx_ring, rx_pkts, nb_pkts); +} -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 00/10] NXP ENETC driver related changes 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (9 preceding siblings ...) 2026-06-19 18:44 ` [PATCH 10/10] net/enetc4: add cacheable BD ring support with SW cache maintenance Gagandeep Singh @ 2026-06-19 21:43 ` Stephen Hemminger 2026-06-22 11:36 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh 11 siblings, 1 reply; 24+ messages in thread From: Stephen Hemminger @ 2026-06-19 21:43 UTC (permalink / raw) To: Gagandeep Singh; +Cc: dev, hemant.agrawal On Sat, 20 Jun 2026 00:14:17 +0530 Gagandeep Singh <g.singh@nxp.com> wrote: > ENETC driver related changes series > > Gagandeep Singh (8): > net/enetc: fix TX BD structure > net/enetc: fix TX BDs flag overwrite issue > net/enetc: fix queue initialization > net/enetc: support ESP packet type in packet parsing > net/enetc: update random MAC generation code > net/enetc: add option to disable VSI messaging > net/enetc: add devargs to control VSI-PSI timeout and delay > net/enetc4: add cacheable BD ring support with SW cache maintenance > > Vanshika Shukla (2): > net/enetc: support scatter-gather > net/enetc: set user configurable priority to TX rings > > drivers/net/enetc/base/enetc_hw.h | 13 +- > drivers/net/enetc/enetc.h | 28 +- > drivers/net/enetc/enetc4_ethdev.c | 123 +++++++-- > drivers/net/enetc/enetc4_vf.c | 159 ++++++++++-- > drivers/net/enetc/enetc_ethdev.c | 26 +- > drivers/net/enetc/enetc_rxtx.c | 411 ++++++++++++++++++++++++++---- > 6 files changed, 649 insertions(+), 111 deletions(-) > The AI review shows some thing that need to be addressed before merging. [PATCH 04/10] net/enetc: support ESP packet type Info: enetc_supported_ptypes_get() adds RTE_PTYPE_TUNNEL_ESP and a trailing RTE_PTYPE_UNKNOWN. *no_of_elements is RTE_DIM(ptypes), so the 0 entry is counted (not used as a sentinel). It is filtered out by the mask test in rte_eth_dev_get_supported_ptypes(), so harmless, but the RTE_PTYPE_UNKNOWN line is unnecessary and should be dropped. [PATCH 06/10] net/enetc: support scatter-gather Warning: scatter Rx reassembly state (first_seg/cur_seg) is held in local variables and reset on every call. rx_frm_cnt only advances on the F bit, so work_limit won't cut a frame, but the "!(bd_status & LSTATUS_R)" break can exit mid-frame if HW has written the leading segments of a multi-segment frame but not yet the segment carrying F. On the next call first_seg is NULL again, next_to_clean has already advanced past the consumed leading segments, and those mbufs are leaked while the tail segments are mis-assembled as a new frame. Persist the partial chain across bursts in the ring (e.g. rx_ring->pkt_first_seg / pkt_last_seg) instead of locals. (Same pattern is reproduced in enetc_clean_rx_ring_cacheable in patch 10.) Warning: enetc4 now advertises RTE_ETH_RX_OFFLOAD_SCATTER and RTE_ETH_TX_OFFLOAD_MULTI_SEGS (VF) but doc/guides/nics/features/ enetc4.ini is not updated (Scattered Rx / Multi segment rows). Info: the VF dev_info now advertises L3/L4 RX checksum offload, but enetc_dev_rx_parse() unconditionally sets RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD and never reports *_BAD. With the offload now advertised, an application relying on it will never see a bad-checksum indication. Info: dccivac(data + (data_len - 1)) / dcbf(data + (seg_len - 1)) underflow to data-1 when the segment length is 0 (uint16_t promotes to int). The preceding loop already covers the final cache line, so the extra op is redundant as well as unsafe for len==0. [PATCH 07/10] net/enetc: add option to disable VSI messaging Warning: new devarg "enetc4_vsi_disable" is registered but not documented in doc/guides/nics/enetc.rst. [PATCH 08/10] net/enetc: add devargs to control VSI-PSI timeout/delay Warning: new devargs "enetc4_vsi_timeout" / "enetc4_vsi_delay" are not documented in doc/guides/nics/enetc.rst. [PATCH 09/10] net/enetc: set user configurable priority to TX rings Error: hw->txq_prior is allocated in parse_txq_prior() with rte_zmalloc() but never freed. It leaks on dev_close / re-probe. Free it in the close/uninit path (and note it is re-allocated every time the handler runs, so a repeated key would leak the prior allocation too). Warning: txq_prior is control-path, CPU-only data; rte_zmalloc() consumes hugepage memory unnecessarily. Use calloc()/malloc(). Warning: the parsed value is OR'd straight into TBMR: tx_en |= priv->hw.txq_prior[tx_ring->index]; with no mask. ENETC_TBMR_EN is BIT(31) and there is no TBMR priority mask defined. A user value with high bits set can corrupt unrelated TBMR control bits. Mask the input to the valid TBMR priority field. Info: strdup(value) return is not checked; on failure strtok(input_str, "|") is called with a NULL first argument, which resumes from strtok's stale internal state rather than erroring. Warning: new devarg "enetc4_txq_prior" not documented in doc/guides/nics/enetc.rst. [PATCH 10/10] net/enetc4: add cacheable BD ring support with SW cache Warning: enetc4_dev_hw_init() switches rx_pkt_burst/tx_pkt_burst to the cache-maintenance variants unconditionally for every enetc4 device (PF and VF). The commit message scopes this to non-cache-coherent parts (i.MX95), but the code applies it everywhere, adding dcbf/dccivac cost on cache-coherent platforms that previously used the _nc fast path. Gate it on a devarg or coherency/platform check. Warning: the RX payload invalidation uses dccivac (dc civac = clean+invalidate). The comment justifies clean-then-invalidate for the BD ring (refill dcbf leaves BD lines clean), but payload buffers are not cleaned before being handed to HW. If a payload cache line is dirty (stale CPU data from a prior use of the mbuf), the clean phase writes it back over the HW-DMA'd data in DDR before invalidating -> silent RX corruption on a non-coherent part. Please confirm payload lines can never be dirty here, or use invalidate-only. Info: struct enetc_bdr gains "uint64_t bd_base_p" but it is never referenced anywhere. Remove the dead field. Info: the 64-bit BD fast copy __uint128_t *dst128 = (__uint128_t *)&rxbd_temp; *dst128 = *(const __uint128_t *)rxbd; takes the address of an 8-byte-aligned stack union (rxbd_temp) as __uint128_t*. That is an under-aligned 128-bit access (UB); aarch64 tolerates it via ldp/stp but it is fragile. Force 16-byte alignment on rxbd_temp or copy as two u64. General (series-wide) Warning: no release notes. The series adds user-visible features (scatter-gather, cacheable BD ring support, four new devargs) with no entry in doc/guides/rel_notes/. New driver capabilities and devargs need release-note coverage. ^ permalink raw reply [flat|nested] 24+ messages in thread
* RE: [PATCH 00/10] NXP ENETC driver related changes 2026-06-19 21:43 ` [PATCH 00/10] NXP ENETC driver related changes Stephen Hemminger @ 2026-06-22 11:36 ` Gagandeep Singh 0 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:36 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev@dpdk.org, Hemant Agrawal Hi > -----Original Message----- > From: Stephen Hemminger <stephen@networkplumber.org> > Sent: Saturday, June 20, 2026 3:14 AM > To: Gagandeep Singh <G.Singh@nxp.com> > Cc: dev@dpdk.org; Hemant Agrawal <hemant.agrawal@nxp.com> > Subject: Re: [PATCH 00/10] NXP ENETC driver related changes > > On Sat, 20 Jun 2026 00:14:17 +0530 > Gagandeep Singh <g.singh@nxp.com> wrote: > > > ENETC driver related changes series > > > > Gagandeep Singh (8): > > net/enetc: fix TX BD structure > > net/enetc: fix TX BDs flag overwrite issue > > net/enetc: fix queue initialization > > net/enetc: support ESP packet type in packet parsing > > net/enetc: update random MAC generation code > > net/enetc: add option to disable VSI messaging > > net/enetc: add devargs to control VSI-PSI timeout and delay > > net/enetc4: add cacheable BD ring support with SW cache maintenance > > > > Vanshika Shukla (2): > > net/enetc: support scatter-gather > > net/enetc: set user configurable priority to TX rings > > > > drivers/net/enetc/base/enetc_hw.h | 13 +- > > drivers/net/enetc/enetc.h | 28 +- > > drivers/net/enetc/enetc4_ethdev.c | 123 +++++++-- > > drivers/net/enetc/enetc4_vf.c | 159 ++++++++++-- > > drivers/net/enetc/enetc_ethdev.c | 26 +- > > drivers/net/enetc/enetc_rxtx.c | 411 ++++++++++++++++++++++++++---- > > 6 files changed, 649 insertions(+), 111 deletions(-) > > > > The AI review shows some thing that need to be addressed before merging. > > [PATCH 04/10] net/enetc: support ESP packet type > > Info: enetc_supported_ptypes_get() adds RTE_PTYPE_TUNNEL_ESP and a trailing > RTE_PTYPE_UNKNOWN. *no_of_elements is RTE_DIM(ptypes), so the > 0 entry is counted (not used as a sentinel). It is filtered out by the mask test in > rte_eth_dev_get_supported_ptypes(), so harmless, but the > RTE_PTYPE_UNKNOWN line is unnecessary and should be dropped. > > > [PATCH 06/10] net/enetc: support scatter-gather > > Warning: scatter Rx reassembly state (first_seg/cur_seg) is held in local variables > and reset on every call. rx_frm_cnt only advances on the F bit, so work_limit > won't cut a frame, but the "!(bd_status & LSTATUS_R)" break can exit mid-frame > if HW has written the leading segments of a multi-segment frame but not yet the > segment carrying F. On the next call first_seg is NULL again, next_to_clean has > already advanced past the consumed leading segments, and those mbufs are > leaked while the tail segments are mis-assembled as a new frame. > Persist the partial chain across bursts in the ring (e.g. > rx_ring->pkt_first_seg / pkt_last_seg) instead of locals. (Same pattern is > reproduced in enetc_clean_rx_ring_cacheable in patch 10.) > > Warning: enetc4 now advertises RTE_ETH_RX_OFFLOAD_SCATTER and > RTE_ETH_TX_OFFLOAD_MULTI_SEGS (VF) but doc/guides/nics/features/ > enetc4.ini is not updated (Scattered Rx / Multi segment rows). > > Info: the VF dev_info now advertises L3/L4 RX checksum offload, but > enetc_dev_rx_parse() unconditionally sets RTE_MBUF_F_RX_IP_CKSUM_GOOD | > RTE_MBUF_F_RX_L4_CKSUM_GOOD and never reports *_BAD. With the offload > now advertised, an application relying on it will never see a bad-checksum > indication. > > Info: dccivac(data + (data_len - 1)) / dcbf(data + (seg_len - 1)) underflow to data-1 > when the segment length is 0 (uint16_t promotes to int). The preceding loop > already covers the final cache line, so the extra op is redundant as well as unsafe > for len==0. > > > [PATCH 07/10] net/enetc: add option to disable VSI messaging > > Warning: new devarg "enetc4_vsi_disable" is registered but not documented in > doc/guides/nics/enetc.rst. > > > [PATCH 08/10] net/enetc: add devargs to control VSI-PSI timeout/delay > > Warning: new devargs "enetc4_vsi_timeout" / "enetc4_vsi_delay" are not > documented in doc/guides/nics/enetc.rst. > > > [PATCH 09/10] net/enetc: set user configurable priority to TX rings > > Error: hw->txq_prior is allocated in parse_txq_prior() with > rte_zmalloc() but never freed. It leaks on dev_close / re-probe. Free it in the > close/uninit path (and note it is re-allocated every time the handler runs, so a > repeated key would leak the prior allocation too). > > Warning: txq_prior is control-path, CPU-only data; rte_zmalloc() consumes > hugepage memory unnecessarily. Use calloc()/malloc(). > > Warning: the parsed value is OR'd straight into TBMR: > tx_en |= priv->hw.txq_prior[tx_ring->index]; > with no mask. ENETC_TBMR_EN is BIT(31) and there is no TBMR priority mask > defined. A user value with high bits set can corrupt unrelated TBMR control bits. > Mask the input to the valid TBMR priority field. > > Info: strdup(value) return is not checked; on failure strtok(input_str, "|") is called > with a NULL first argument, which resumes from strtok's stale internal state > rather than erroring. > > Warning: new devarg "enetc4_txq_prior" not documented in > doc/guides/nics/enetc.rst. > > > [PATCH 10/10] net/enetc4: add cacheable BD ring support with SW cache > > Warning: enetc4_dev_hw_init() switches rx_pkt_burst/tx_pkt_burst to the cache- > maintenance variants unconditionally for every enetc4 device (PF and VF). The > commit message scopes this to non-cache-coherent parts (i.MX95), but the code > applies it everywhere, adding dcbf/dccivac cost on cache-coherent platforms that > previously used the _nc fast path. Gate it on a devarg or coherency/platform > check. > > Warning: the RX payload invalidation uses dccivac (dc civac = > clean+invalidate). The comment justifies clean-then-invalidate for the > BD ring (refill dcbf leaves BD lines clean), but payload buffers are not cleaned > before being handed to HW. If a payload cache line is dirty (stale CPU data from a > prior use of the mbuf), the clean phase writes it back over the HW-DMA'd data in > DDR before invalidating -> silent RX corruption on a non-coherent part. Please > confirm payload lines can never be dirty here, or use invalidate-only. > > Info: struct enetc_bdr gains "uint64_t bd_base_p" but it is never referenced > anywhere. Remove the dead field. > > Info: the 64-bit BD fast copy > __uint128_t *dst128 = (__uint128_t *)&rxbd_temp; > *dst128 = *(const __uint128_t *)rxbd; > takes the address of an 8-byte-aligned stack union (rxbd_temp) as __uint128_t*. > That is an under-aligned 128-bit access (UB); aarch64 tolerates it via ldp/stp but > it is fragile. Force 16-byte alignment on rxbd_temp or copy as two u64. > > > General (series-wide) > > Warning: no release notes. The series adds user-visible features (scatter-gather, > cacheable BD ring support, four new devargs) with no entry in > doc/guides/rel_notes/. New driver capabilities and devargs need release-note > coverage. I have sent the V2 series which includes most of the fixes. I have mentioned all the fixes in the cover-letter. Thanks, Gagan ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 0/9] ENETC driver related changes series 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh ` (10 preceding siblings ...) 2026-06-19 21:43 ` [PATCH 00/10] NXP ENETC driver related changes Stephen Hemminger @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 1/9] net/enetc: fix TX BD structure Gagandeep Singh ` (9 more replies) 11 siblings, 10 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 2320 bytes --] V2 changes: - Fixed an un-used variable compilation issue reported on fedora:43-gcc-minsize - Fixed various AI reported issues: - Release notes updated for all new devargs - enect4.ini features doc updated for scattered RX. - removed Not required RTE_PTYPE_UNKNOWN. - Fixed mid-frame mbuf leak in SG case. - Enabled SG for enetc4 PF also. - move to calloc from rte_zmalloc in parse_txq_prior(). - added vaidation checks on strdup, strtoul. - added NC devargs to use cacheable ops conditionally. - removed dead code like bd_base_p etc. - Fixed rte_cpu_to_le_16() conversion on flags and combined all flags related patches in one patch. - Fixed memory leak issue due to TXQ priority patch. - There were some false positives, I have ignored them: Race condition on flags field: clean_tx_ring only touches HW-completed BDs (next_to_clean→hwci), never newly-submitted BDs; doorbell hasn't fired yet. Missing dcbf in clean_tx_ring: DPDK is single-threaded per queue; TX path always overwrites flags completely before dcbf. TX dcbf granularity with wrap: Safe (AI admits it). RX refill flush at wrap: In-loop dcbf at i & mask == 0 already flushes aligned groups; trailing flush only needed for partial groups. RX reading before invalidate: dccivac precedes the read for every group in the loop Gagandeep Singh (7): net/enetc: fix TX BD structure net/enetc: fix queue initialization net/enetc: support ESP packet type in packet parsing net/enetc: update random MAC generation code net/enetc: add option to disable VSI messaging net/enetc: add devargs to control VSI-PSI timeout and delay net/enetc4: add cacheable BD ring support with SW cache maintenance Vanshika Shukla (2): net/enetc: support scatter-gather net/enetc: set user configurable priority to TX rings doc/guides/nics/features/enetc4.ini | 1 + doc/guides/rel_notes/release_26_07.rst | 10 + drivers/net/enetc/base/enetc_hw.h | 13 +- drivers/net/enetc/enetc.h | 31 +- drivers/net/enetc/enetc4_ethdev.c | 172 ++++++++-- drivers/net/enetc/enetc4_vf.c | 204 ++++++++++-- drivers/net/enetc/enetc_ethdev.c | 25 +- drivers/net/enetc/enetc_rxtx.c | 430 ++++++++++++++++++++++--- 8 files changed, 768 insertions(+), 118 deletions(-) -- 2.25.1 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 1/9] net/enetc: fix TX BD structure 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 2/9] net/enetc: fix queue initialization Gagandeep Singh ` (8 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, stable, Gagandeep Singh The flags field in struct enetc_tx_bd was declared as uint16_t but ENETC4 TX BDs only use an 8-bit flags byte. Fix the type to uint8_t to match the hardware descriptor layout. Fixes: 696fa399d797 ("net/enetc: add PMD with basic operations") Cc: stable@dpdk.org Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/base/enetc_hw.h | 7 +++---- drivers/net/enetc/enetc_rxtx.c | 17 +++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h index 173d677..19efadd 100644 --- a/drivers/net/enetc/base/enetc_hw.h +++ b/drivers/net/enetc/base/enetc_hw.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2024 NXP + * Copyright 2018-2026 NXP */ #ifndef _ENETC_HW_H_ @@ -198,8 +198,7 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_TX_ADDR(txq, addr) ((void *)((txq)->enetc_txbdr + (addr))) -#define ENETC_TXBD_FLAGS_IE BIT(13) -#define ENETC_TXBD_FLAGS_F BIT(15) +#define ENETC_TXBD_FLAGS_F BIT(7) /* ENETC Parsed values (Little Endian) */ #define ENETC_PARSE_ERROR 0x8000 @@ -262,7 +261,7 @@ struct enetc_tx_bd { uint8_t l3t:1; uint8_t resv:5; uint8_t l4t:3; - uint16_t flags; + uint8_t flags; };/* default layout */ uint32_t txstart; uint32_t lstatus; diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index a2b8153..d3b98b3 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2024 NXP + * Copyright 2018-2026 NXP */ #include <stdbool.h> @@ -101,7 +101,7 @@ enetc_xmit_pkts(void *tx_queue, tx_swbd = &tx_ring->q_swbd[i]; txbd->frm_len = tx_pkts[start]->pkt_len; txbd->buf_len = txbd->frm_len; - txbd->flags = rte_cpu_to_le_16(ENETC_TXBD_FLAGS_F); + txbd->flags = ENETC_TXBD_FLAGS_F; txbd->addr = (uint64_t)(uintptr_t) rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova + tx_swbd->buffer_addr->data_off); @@ -133,13 +133,13 @@ enetc4_tx_offload_checksum(struct rte_mbuf *mbuf, struct enetc_tx_bd *txbd) txbd->ipcs = ENETC4_TXBD_IPCS; txbd->l3_start = mbuf->l2_len; txbd->l3_hdr_size = mbuf->l3_len / 4; - txbd->flags |= rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_L_TX_CKSUM); + txbd->flags |= ENETC4_TXBD_FLAGS_L_TX_CKSUM; if ((mbuf->ol_flags & RTE_MBUF_F_TX_UDP_CKSUM) == RTE_MBUF_F_TX_UDP_CKSUM) { - txbd->l4t = rte_cpu_to_le_16(ENETC4_TXBD_L4T_UDP); - txbd->flags |= rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_L4CS); + txbd->l4t = ENETC4_TXBD_L4T_UDP; + txbd->flags |= ENETC4_TXBD_FLAGS_L4CS; } else if ((mbuf->ol_flags & RTE_MBUF_F_TX_TCP_CKSUM) == RTE_MBUF_F_TX_TCP_CKSUM) { - txbd->l4t = rte_cpu_to_le_16(ENETC4_TXBD_L4T_TCP); - txbd->flags |= rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_L4CS); + txbd->l4t = ENETC4_TXBD_L4T_TCP; + txbd->flags |= ENETC4_TXBD_FLAGS_L4CS; } } } @@ -172,7 +172,7 @@ enetc_xmit_pkts_nc(void *tx_queue, dcbf(data + j); txbd = ENETC_TXBD(*tx_ring, i); - txbd->flags = rte_cpu_to_le_16(ENETC4_TXBD_FLAGS_F); + txbd->flags = 0; if (tx_ring->q_swbd[i].buffer_addr->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK) enetc4_tx_offload_checksum(tx_ring->q_swbd[i].buffer_addr, txbd); @@ -182,6 +182,7 @@ enetc_xmit_pkts_nc(void *tx_queue, txbd->addr = (uint64_t)(uintptr_t) rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova + tx_swbd->buffer_addr->data_off); + txbd->flags |= ENETC4_TXBD_FLAGS_F; i++; start++; if (unlikely(i == tx_ring->bd_count)) -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 2/9] net/enetc: fix queue initialization 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 1/9] net/enetc: fix TX BD structure Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 3/9] net/enetc: support ESP packet type in packet parsing Gagandeep Singh ` (7 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, stable, Gagandeep Singh Hardware can misbehave if the user tries to reset the consumer and producer indexes without resetting the ring. This patch adds the ring reset step before resetting the indexes. Fixes: 6c9c5aadc0e0 ("net/enetc: support ENETC4 queue API") Cc: stable@dpdk.org Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc4_ethdev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index 78eba70..154fc09 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2024 NXP + * Copyright 2024-2026 NXP */ #include <stdbool.h> @@ -279,6 +279,7 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev, const struct rte_eth_txconf *tx_conf) { int err; + uint32_t tx_data; struct enetc_bdr *tx_ring; struct rte_eth_dev_data *data = dev->data; struct enetc_eth_adapter *priv = @@ -301,6 +302,10 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev, goto fail; tx_ring->ndev = dev; + /* reset queue */ + tx_data = enetc4_txbdr_rd(&priv->hw.hw, tx_ring->index, ENETC_TBMR); + tx_data &= ~ENETC_TBMR_EN; + enetc4_txbdr_wr(&priv->hw.hw, tx_ring->index, ENETC_TBMR, tx_data); enetc4_setup_txbdr(&priv->hw.hw, tx_ring); data->tx_queues[queue_idx] = tx_ring; tx_ring->tx_deferred_start = tx_conf->tx_deferred_start; @@ -427,6 +432,7 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev, struct rte_mempool *mb_pool) { int err = 0; + uint32_t rx_enable; struct enetc_bdr *rx_ring; struct rte_eth_dev_data *data = dev->data; struct enetc_eth_adapter *adapter = @@ -450,6 +456,10 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev, goto fail; rx_ring->ndev = dev; + /* reset queue */ + rx_enable = enetc4_rxbdr_rd(&adapter->hw.hw, rx_ring->index, ENETC_RBMR); + rx_enable &= ~ENETC_RBMR_EN; + enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index, ENETC_RBMR, rx_enable); enetc4_setup_rxbdr(&adapter->hw.hw, rx_ring, mb_pool); data->rx_queues[rx_queue_id] = rx_ring; rx_ring->rx_deferred_start = rx_conf->rx_deferred_start; -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 3/9] net/enetc: support ESP packet type in packet parsing 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 1/9] net/enetc: fix TX BD structure Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 2/9] net/enetc: fix queue initialization Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 4/9] net/enetc: update random MAC generation code Gagandeep Singh ` (6 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Gagandeep Singh Add ESP (Encapsulating Security Payload) packet type definitions and handling to the RX packet parsing path. Also update the supported ptypes array to advertise ESP tunnel type support. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- doc/guides/rel_notes/release_26_07.rst | 3 +++ drivers/net/enetc/base/enetc_hw.h | 4 ++++ drivers/net/enetc/enetc_ethdev.c | 3 ++- drivers/net/enetc/enetc_rxtx.c | 10 ++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index fc6e144..35476c2 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -187,6 +187,9 @@ New Features ``RTE_ETH_EVENT_RECOVERY_FAILED``) to notify upper layers of the reset lifecycle. +* **Updated NXP ENETC ethernet driver.** + + * Added support for ESP packet type in packet parsing Removed Items ------------- diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h index 19efadd..f79c950 100644 --- a/drivers/net/enetc/base/enetc_hw.h +++ b/drivers/net/enetc/base/enetc_hw.h @@ -226,6 +226,10 @@ enum enetc_bdr_type {TX, RX}; (0x0003 | ENETC_PKT_TYPE_IPV4) #define ENETC_PKT_TYPE_IPV6_ICMP \ (0x0003 | ENETC_PKT_TYPE_IPV6) +#define ENETC_PKT_TYPE_IPV4_ESP \ + (0x0005 | ENETC_PKT_TYPE_IPV4) +#define ENETC_PKT_TYPE_IPV6_ESP \ + (0x0005 | ENETC_PKT_TYPE_IPV6) /* PCI device info */ struct enetc_hw { diff --git a/drivers/net/enetc/enetc_ethdev.c b/drivers/net/enetc/enetc_ethdev.c index f41f3c1..8196377 100644 --- a/drivers/net/enetc/enetc_ethdev.c +++ b/drivers/net/enetc/enetc_ethdev.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2024 NXP + * Copyright 2018-2026 NXP */ #include <stdbool.h> @@ -95,6 +95,7 @@ enetc_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP, + RTE_PTYPE_TUNNEL_ESP }; *no_of_elements = RTE_DIM(ptypes); diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index d3b98b3..94177bb 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -370,6 +370,16 @@ enetc_dev_rx_parse(struct rte_mbuf *m, uint16_t parse_results) RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_UDP; return; + case ENETC_PKT_TYPE_IPV4_ESP: + m->packet_type = RTE_PTYPE_L2_ETHER | + RTE_PTYPE_L3_IPV4 | + RTE_PTYPE_TUNNEL_ESP; + return; + case ENETC_PKT_TYPE_IPV6_ESP: + m->packet_type = RTE_PTYPE_L2_ETHER | + RTE_PTYPE_L3_IPV6 | + RTE_PTYPE_TUNNEL_ESP; + return; case ENETC_PKT_TYPE_IPV4_SCTP: m->packet_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4 | -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 4/9] net/enetc: update random MAC generation code 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (2 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 3/9] net/enetc: support ESP packet type in packet parsing Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 5/9] net/enetc: support scatter-gather Gagandeep Singh ` (5 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Gagandeep Singh Use rte_eth_random_addr() instead of manual rte_rand() based MAC generation. Also handle VF path by writing to ENETC_SIPMAR0/1 instead of ENETC_PSIPMAR0/1 when running as a VF. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- drivers/net/enetc/enetc_ethdev.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/enetc/enetc_ethdev.c b/drivers/net/enetc/enetc_ethdev.c index 8196377..55b0e0b 100644 --- a/drivers/net/enetc/enetc_ethdev.c +++ b/drivers/net/enetc/enetc_ethdev.c @@ -195,20 +195,18 @@ enetc_hardware_init(struct enetc_eth_hw *hw) } if ((high_mac | low_mac) == 0) { - char *first_byte; - ENETC_PMD_NOTICE("MAC is not available for this SI, " "set random MAC"); - mac = (uint32_t *)hw->mac.addr; - *mac = (uint32_t)rte_rand(); - first_byte = (char *)mac; - *first_byte &= 0xfe; /* clear multicast bit */ - *first_byte |= 0x02; /* set local assignment bit (IEEE802) */ - - enetc_port_wr(enetc_hw, ENETC_PSIPMAR0(0), *mac); - mac++; - *mac = (uint16_t)rte_rand(); - enetc_port_wr(enetc_hw, ENETC_PSIPMAR1(0), *mac); + rte_eth_random_addr(hw->mac.addr); + high_mac = *(uint32_t *)hw->mac.addr; + low_mac = *(uint16_t *)(hw->mac.addr + 4); + if (hw->device_id == ENETC_DEV_ID_VF) { + enetc_wr(enetc_hw, ENETC_SIPMAR0, high_mac); + enetc_wr(enetc_hw, ENETC_SIPMAR1, low_mac); + } else { + enetc_port_wr(enetc_hw, ENETC_PSIPMAR0(0), high_mac); + enetc_port_wr(enetc_hw, ENETC_PSIPMAR1(0), low_mac); + } enetc_print_ethaddr("New address: ", (const struct rte_ether_addr *)hw->mac.addr); } -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 5/9] net/enetc: support scatter-gather 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (3 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 4/9] net/enetc: update random MAC generation code Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 6/9] net/enetc: add option to disable VSI messaging Gagandeep Singh ` (4 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Vanshika Shukla From: Vanshika Shukla <vanshika.shukla@nxp.com> Add scatter-gather support for ENETC4 PMD: - Add ENETC_RXBD_LSTATUS_R/F bits for RX BD status - Add ENETC4_MAX_SEGS (63) for max segments per TX packet - Update enetc4_vf_dev_infos_get to fill nb_seg_max, offloads, max queues and packet length - Extend enetc_xmit_pkts_nc to handle multi-segment mbufs - Extend enetc_clean_rx_ring_nc to chain scatter-gather segments using LSTATUS_R/F bits Signed-off-by: Vanshika Shukla <vanshika.shukla@nxp.com> --- doc/guides/nics/features/enetc4.ini | 1 + doc/guides/rel_notes/release_26_07.rst | 3 +- drivers/net/enetc/base/enetc_hw.h | 2 + drivers/net/enetc/enetc.h | 7 +- drivers/net/enetc/enetc4_ethdev.c | 10 +- drivers/net/enetc/enetc4_vf.c | 46 +++++++-- drivers/net/enetc/enetc_rxtx.c | 129 ++++++++++++++++--------- 7 files changed, 139 insertions(+), 59 deletions(-) diff --git a/doc/guides/nics/features/enetc4.ini b/doc/guides/nics/features/enetc4.ini index 87425f4..698140e 100644 --- a/doc/guides/nics/features/enetc4.ini +++ b/doc/guides/nics/features/enetc4.ini @@ -17,6 +17,7 @@ Basic stats = Y L3 checksum offload = Y L4 checksum offload = Y Queue start/stop = Y +Scattered Rx = Y Linux = Y ARMv8 = Y Usage doc = Y diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 35476c2..f900145 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -189,7 +189,8 @@ New Features * **Updated NXP ENETC ethernet driver.** - * Added support for ESP packet type in packet parsing + * Added support for ESP packet type in packet parsing. + * Added scatter-gather support for ENETC4 PFs and VFs. Removed Items ------------- diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h index f79c950..6e96562 100644 --- a/drivers/net/enetc/base/enetc_hw.h +++ b/drivers/net/enetc/base/enetc_hw.h @@ -230,6 +230,8 @@ enum enetc_bdr_type {TX, RX}; (0x0005 | ENETC_PKT_TYPE_IPV4) #define ENETC_PKT_TYPE_IPV6_ESP \ (0x0005 | ENETC_PKT_TYPE_IPV6) +#define ENETC_RXBD_LSTATUS_R BIT(30) +#define ENETC_RXBD_LSTATUS_F BIT(31) /* PCI device info */ struct enetc_hw { diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 4d99b5b..01da898 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2019,2024 NXP + * Copyright 2018-2019,2024-2026 NXP */ #ifndef _ENETC_H_ @@ -28,6 +28,8 @@ #define MIN_BD_COUNT 32 /* BD ALIGN */ #define BD_ALIGN 8 +/* Max segments per ENETC4 TX packet (scatter-gather) */ +#define ENETC4_MAX_SEGS 63 /* minimum frame size supported */ #define ENETC_MAC_MINFRM_SIZE 68 @@ -90,6 +92,9 @@ struct enetc_bdr { 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 */ + struct rte_mbuf *pkt_last_seg; /* last segment linked so far */ struct rte_eth_dev *ndev; uint64_t ierrors; uint8_t rx_deferred_start; diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index 154fc09..ad1ef4d 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -14,13 +14,15 @@ 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_TCP_CKSUM | + RTE_ETH_RX_OFFLOAD_SCATTER; /* 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; + RTE_ETH_TX_OFFLOAD_TCP_CKSUM | + RTE_ETH_TX_OFFLOAD_MULTI_SEGS; static int enetc4_dev_start(struct rte_eth_dev *dev) @@ -199,11 +201,15 @@ enetc4_dev_infos_get(struct rte_eth_dev *dev, .nb_max = MAX_BD_COUNT, .nb_min = MIN_BD_COUNT, .nb_align = BD_ALIGN, + .nb_seg_max = ENETC4_MAX_SEGS, + .nb_mtu_seg_max = ENETC4_MAX_SEGS, }; dev_info->tx_desc_lim = (struct rte_eth_desc_lim) { .nb_max = MAX_BD_COUNT, .nb_min = MIN_BD_COUNT, .nb_align = BD_ALIGN, + .nb_seg_max = ENETC4_MAX_SEGS, + .nb_mtu_seg_max = ENETC4_MAX_SEGS, }; dev_info->max_rx_queues = hw->max_rx_queues; dev_info->max_tx_queues = hw->max_tx_queues; diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index bec7128..9dc4e1d 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2024 NXP + * Copyright 2024-2026 NXP */ #include <stdbool.h> @@ -18,8 +18,19 @@ uint16_t enetc_crc_table[ENETC_CRC_TABLE_SIZE]; bool enetc_crc_gen; /* Supported Rx offloads */ -static uint64_t dev_vf_rx_offloads_sup = - RTE_ETH_RX_OFFLOAD_VLAN_FILTER; +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_VLAN_FILTER | + RTE_ETH_RX_OFFLOAD_SCATTER; + +/* 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 | + RTE_ETH_TX_OFFLOAD_MULTI_SEGS; static void enetc_gen_crc_table(void) @@ -61,21 +72,38 @@ static int enetc4_vf_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { - int ret = 0; + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); PMD_INIT_FUNC_TRACE(); - ret = enetc4_dev_infos_get(dev, dev_info); - if (ret) - return ret; - + dev_info->rx_desc_lim = (struct rte_eth_desc_lim) { + .nb_max = MAX_BD_COUNT, + .nb_min = MIN_BD_COUNT, + .nb_align = BD_ALIGN, + .nb_seg_max = ENETC4_MAX_SEGS, + .nb_mtu_seg_max = ENETC4_MAX_SEGS, + }; + dev_info->tx_desc_lim = (struct rte_eth_desc_lim) { + .nb_max = MAX_BD_COUNT, + .nb_min = MIN_BD_COUNT, + .nb_align = BD_ALIGN, + .nb_seg_max = ENETC4_MAX_SEGS, + .nb_mtu_seg_max = ENETC4_MAX_SEGS, + }; + dev_info->max_rx_queues = hw->max_rx_queues; + dev_info->max_tx_queues = hw->max_tx_queues; + dev_info->max_rx_pktlen = ENETC4_MAC_MAXFRM_SIZE; dev_info->max_mtu = dev_info->max_rx_pktlen - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN); dev_info->max_mac_addrs = ENETC4_MAC_ENTRIES; - dev_info->rx_offload_capa |= dev_vf_rx_offloads_sup; + dev_info->rx_offload_capa = dev_rx_offloads_sup; + dev_info->tx_offload_capa = dev_tx_offloads_sup; + dev_info->flow_type_rss_offloads = ENETC_RSS_OFFLOAD_ALL; return 0; } + int enetc4_vf_dev_stop(struct rte_eth_dev *dev __rte_unused) { diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index 94177bb..e4f5608 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -149,54 +149,64 @@ enetc_xmit_pkts_nc(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) { - struct enetc_swbd *tx_swbd; - int i, start, bds_to_use; - struct enetc_tx_bd *txbd; struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue; - unsigned int buflen, j; + int i, start, bds_to_use, bd_count; + struct enetc_tx_bd *txbd; + struct rte_mbuf *seg; + uint16_t seg_len, segs_per_pkt; + bool is_first_seg; + unsigned int j; uint8_t *data; i = tx_ring->next_to_use; - bds_to_use = enetc_bd_unused(tx_ring); - if (bds_to_use < nb_pkts) - nb_pkts = bds_to_use; + bd_count = tx_ring->bd_count; start = 0; - while (nb_pkts--) { - tx_ring->q_swbd[i].buffer_addr = tx_pkts[start]; + while (start < nb_pkts) { + seg = tx_pkts[start]; + segs_per_pkt = seg->nb_segs; - buflen = rte_pktmbuf_pkt_len(tx_ring->q_swbd[i].buffer_addr); - data = rte_pktmbuf_mtod(tx_ring->q_swbd[i].buffer_addr, void *); - for (j = 0; j <= buflen; j += RTE_CACHE_LINE_SIZE) - dcbf(data + j); + if (bds_to_use < segs_per_pkt) + break; - txbd = ENETC_TXBD(*tx_ring, i); - txbd->flags = 0; - if (tx_ring->q_swbd[i].buffer_addr->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK) - enetc4_tx_offload_checksum(tx_ring->q_swbd[i].buffer_addr, txbd); + 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 *); + + /* Flush payload to PoC so HW DMA reads the correct data. */ + for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE) + dcbf(data + j); + /* Cover the last byte of an unaligned buffer. */ + 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 = tx_pkts[start]; + 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; + } - tx_swbd = &tx_ring->q_swbd[i]; - txbd->frm_len = buflen; - txbd->buf_len = txbd->frm_len; - txbd->addr = (uint64_t)(uintptr_t) - rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova + - tx_swbd->buffer_addr->data_off); + /* Set the frame-last flag on the final BD of this packet. */ txbd->flags |= ENETC4_TXBD_FLAGS_F; - i++; start++; - if (unlikely(i == tx_ring->bd_count)) - i = 0; } - /* we're only cleaning up the Tx ring here, on the assumption that - * software is slower than hardware and hardware completed sending - * older frames out by now. - * We're also cleaning up the ring before kicking off Tx for the new - * batch to minimize chances of contention on the Tx ring - */ enetc_clean_tx_ring(tx_ring); - tx_ring->next_to_use = i; enetc_wr_reg(tx_ring->tcir, i); return start; @@ -501,38 +511,63 @@ 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; uint32_t bd_status; uint8_t *data; uint32_t j; + struct rte_mbuf *seg; + uint16_t data_len; /* next descriptor to process */ i = rx_ring->next_to_clean; - /* next descriptor to process */ rxbd = ENETC_RXBD(*rx_ring, i); - cleaned_cnt = enetc_bd_unused(rx_ring); rx_swbd = &rx_ring->q_swbd[i]; + /* Restore partial multi-segment chain from a previous burst. */ + first_seg = rx_ring->pkt_first_seg; + cur_seg = rx_ring->pkt_last_seg; + while (likely(rx_frm_cnt < work_limit)) { rxbd_temp = *rxbd; bd_status = rte_le_to_cpu_32(rxbd_temp.r.lstatus); - if (!bd_status) + /* LSTATUS_R indicates this BD has been written by HW */ + if (!(bd_status & ENETC_RXBD_LSTATUS_R)) break; if (rxbd_temp.r.error) rx_ring->ierrors++; - rx_swbd->buffer_addr->pkt_len = rxbd_temp.r.buf_len - - rx_ring->crc_len; - rx_swbd->buffer_addr->data_len = rx_swbd->buffer_addr->pkt_len; - rx_swbd->buffer_addr->hash.rss = rxbd_temp.r.rss_hash; - enetc_dev_rx_parse(rx_swbd->buffer_addr, - rxbd_temp.r.parse_summary); + 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; + enetc_dev_rx_parse(first_seg, rxbd_temp.r.parse_summary); + first_seg->hash.rss = rxbd_temp.r.rss_hash; + } else { + first_seg->pkt_len += data_len; + first_seg->nb_segs++; + cur_seg->next = seg; + cur_seg = seg; + } - data = rte_pktmbuf_mtod(rx_swbd->buffer_addr, void *); - for (j = 0; j <= rx_swbd->buffer_addr->pkt_len; j += RTE_CACHE_LINE_SIZE) + /* Invalidate packet data cache lines so CPU reads HW-written data. */ + data = rte_pktmbuf_mtod(seg, void *); + for (j = 0; j < data_len; j += RTE_CACHE_LINE_SIZE) dccivac(data + j); + dccivac(data + (data_len - 1)); + + if (bd_status & ENETC_RXBD_LSTATUS_F) { + seg->next = NULL; + first_seg->pkt_len -= rx_ring->crc_len; + rx_pkts[rx_frm_cnt] = first_seg; + rx_frm_cnt++; + first_seg = NULL; + } - rx_pkts[rx_frm_cnt] = rx_swbd->buffer_addr; cleaned_cnt++; rx_swbd++; i++; @@ -541,9 +576,11 @@ enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring, rx_swbd = &rx_ring->q_swbd[i]; } rxbd = ENETC_RXBD(*rx_ring, i); - rx_frm_cnt++; } + /* Save partial chain for the next burst if frame is incomplete. */ + rx_ring->pkt_first_seg = first_seg; + rx_ring->pkt_last_seg = cur_seg; rx_ring->next_to_clean = i; enetc_refill_rx_ring(rx_ring, cleaned_cnt); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 6/9] net/enetc: add option to disable VSI messaging 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (4 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 5/9] net/enetc: support scatter-gather Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay Gagandeep Singh ` (3 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Gagandeep Singh Add devarg 'enetc4_vsi_disable' to allow disabling features dependent on VSI-PSI messaging. This is useful for testing DPDK with a PF driver that does not support VSI-PSI messages. When the devarg is present, a reduced ops table (enetc4_vf_ops_no_vsi_m) is used that replaces link_update with a no-op stub and omits MAC/VLAN filter ops that require VSI msgs. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- doc/guides/rel_notes/release_26_07.rst | 2 + drivers/net/enetc/enetc4_vf.c | 61 ++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index f900145..783ad16 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -191,6 +191,8 @@ New Features * Added support for ESP packet type in packet parsing. * Added scatter-gather support for ENETC4 PFs and VFs. + * Added devargs option ``enetc4_vsi_disable`` to disable VSI-PSI + messaging. Removed Items ------------- diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index 9dc4e1d..44c0dc0 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -3,11 +3,14 @@ */ #include <stdbool.h> +#include <rte_kvargs.h> #include <rte_random.h> #include <dpaax_iova_table.h> #include "enetc_logs.h" #include "enetc.h" +#define ENETC4_VSI_DISABLE "enetc4_vsi_disable" + #define ENETC_CRC_TABLE_SIZE 256 #define ENETC_POLY 0x1021 #define ENETC_CRC_INIT 0xffff @@ -687,6 +690,13 @@ enetc4_vf_get_link_speed(struct rte_eth_dev *dev, struct enetc_psi_reply_msg *re return err; } +static int +enetc4_vf_link_update_dummy(struct rte_eth_dev *dev __rte_unused, + int wait_to_complete __rte_unused) +{ + return 0; +} + static int enetc4_vf_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused) { @@ -1148,6 +1158,27 @@ static const struct rte_pci_id pci_vf_id_enetc4_map[] = { }; /* Features supported by this driver */ +/* ops table used when VSI messaging is disabled */ +static const struct eth_dev_ops enetc4_vf_ops_no_vsi_m = { + .dev_configure = enetc4_dev_configure, + .dev_start = enetc4_vf_dev_start, + .dev_stop = enetc4_vf_dev_stop, + .dev_close = enetc4_dev_close, + .stats_get = enetc4_vf_stats_get, + .dev_infos_get = enetc4_vf_dev_infos_get, + .mtu_set = enetc4_vf_mtu_set, + .link_update = enetc4_vf_link_update_dummy, + .rx_queue_setup = enetc4_rx_queue_setup, + .rx_queue_start = enetc4_rx_queue_start, + .rx_queue_stop = enetc4_rx_queue_stop, + .rx_queue_release = enetc4_rx_queue_release, + .tx_queue_setup = enetc4_tx_queue_setup, + .tx_queue_start = enetc4_tx_queue_start, + .tx_queue_stop = enetc4_tx_queue_stop, + .tx_queue_release = enetc4_tx_queue_release, + .dev_supported_ptypes_get = enetc4_supported_ptypes_get, +}; + static const struct eth_dev_ops enetc4_vf_ops = { .dev_configure = enetc4_dev_configure, .dev_start = enetc4_vf_dev_start, @@ -1283,7 +1314,28 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) struct enetc_hw *enetc_hw = &hw->hw; PMD_INIT_FUNC_TRACE(); - eth_dev->dev_ops = &enetc4_vf_ops; + + /* check if VSI messaging should be disabled via devarg */ + if (eth_dev->device->devargs) { + struct rte_kvargs *kvlist; + + kvlist = rte_kvargs_parse(eth_dev->device->devargs->args, + NULL); + if (kvlist) { + if (rte_kvargs_count(kvlist, ENETC4_VSI_DISABLE) != 0) { + ENETC_PMD_NOTICE("VSI messaging disabled by devarg"); + eth_dev->dev_ops = &enetc4_vf_ops_no_vsi_m; + } else { + eth_dev->dev_ops = &enetc4_vf_ops; + } + rte_kvargs_free(kvlist); + } else { + eth_dev->dev_ops = &enetc4_vf_ops; + } + } else { + eth_dev->dev_ops = &enetc4_vf_ops; + } + enetc4_dev_hw_init(eth_dev); si_cap = enetc_rd(enetc_hw, ENETC_SICAPR0); @@ -1304,8 +1356,9 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) ENETC_PMD_DEBUG("port_id %d vendorID=0x%x deviceID=0x%x", eth_dev->data->port_id, pci_dev->id.vendor_id, pci_dev->id.device_id); - /* update link */ - enetc4_vf_link_update(eth_dev, 0); + /* update link if VSI messaging is enabled */ + if (eth_dev->dev_ops == &enetc4_vf_ops) + enetc4_vf_link_update(eth_dev, 0); return 0; } @@ -1389,4 +1442,6 @@ static struct rte_pci_driver rte_enetc4_vf_pmd = { RTE_PMD_REGISTER_PCI(net_enetc4_vf, rte_enetc4_vf_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4_vf, pci_vf_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4_vf, "* igb_uio | uio_pci_generic"); +RTE_PMD_REGISTER_PARAM_STRING(net_enetc4_vf, + ENETC4_VSI_DISABLE "=<any>"); RTE_LOG_REGISTER_DEFAULT(enetc4_vf_logtype_pmd, NOTICE); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (5 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 6/9] net/enetc: add option to disable VSI messaging Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 8/9] net/enetc: set user configurable priority to TX rings Gagandeep Singh ` (2 subsequent siblings) 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Gagandeep Singh Add two new devargs for ENETC4 VF: - enetc4_vsi_timeout: VSI-PSI message wait timeout (iteration count) - enetc4_vsi_delay: VSI-PSI message wait delay in microseconds Store the values in struct enetc_eth_hw and use them in enetc4_msg_vsi_send() instead of the hardcoded defaults. Fall back to ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE / ENETC4_DEF_VSI_WAIT_DELAY_UPDATE when not set. Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- doc/guides/rel_notes/release_26_07.rst | 2 + drivers/net/enetc/enetc.h | 2 + drivers/net/enetc/enetc4_vf.c | 66 +++++++++++++++++++------- 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 783ad16..192623d 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -193,6 +193,8 @@ New Features * Added scatter-gather support for ENETC4 PFs and VFs. * Added devargs option ``enetc4_vsi_disable`` to disable VSI-PSI messaging. + * Added devargs options ``enetc4_vsi_timeout`` and ``enetc4_vsi_delay`` + for VSI-PSI messaging timeout and delay. Removed Items ------------- diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 01da898..80844e9 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -112,6 +112,8 @@ struct enetc_eth_hw { uint32_t num_rss; uint32_t max_rx_queues; uint32_t max_tx_queues; + uint32_t vsi_timeout; /* VSI-PSI message wait timeout (iterations) */ + uint32_t vsi_delay; /* VSI-PSI message wait delay (us) */ }; /* diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index 44c0dc0..d78e08e 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -10,6 +10,8 @@ #include "enetc.h" #define ENETC4_VSI_DISABLE "enetc4_vsi_disable" +#define ENETC4_VSI_TIMEOUT "enetc4_vsi_timeout" +#define ENETC4_VSI_DELAY "enetc4_vsi_delay" #define ENETC_CRC_TABLE_SIZE 256 #define ENETC_POLY 0x1021 @@ -262,10 +264,13 @@ enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw) } static int -enetc4_msg_vsi_send(struct enetc_hw *enetc_hw, struct enetc_msg_swbd *msg) +enetc4_msg_vsi_send(struct enetc_eth_hw *hw, struct enetc_msg_swbd *msg) { - int timeout = ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE; - int delay_us = ENETC4_DEF_VSI_WAIT_DELAY_UPDATE; + struct enetc_hw *enetc_hw = &hw->hw; + int timeout = hw->vsi_timeout ? (int)hw->vsi_timeout : + ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE; + int delay_us = hw->vsi_delay ? (int)hw->vsi_delay : + ENETC4_DEF_VSI_WAIT_DELAY_UPDATE; uint8_t class_id = 0; int err = 0; int vsimsgsr; @@ -382,7 +387,7 @@ enetc4_vf_set_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *addr) ENETC_CMD_ID_SET_PRIMARY_MAC, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -426,7 +431,6 @@ static int enetc4_vf_promisc_send_message(struct rte_eth_dev *dev, bool promisc_en) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_cmd_set_promisc *cmd; struct enetc_msg_swbd *msg; uint32_t msg_size; @@ -466,7 +470,7 @@ enetc4_vf_promisc_send_message(struct rte_eth_dev *dev, bool promisc_en) ENETC_CMD_ID_SET_MAC_PROMISCUOUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -483,7 +487,6 @@ static int enetc4_vf_allmulti_send_message(struct rte_eth_dev *dev, bool mc_promisc) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_cmd_set_promisc *cmd; struct enetc_msg_swbd *msg; uint32_t msg_size; @@ -524,7 +527,7 @@ enetc4_vf_allmulti_send_message(struct rte_eth_dev *dev, bool mc_promisc) ENETC_CMD_ID_SET_MAC_PROMISCUOUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -630,7 +633,7 @@ enetc4_vf_get_link_status(struct rte_eth_dev *dev, struct enetc_psi_reply_msg *r ENETC_CMD_ID_GET_LINK_STATUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -676,7 +679,7 @@ enetc4_vf_get_link_speed(struct rte_eth_dev *dev, struct enetc_psi_reply_msg *re ENETC_CMD_ID_GET_LINK_SPEED, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -819,7 +822,6 @@ static int enetc4_vf_vlan_promisc(struct rte_eth_dev *dev, bool promisc_en) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_cmd_set_vlan_promisc *cmd; struct enetc_msg_swbd *msg; uint32_t msg_size; @@ -858,7 +860,7 @@ enetc4_vf_vlan_promisc(struct rte_eth_dev *dev, bool promisc_en) ENETC_CMD_ID_SET_VLAN_PROMISCUOUS, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -921,7 +923,7 @@ enetc4_vf_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *addr, ENETC_MSG_ADD_EXACT_MAC_ENTRIES, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -1021,7 +1023,7 @@ static int enetc4_vf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, } /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) { ENETC_PMD_ERR("VSI message send error"); goto end; @@ -1104,7 +1106,6 @@ static int enetc4_vf_link_register_notif(struct rte_eth_dev *dev, bool enable) { struct enetc_eth_hw *hw = ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct enetc_hw *enetc_hw = &hw->hw; struct enetc_msg_swbd *msg; struct rte_eth_link link; uint32_t msg_size; @@ -1138,7 +1139,7 @@ enetc4_vf_link_register_notif(struct rte_eth_dev *dev, bool enable) cmd, 0, 0, 0); /* send the command and wait */ - err = enetc4_msg_vsi_send(enetc_hw, msg); + err = enetc4_msg_vsi_send(hw, msg); if (err) ENETC_PMD_ERR("VSI msg error for link status notification"); @@ -1322,12 +1323,41 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) kvlist = rte_kvargs_parse(eth_dev->device->devargs->args, NULL); if (kvlist) { + const char *val; + if (rte_kvargs_count(kvlist, ENETC4_VSI_DISABLE) != 0) { ENETC_PMD_NOTICE("VSI messaging disabled by devarg"); eth_dev->dev_ops = &enetc4_vf_ops_no_vsi_m; } else { eth_dev->dev_ops = &enetc4_vf_ops; } + + /* parse optional VSI-PSI timeout devarg */ + val = rte_kvargs_get(kvlist, ENETC4_VSI_TIMEOUT); + if (val) { + errno = 0; + hw->vsi_timeout = (uint32_t)strtoul(val, NULL, 0); + if (errno != 0 || hw->vsi_timeout == 0) { + ENETC_PMD_ERR("Invalid VSI Timeout value = %u", + hw->vsi_timeout); + return -1; + } + ENETC_PMD_NOTICE("VSI timeout set to %u", hw->vsi_timeout); + } + + /* parse optional VSI-PSI delay devarg */ + val = rte_kvargs_get(kvlist, ENETC4_VSI_DELAY); + if (val) { + errno = 0; + hw->vsi_delay = (uint32_t)strtoul(val, NULL, 0); + if (errno != 0 || hw->vsi_delay == 0) { + ENETC_PMD_ERR("Invalid VSI Delay value = %u", + hw->vsi_delay); + return -1; + } + ENETC_PMD_NOTICE("VSI delay set to %u us", hw->vsi_delay); + } + rte_kvargs_free(kvlist); } else { eth_dev->dev_ops = &enetc4_vf_ops; @@ -1443,5 +1473,7 @@ RTE_PMD_REGISTER_PCI(net_enetc4_vf, rte_enetc4_vf_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4_vf, pci_vf_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4_vf, "* igb_uio | uio_pci_generic"); RTE_PMD_REGISTER_PARAM_STRING(net_enetc4_vf, - ENETC4_VSI_DISABLE "=<any>"); + ENETC4_VSI_DISABLE "=<any> " + ENETC4_VSI_TIMEOUT "=<uint> " + ENETC4_VSI_DELAY "=<uint>"); RTE_LOG_REGISTER_DEFAULT(enetc4_vf_logtype_pmd, NOTICE); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 8/9] net/enetc: set user configurable priority to TX rings 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (6 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 9/9] net/enetc4: add cacheable BD ring support with SW cache maintenance Gagandeep Singh 2026-06-22 15:06 ` [PATCH v2 0/9] ENETC driver related changes series Stephen Hemminger 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Vanshika Shukla From: Vanshika Shukla <vanshika.shukla@nxp.com> Add devarg 'enetc4_txq_prior' to allow per-queue TX ring priority configuration. The value is a '|'-separated list of TBMR priority bits, one per TX queue (e.g. 'enetc4_txq_prior=1|2|3'). The configuration accepts values only up to the maximum supported TX queues. Any additional values beyond this supported range are discarded. Store the parsed priorities in hw->txq_prior and apply them in enetc4_tx_queue_setup() when enabling the ring. Signed-off-by: Vanshika Shukla <vanshika.shukla@nxp.com> --- doc/guides/rel_notes/release_26_07.rst | 1 + drivers/net/enetc/enetc.h | 1 + drivers/net/enetc/enetc4_ethdev.c | 81 +++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 192623d..495eba0 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -195,6 +195,7 @@ New Features messaging. * Added devargs options ``enetc4_vsi_timeout`` and ``enetc4_vsi_delay`` for VSI-PSI messaging timeout and delay. + * Added devargs option ``enetc4_txq_prior`` to set TX queues priorities. Removed Items ------------- diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index 80844e9..c12597b 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -114,6 +114,7 @@ struct enetc_eth_hw { uint32_t max_tx_queues; uint32_t vsi_timeout; /* VSI-PSI message wait timeout (iterations) */ uint32_t vsi_delay; /* VSI-PSI message wait delay (us) */ + uint32_t *txq_prior; /* per-queue TX priority (TBMR priority bits) */ }; /* diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index ad1ef4d..7e2d665 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -3,6 +3,7 @@ */ #include <stdbool.h> +#include <rte_kvargs.h> #include <rte_random.h> #include <dpaax_iova_table.h> @@ -10,6 +11,67 @@ #include "enetc_logs.h" #include "enetc.h" +#define ENETC4_TXQ_PRIORITIES "enetc4_txq_prior" + +static int +parse_txq_prior(const char *key __rte_unused, const char *value, void *opaque) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)opaque; + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); + char *input_str = strdup(value); + char *str; + uint32_t i = 0; + + if (!input_str) + return -ENOMEM; + + hw->txq_prior = calloc(hw->max_tx_queues, sizeof(uint32_t)); + if (!hw->txq_prior) { + free(input_str); + return -ENOMEM; + } + + str = strtok(input_str, "|"); + while (str != NULL && i < hw->max_tx_queues) { + hw->txq_prior[i++] = (uint32_t)atoi(str); + str = strtok(NULL, "|"); + } + + free(input_str); + return 0; +} + +static int +enetc4_get_devargs(struct rte_eth_dev *dev, const char *key) +{ + struct rte_devargs *devargs = dev->device->devargs; + struct rte_kvargs *kvlist; + + if (!devargs) + return 0; + + kvlist = rte_kvargs_parse(devargs->args, NULL); + if (!kvlist) + return 0; + + if (!rte_kvargs_count(kvlist, key)) { + rte_kvargs_free(kvlist); + return 0; + } + + if (!strcmp(key, ENETC4_TXQ_PRIORITIES)) { + if (rte_kvargs_process(kvlist, key, + parse_txq_prior, (void *)dev) < 0) { + rte_kvargs_free(kvlist); + return 0; + } + } + + rte_kvargs_free(kvlist); + return 0; +} + /* Supported Rx offloads */ static uint64_t dev_rx_offloads_sup = RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | @@ -316,9 +378,14 @@ enetc4_tx_queue_setup(struct rte_eth_dev *dev, data->tx_queues[queue_idx] = tx_ring; tx_ring->tx_deferred_start = tx_conf->tx_deferred_start; if (!tx_conf->tx_deferred_start) { + uint32_t tx_en = ENETC_TBMR_EN; + + /* apply TX queue priority if configured */ + if (priv->hw.txq_prior) + tx_en |= priv->hw.txq_prior[tx_ring->index]; /* enable ring */ enetc4_txbdr_wr(&priv->hw.hw, tx_ring->index, - ENETC_TBMR, ENETC_TBMR_EN); + ENETC_TBMR, tx_en); dev->data->tx_queue_state[tx_ring->index] = RTE_ETH_QUEUE_STATE_STARTED; } else { @@ -1015,6 +1082,8 @@ enetc4_dev_init(struct rte_eth_dev *eth_dev) hw->max_tx_queues = si_cap & ENETC_SICAPR0_BDR_MASK; hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK; + enetc4_get_devargs(eth_dev, ENETC4_TXQ_PRIORITIES); + ENETC_PMD_DEBUG("Max RX queues = %d Max TX queues = %d", hw->max_rx_queues, hw->max_tx_queues); error = enetc4_mac_init(hw, eth_dev); @@ -1041,8 +1110,16 @@ enetc4_dev_init(struct rte_eth_dev *eth_dev) static int enetc4_dev_uninit(struct rte_eth_dev *eth_dev) { + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + PMD_INIT_FUNC_TRACE(); + if (hw->txq_prior) { + free(hw->txq_prior); + hw->txq_prior = NULL; + } + return enetc4_dev_close(eth_dev); } @@ -1071,4 +1148,6 @@ static struct rte_pci_driver rte_enetc4_pmd = { RTE_PMD_REGISTER_PCI(net_enetc4, rte_enetc4_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4, pci_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4, "* vfio-pci"); +RTE_PMD_REGISTER_PARAM_STRING(net_enetc4, + ENETC4_TXQ_PRIORITIES "=<string>"); RTE_LOG_REGISTER_DEFAULT(enetc4_logtype_pmd, NOTICE); -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 9/9] net/enetc4: add cacheable BD ring support with SW cache maintenance 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (7 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 8/9] net/enetc: set user configurable priority to TX rings Gagandeep Singh @ 2026-06-22 11:35 ` Gagandeep Singh 2026-06-22 15:06 ` [PATCH v2 0/9] ENETC driver related changes series Stephen Hemminger 9 siblings, 0 replies; 24+ messages in thread From: Gagandeep Singh @ 2026-06-22 11:35 UTC (permalink / raw) To: dev; +Cc: hemant.agrawal, Gagandeep Singh On non-cache-coherent platforms such as i.MX95, the BD ring memory may be mapped as cacheable (normal memory) while the ENETC hardware DMA engine writes and reads descriptors without CPU cache snooping. SW must therefore perform explicit cache maintenance to keep CPU caches and DDR coherent. TX path (enetc_xmit_pkts_cacheable): - Flush each segment's payload cache lines to PoC (dcbf) before the BD is handed to HW, so HW DMA reads the correct data. - After all BDs for a burst are written, flush the BD cache lines (dcbf, one per 64-byte group of 4 BDs) so HW can read the updated descriptors. RX refill (enetc_refill_rx_ring): - After writing each full 4-BD cache-line group, dcbf that group so HW sees the buffer addresses and cleared lstatus fields. - Flush any partial trailing group before updating the ring tail. RX receive (enetc_recv_pkts_cacheable via enetc_clean_rx_ring_cacheable): - Before reading BD status, dccivac the current BD cache line so stale CPU-cached BD data is discarded and fresh HW-written content is fetched from DDR. - After a BD is consumed, dccivac each payload cache line so the CPU reads the DMA'd packet data, not stale cached bytes. Add a new devarg 'nc=1' that allows selecting the non-cacheable RX/TX ops. When nc=1 is specified: eth_dev->rx_pkt_burst = &enetc_recv_pkts_nc; eth_dev->tx_pkt_burst = &enetc_xmit_pkts_nc; The default (nc not set or nc=0) keeps the cacheable path with SW cache maintenance (dccivac/dcbf): eth_dev->rx_pkt_burst = &enetc_recv_pkts_cacheable; eth_dev->tx_pkt_burst = &enetc_xmit_pkts_cacheable; Usage: --allow 0000:00:01.0,nc=1 Signed-off-by: Gagandeep Singh <g.singh@nxp.com> --- doc/guides/rel_notes/release_26_07.rst | 1 + drivers/net/enetc/enetc.h | 21 ++ drivers/net/enetc/enetc4_ethdev.c | 71 +++++-- drivers/net/enetc/enetc4_vf.c | 35 +++- drivers/net/enetc/enetc_rxtx.c | 278 ++++++++++++++++++++++++- 5 files changed, 388 insertions(+), 18 deletions(-) diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 495eba0..b208229 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -196,6 +196,7 @@ New Features * Added devargs options ``enetc4_vsi_timeout`` and ``enetc4_vsi_delay`` for VSI-PSI messaging timeout and delay. * Added devargs option ``enetc4_txq_prior`` to set TX queues priorities. + * Added devargs option ``nc`` to select non-cacheable RX/TX ops. Removed Items ------------- diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h index c12597b..d3a8b8e 100644 --- a/drivers/net/enetc/enetc.h +++ b/drivers/net/enetc/enetc.h @@ -115,6 +115,7 @@ struct enetc_eth_hw { uint32_t vsi_timeout; /* VSI-PSI message wait timeout (iterations) */ uint32_t vsi_delay; /* VSI-PSI message wait delay (us) */ uint32_t *txq_prior; /* per-queue TX priority (TBMR priority bits) */ + uint8_t nc_mode; /* 1 = non-cacheable BD memory, use _nc ops */ }; /* @@ -315,8 +316,28 @@ 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_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); + +/* + * Cache-maintenance constants for cacheable BD ring mode. + * + * BD = 16 bytes, cache line = 64 bytes => 4 BDs per cache line. + * Every dcbf in enetc_refill_rx_ring() flushes a full 64-byte cache line. + * To ensure each dcbf covers only fully-written BDs the caller + * must pass a count rounded DOWN to a multiple of ENETC_BD_PER_CL so that + * the last partial group is left in cache to be completed and flushed in + * the next call. + */ +#define ENETC_BD_PER_CL (RTE_CACHE_LINE_SIZE / sizeof(union enetc_rx_bd)) +#define ENETC_BD_PER_CL_MASK (ENETC_BD_PER_CL - 1) +/* Round n DOWN to the nearest multiple of ENETC_BD_PER_CL. */ +#define ENETC_BD_ALIGN_DOWN(n) ((n) & ~(unsigned int)ENETC_BD_PER_CL_MASK) + void enetc4_dev_hw_init(struct rte_eth_dev *eth_dev); void enetc_print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr); diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c index 7e2d665..2ddd63d 100644 --- a/drivers/net/enetc/enetc4_ethdev.c +++ b/drivers/net/enetc/enetc4_ethdev.c @@ -12,6 +12,7 @@ #include "enetc.h" #define ENETC4_TXQ_PRIORITIES "enetc4_txq_prior" +#define ENETC4_NC_MEMORY "nc" static int parse_txq_prior(const char *key __rte_unused, const char *value, void *opaque) @@ -42,6 +43,19 @@ parse_txq_prior(const char *key __rte_unused, const char *value, void *opaque) return 0; } +static int +parse_nc(const char *key __rte_unused, const char *value, void *extra_args) +{ + struct rte_eth_dev *dev = extra_args; + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (value && atoi(value) == 1) + hw->nc_mode = 1; + + return 0; +} + static int enetc4_get_devargs(struct rte_eth_dev *dev, const char *key) { @@ -67,6 +81,13 @@ enetc4_get_devargs(struct rte_eth_dev *dev, const char *key) return 0; } } + if (!strcmp(key, ENETC4_NC_MEMORY)) { + if (rte_kvargs_process(kvlist, key, + parse_nc, (void *)dev) < 0) { + rte_kvargs_free(kvlist); + return 0; + } + } rte_kvargs_free(kvlist); return 0; @@ -289,12 +310,14 @@ enetc4_alloc_txbdr(struct enetc_bdr *txr, uint16_t nb_desc) int size; size = nb_desc * sizeof(struct enetc_swbd); - txr->q_swbd = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* 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; - size = nb_desc * sizeof(struct enetc_bdr); - txr->bd_base = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* Allocate the TX BD ring: each BD is struct enetc_tx_bd (16 bytes). */ + size = nb_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; @@ -449,12 +472,14 @@ enetc4_alloc_rxbdr(struct enetc_bdr *rxr, uint16_t nb_desc) int size; size = nb_desc * sizeof(struct enetc_swbd); - rxr->q_swbd = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* 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; - size = nb_desc * sizeof(struct enetc_bdr); - rxr->bd_base = rte_malloc(NULL, size, ENETC_BD_RING_ALIGN); + /* Allocate the RX BD ring: each BD is union enetc_rx_bd (16 bytes). */ + size = nb_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; @@ -489,7 +514,7 @@ enetc4_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring, 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_unused(rx_ring))); + 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); @@ -751,12 +776,17 @@ enetc4_dev_configure(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); - max_len = dev->data->dev_conf.rxmode.mtu + RTE_ETHER_HDR_LEN + - RTE_ETHER_CRC_LEN; - enetc4_port_wr(enetc_hw, ENETC4_PM_MAXFRM(0), ENETC_SET_MAXFRM(max_len)); + /* Port-level register writes are PF-only; skip for VF devices */ + if (hw->device_id != ENETC4_DEV_ID_VF) { + max_len = dev->data->dev_conf.rxmode.mtu + RTE_ETHER_HDR_LEN + + RTE_ETHER_CRC_LEN; + enetc4_port_wr(enetc_hw, ENETC4_PM_MAXFRM(0), + ENETC_SET_MAXFRM(max_len)); - val = ENETC4_MAC_MAXFRM_SIZE | SDU_TYPE_MPDU; - enetc4_port_wr(enetc_hw, ENETC4_PTCTMSDUR(0), val | SDU_TYPE_MPDU); + val = ENETC4_MAC_MAXFRM_SIZE | SDU_TYPE_MPDU; + enetc4_port_wr(enetc_hw, ENETC4_PTCTMSDUR(0), + val | SDU_TYPE_MPDU); + } /* Rx offloads which are enabled by default */ if (dev_rx_offloads_sup & ~rx_offloads) { @@ -778,7 +808,8 @@ enetc4_dev_configure(struct rte_eth_dev *dev) if (rx_offloads & (RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM)) checksum &= ~L4_CKSUM; - enetc4_port_wr(enetc_hw, ENETC4_PARCSCR, checksum); + if (hw->device_id != ENETC4_DEV_ID_VF) + enetc4_port_wr(enetc_hw, ENETC4_PARCSCR, checksum); /* Enable interrupts */ if (hw->device_id == ENETC4_DEV_ID_VF) { @@ -1041,8 +1072,8 @@ enetc4_dev_hw_init(struct rte_eth_dev *eth_dev) ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev); - eth_dev->rx_pkt_burst = &enetc_recv_pkts_nc; - eth_dev->tx_pkt_burst = &enetc_xmit_pkts_nc; + eth_dev->rx_pkt_burst = &enetc_recv_pkts_cacheable; + eth_dev->tx_pkt_burst = &enetc_xmit_pkts_cacheable; /* Retrieving and storing the HW base address of device */ hw->hw.reg = (void *)pci_dev->mem_resource[0].addr; @@ -1082,7 +1113,14 @@ enetc4_dev_init(struct rte_eth_dev *eth_dev) hw->max_tx_queues = si_cap & ENETC_SICAPR0_BDR_MASK; hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK; + hw->nc_mode = 0; enetc4_get_devargs(eth_dev, ENETC4_TXQ_PRIORITIES); + enetc4_get_devargs(eth_dev, ENETC4_NC_MEMORY); + if (hw->nc_mode) { + eth_dev->rx_pkt_burst = &enetc_recv_pkts_nc; + eth_dev->tx_pkt_burst = &enetc_xmit_pkts_nc; + ENETC_PMD_LOG(INFO, "nc=1: using non-cacheable BD ops (_nc)"); + } ENETC_PMD_DEBUG("Max RX queues = %d Max TX queues = %d", hw->max_rx_queues, hw->max_tx_queues); @@ -1149,5 +1187,6 @@ RTE_PMD_REGISTER_PCI(net_enetc4, rte_enetc4_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_enetc4, pci_id_enetc4_map); RTE_PMD_REGISTER_KMOD_DEP(net_enetc4, "* vfio-pci"); RTE_PMD_REGISTER_PARAM_STRING(net_enetc4, - ENETC4_TXQ_PRIORITIES "=<string>"); + ENETC4_TXQ_PRIORITIES "=<string> " + ENETC4_NC_MEMORY "=<int>"); RTE_LOG_REGISTER_DEFAULT(enetc4_logtype_pmd, NOTICE); diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index d78e08e..98435ef 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -12,6 +12,30 @@ #define ENETC4_VSI_DISABLE "enetc4_vsi_disable" #define ENETC4_VSI_TIMEOUT "enetc4_vsi_timeout" #define ENETC4_VSI_DELAY "enetc4_vsi_delay" +#define ENETC4_NC_MEMORY "nc" + +static void +enetc4_vf_get_devarg_nc(struct rte_eth_dev *dev) +{ + struct enetc_eth_hw *hw = + ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_devargs *devargs = dev->device->devargs; + struct rte_kvargs *kvlist; + const char *val; + + if (!devargs) + return; + + kvlist = rte_kvargs_parse(devargs->args, NULL); + if (!kvlist) + return; + + val = rte_kvargs_get(kvlist, ENETC4_NC_MEMORY); + if (val && atoi(val) == 1) + hw->nc_mode = 1; + + rte_kvargs_free(kvlist); +} #define ENETC_CRC_TABLE_SIZE 256 #define ENETC_POLY 0x1021 @@ -1368,6 +1392,14 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev) enetc4_dev_hw_init(eth_dev); + hw->nc_mode = 0; + enetc4_vf_get_devarg_nc(eth_dev); + if (hw->nc_mode) { + eth_dev->rx_pkt_burst = &enetc_recv_pkts_nc; + eth_dev->tx_pkt_burst = &enetc_xmit_pkts_nc; + ENETC_PMD_LOG(INFO, "nc=1: using non-cacheable BD ops (_nc)"); + } + si_cap = enetc_rd(enetc_hw, ENETC_SICAPR0); hw->max_tx_queues = si_cap & ENETC_SICAPR0_BDR_MASK; hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK; @@ -1475,5 +1507,6 @@ RTE_PMD_REGISTER_KMOD_DEP(net_enetc4_vf, "* igb_uio | uio_pci_generic"); RTE_PMD_REGISTER_PARAM_STRING(net_enetc4_vf, ENETC4_VSI_DISABLE "=<any> " ENETC4_VSI_TIMEOUT "=<uint> " - ENETC4_VSI_DELAY "=<uint>"); + ENETC4_VSI_DELAY "=<uint> " + ENETC4_NC_MEMORY "=<int>"); RTE_LOG_REGISTER_DEFAULT(enetc4_vf_logtype_pmd, NOTICE); diff --git a/drivers/net/enetc/enetc_rxtx.c b/drivers/net/enetc/enetc_rxtx.c index e4f5608..2cd74f5 100644 --- a/drivers/net/enetc/enetc_rxtx.c +++ b/drivers/net/enetc/enetc_rxtx.c @@ -26,6 +26,7 @@ enetc_clean_tx_ring(struct enetc_bdr *tx_ring) struct enetc_swbd *tx_swbd, *tx_swbd_base; int i, hwci, bd_count; struct rte_mbuf *m[ENETC_RXBD_BUNDLE]; + struct enetc_tx_bd *txbd; /* we don't need barriers here, we just want a relatively current value * from HW. @@ -51,6 +52,13 @@ enetc_clean_tx_ring(struct enetc_bdr *tx_ring) /* It seems calling rte_pktmbuf_free is wasting a lot of cycles, * make a list and call _free when it's done. */ + /* Clear flags on the reclaimed BD so that dcbf in the + * cacheable TX path never flushes a stale flags_F to memory + * before the new BD fields are fully written. + */ + txbd = ENETC_TXBD(*tx_ring, i); + txbd->flags = 0; + if (tx_frm_cnt == ENETC_RXBD_BUNDLE) { rte_pktmbuf_free_bulk(m, tx_frm_cnt); tx_frm_cnt = 0; @@ -202,7 +210,8 @@ enetc_xmit_pkts_nc(void *tx_queue, } /* Set the frame-last flag on the final BD of this packet. */ - txbd->flags |= ENETC4_TXBD_FLAGS_F; + if (likely(txbd)) + txbd->flags |= ENETC4_TXBD_FLAGS_F; start++; } @@ -217,6 +226,7 @@ enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) { struct enetc_swbd *rx_swbd; union enetc_rx_bd *rxbd; + union enetc_rx_bd *grp_start_rxbd; int i, j, k = ENETC_RXBD_BUNDLE; struct rte_mbuf *m[ENETC_RXBD_BUNDLE]; struct rte_mempool *mb_pool; @@ -225,6 +235,7 @@ enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) 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++) { /* bulk alloc for the next up to 8 BDs */ if (k == ENETC_RXBD_BUNDLE) { @@ -246,12 +257,29 @@ enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) i++; k++; if (unlikely(i == rx_ring->bd_count)) { + /* + * Ring wrap: flush the current partial or full group + * before resetting the pointer to index 0. + */ + 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-BD group (one cache line). + * Flush it to PoC so HW sees the updated descriptors. + */ + 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; @@ -604,3 +632,251 @@ enetc_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts, return enetc_clean_rx_ring(rx_ring, rx_pkts, nb_pkts); } + +/* --- Cacheable BD ring TX path with SW cache maintenance (dcbf) --- */ + +uint16_t +enetc_xmit_pkts_cacheable(void *tx_queue, + struct rte_mbuf **tx_pkts, + uint16_t nb_pkts) +{ + int i, start, bds_to_use; + struct enetc_tx_bd *txbd; + 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; + + /* + * Remember the first BD index of this batch so we can flush the + * BD cache lines to PoC after all descriptors are written. + */ + first_bd_idx = i; + + while (start < nb_pkts) { + seg = tx_pkts[start]; + segs_per_pkt = seg->nb_segs; + + 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 *); + + /* + * Flush packet data cache lines to PoC so HW DMA + * reads the correct payload from memory. + */ + for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE) + dcbf(data + j); + + /* + * Cover the last byte of an unaligned buffer to + * ensure the full payload is clean to the Point of + * Coherency. + */ + 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; + } + + /* + * Set the frame-last flag on the final BD of this packet. + * This is the last write to the BD group; the cache flush + * below will push all BDs to memory afterwards. + */ + if (likely(txbd)) + txbd->flags |= ENETC4_TXBD_FLAGS_F; + start++; + } + + /* + * Flush TX BDs to PoC so HW (non-cache-coherent i.MX95) can read + * the descriptors from memory. TX BDs are 16 B each; 4 BDs share + * one 64-byte cache line. Walk from the cache-line-aligned start + * of first_bd_idx to just past the last written BD, one dcbf per + * cache line. + * + * The flush must happen AFTER all BD fields (including flags_F) are + * written, so HW never sees a partial descriptor. + */ + 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; +} + +/* --- Cacheable BD ring RX path with SW cache maintenance (dccivac) --- */ + +static int +enetc_clean_rx_ring_cacheable(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; + struct rte_mbuf *first_seg, *cur_seg; + uint32_t bd_status; + uint8_t *data; + uint32_t j; + struct rte_mbuf *seg; + uint16_t data_len; + + 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]; + + /* Restore partial multi-segment chain from a previous burst. */ + first_seg = rx_ring->pkt_first_seg; + cur_seg = rx_ring->pkt_last_seg; + + /* + * On i.MX95 the BD ring is in cacheable hugepage memory but the + * platform is non-cache-coherent. HW writes RX BDs to DDR + * without snooping the CPU cache, so stale cached copies of BD + * status fields must be discarded before the CPU reads them. + * + * Ideal instruction: DC IVAC (invalidate only, no writeback). + * ARM64 constraint: DC IVAC requires EL1 privilege; executing it + * from EL0 (DPDK userspace) raises a fault. The only EL0-safe + * cache maintenance instruction that invalidates is DC CIVAC + * (clean + invalidate, dccivac). + * + * Safety of using dccivac here: + * enetc_refill_rx_ring() issues dcbf() on every BD group before + * returning ownership to HW. After dcbf the CPU cache lines are + * marked clean (no dirty data). When dccivac runs, the "clean" + * phase finds nothing dirty to write back, so it behaves as a + * pure invalidate - exactly what we need. + * + * Granularity: BD = 16 B, cache line = 64 B, so one dccivac + * covers exactly 4 BDs. Invalidate at each 4-BD boundary. + */ + dccivac((void *)ENETC_RXBD(*rx_ring, + (i & ~(int)ENETC_BD_PER_CL_MASK))); + + while (likely(rx_frm_cnt < work_limit)) { + bd_status = rte_le_to_cpu_32(rxbd->r.lstatus); + + if (!(bd_status & ENETC_RXBD_LSTATUS_R)) + break; + if (rxbd->r.error) + rx_ring->ierrors++; + + seg = rx_swbd->buffer_addr; + data_len = rte_le_to_cpu_16(rxbd->r.buf_len); + seg->data_len = data_len; + if (!first_seg) { + first_seg = seg; + cur_seg = seg; + first_seg->pkt_len = data_len; + enetc_dev_rx_parse(first_seg, + rxbd->r.parse_summary); + first_seg->hash.rss = rxbd->r.rss_hash; + } else { + first_seg->pkt_len += data_len; + first_seg->nb_segs++; + cur_seg->next = seg; + cur_seg = seg; + } + + /* + * Invalidate packet data cache lines so the CPU reads the + * payload that HW DMA'd into memory, not stale cached bytes. + */ + 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. */ + dccivac(data + (data_len - 1)); + + if (bd_status & ENETC_RXBD_LSTATUS_F) { + seg->next = NULL; + first_seg->pkt_len -= rx_ring->crc_len; + rx_pkts[rx_frm_cnt] = first_seg; + rx_frm_cnt++; + first_seg = NULL; + } + + cleaned_cnt++; + rx_swbd++; + i++; + 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-BD (cache-line) boundary: invalidate the new + * group so the next four 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); + } + + /* Save partial chain for the next burst if frame is incomplete. */ + rx_ring->pkt_first_seg = first_seg; + rx_ring->pkt_last_seg = cur_seg; + rx_ring->next_to_clean = i; + enetc_refill_rx_ring(rx_ring, ENETC_BD_ALIGN_DOWN(cleaned_cnt)); + + return rx_frm_cnt; +} + +uint16_t +enetc_recv_pkts_cacheable(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_cacheable(rx_ring, rx_pkts, nb_pkts); +} -- 2.25.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v2 0/9] ENETC driver related changes series 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh ` (8 preceding siblings ...) 2026-06-22 11:35 ` [PATCH v2 9/9] net/enetc4: add cacheable BD ring support with SW cache maintenance Gagandeep Singh @ 2026-06-22 15:06 ` Stephen Hemminger 9 siblings, 0 replies; 24+ messages in thread From: Stephen Hemminger @ 2026-06-22 15:06 UTC (permalink / raw) To: Gagandeep Singh; +Cc: dev, hemant.agrawal On Mon, 22 Jun 2026 17:05:08 +0530 Gagandeep Singh <g.singh@nxp.com> wrote: > V2 changes: > - Fixed an un-used variable compilation issue reported on fedora:43-gcc-minsize > - Fixed various AI reported issues: > - Release notes updated for all new devargs > - enect4.ini features doc updated for scattered RX. > - removed Not required RTE_PTYPE_UNKNOWN. > - Fixed mid-frame mbuf leak in SG case. > - Enabled SG for enetc4 PF also. > - move to calloc from rte_zmalloc in parse_txq_prior(). > - added vaidation checks on strdup, strtoul. > - added NC devargs to use cacheable ops conditionally. > - removed dead code like bd_base_p etc. > - Fixed rte_cpu_to_le_16() conversion on flags and combined > all flags related patches in one patch. > - Fixed memory leak issue due to TXQ priority patch. > - There were some false positives, I have ignored them: > Race condition on flags field: > clean_tx_ring only touches HW-completed BDs (next_to_clean→hwci), > never newly-submitted BDs; doorbell hasn't fired yet. > Missing dcbf in clean_tx_ring: > DPDK is single-threaded per queue; TX path always overwrites > flags completely before dcbf. > TX dcbf granularity with wrap: > Safe (AI admits it). > RX refill flush at wrap: > In-loop dcbf at i & mask == 0 already flushes aligned groups; > trailing flush only needed for partial groups. > RX reading before invalidate: > dccivac precedes the read for every group in the loop > > Gagandeep Singh (7): > net/enetc: fix TX BD structure > net/enetc: fix queue initialization > net/enetc: support ESP packet type in packet parsing > net/enetc: update random MAC generation code > net/enetc: add option to disable VSI messaging > net/enetc: add devargs to control VSI-PSI timeout and delay > net/enetc4: add cacheable BD ring support with SW cache maintenance > > Vanshika Shukla (2): > net/enetc: support scatter-gather > net/enetc: set user configurable priority to TX rings > > doc/guides/nics/features/enetc4.ini | 1 + > doc/guides/rel_notes/release_26_07.rst | 10 + > drivers/net/enetc/base/enetc_hw.h | 13 +- > drivers/net/enetc/enetc.h | 31 +- > drivers/net/enetc/enetc4_ethdev.c | 172 ++++++++-- > drivers/net/enetc/enetc4_vf.c | 204 ++++++++++-- > drivers/net/enetc/enetc_ethdev.c | 25 +- > drivers/net/enetc/enetc_rxtx.c | 430 ++++++++++++++++++++++--- > 8 files changed, 768 insertions(+), 118 deletions(-) > Better but still had some AI feedback if I asked it for more complete review. Agree that putting new devargs in doc is needed. Error ===== [PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay drivers/net/enetc/enetc4_vf.c, enetc4_vf_dev_init() kvlist is leaked on the two invalid-value error paths. It is allocated by rte_kvargs_parse() (line 1347) and only freed at line 1385, but both return -1; /* invalid VSI Timeout, line 1367 */ return -1; /* invalid VSI Delay, line 1380 */ return before that free. A malformed enetc4_vsi_timeout= or enetc4_vsi_delay= leaks the kvargs structure on every probe. Free before returning, e.g.: if (errno != 0 || hw->vsi_timeout == 0) { ENETC_PMD_ERR("Invalid VSI Timeout value = %u", hw->vsi_timeout); rte_kvargs_free(kvlist); return -1; } (same for the delay path), or restructure with a goto. Warning ======= Series (patches 6-9) The new runtime devargs - enetc4_vsi_disable, enetc4_vsi_timeout, enetc4_vsi_delay, enetc4_txq_prior, and nc - are registered via RTE_PMD_REGISTER_PARAM_STRING and noted in the release notes, but doc/guides/nics/enetc4.rst has no Runtime Configuration section describing them. Convention is to document devargs in the NIC guide so users can find the syntax (e.g. the nc=1 / 'a|b|c' priority list formats are non-obvious). Info ==== [PATCH v2 5/9] and [PATCH v2 9/9] - RX multi-segment reassembly In enetc_clean_rx_ring_nc() and enetc_clean_rx_ring_cacheable(), on the frame-last BD: first_seg->pkt_len -= rx_ring->crc_len; reduces pkt_len but leaves the final segment's data_len unchanged, so pkt_len != sum(data_len) when crc_len is non-zero. The old single-segment path kept them equal (pkt_len = data_len = buf_len - crc_len). This is currently unreachable: enetc4 does not advertise RTE_ETH_RX_OFFLOAD_KEEP_CRC, so crc_len is always 0 and the subtraction is a no-op. Flagging only so the asymmetry is on record if KEEP_CRC is ever added - at that point the last segment's data_len would need the same adjustment (and the CRC may straddle the last two segments). ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-06-22 15:06 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-19 18:44 [PATCH 00/10] NXP ENETC driver related changes Gagandeep Singh 2026-06-19 18:44 ` [PATCH 01/10] net/enetc: fix TX BD structure Gagandeep Singh 2026-06-19 18:44 ` [PATCH 02/10] net/enetc: fix TX BDs flag overwrite issue Gagandeep Singh 2026-06-19 18:44 ` [PATCH 03/10] net/enetc: fix queue initialization Gagandeep Singh 2026-06-19 18:44 ` [PATCH 04/10] net/enetc: support ESP packet type in packet parsing Gagandeep Singh 2026-06-19 18:44 ` [PATCH 05/10] net/enetc: update random MAC generation code Gagandeep Singh 2026-06-19 18:44 ` [PATCH 06/10] net/enetc: support scatter-gather Gagandeep Singh 2026-06-19 18:44 ` [PATCH 07/10] net/enetc: add option to disable VSI messaging Gagandeep Singh 2026-06-19 18:44 ` [PATCH 08/10] net/enetc: add devargs to control VSI-PSI timeout and delay Gagandeep Singh 2026-06-19 18:44 ` [PATCH 09/10] net/enetc: set user configurable priority to TX rings Gagandeep Singh 2026-06-19 18:44 ` [PATCH 10/10] net/enetc4: add cacheable BD ring support with SW cache maintenance Gagandeep Singh 2026-06-19 21:43 ` [PATCH 00/10] NXP ENETC driver related changes Stephen Hemminger 2026-06-22 11:36 ` Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 0/9] ENETC driver related changes series Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 1/9] net/enetc: fix TX BD structure Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 2/9] net/enetc: fix queue initialization Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 3/9] net/enetc: support ESP packet type in packet parsing Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 4/9] net/enetc: update random MAC generation code Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 5/9] net/enetc: support scatter-gather Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 6/9] net/enetc: add option to disable VSI messaging Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 8/9] net/enetc: set user configurable priority to TX rings Gagandeep Singh 2026-06-22 11:35 ` [PATCH v2 9/9] net/enetc4: add cacheable BD ring support with SW cache maintenance Gagandeep Singh 2026-06-22 15:06 ` [PATCH v2 0/9] ENETC driver related changes series Stephen Hemminger
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox