* RE: [PATCH v2 0/9] ENETC driver related changes series
From: Gagandeep Singh @ 2026-06-23 6:02 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev@dpdk.org, Hemant Agrawal
In-Reply-To: <20260622080615.6f397799@phoenix.local>
Hi,
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Monday, June 22, 2026 8:36 PM
> To: Gagandeep Singh <G.Singh@nxp.com>
> Cc: dev@dpdk.org; Hemant Agrawal <hemant.agrawal@nxp.com>
> Subject: Re: [PATCH v2 0/9] ENETC driver related changes series
>
> 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.
>
>
Fixed in v3.
> 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).
>
Documentation is done in v3
> 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).
I have noted it down, will submit the changes as a separate patch when
We will support KEEP_CRC in enetc4.
^ permalink raw reply
* [PATCH v3 9/9] net/enetc4: add cacheable BD ring support with SW cache maintenance
From: Gagandeep Singh @ 2026-06-23 6:00 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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/nics/enetc4.rst | 10 +
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 ++++++++++++++++++++++++-
6 files changed, 398 insertions(+), 18 deletions(-)
diff --git a/doc/guides/nics/enetc4.rst b/doc/guides/nics/enetc4.rst
index 844b290..16b1ba6 100644
--- a/doc/guides/nics/enetc4.rst
+++ b/doc/guides/nics/enetc4.rst
@@ -140,3 +140,13 @@ PF/Common devargs
Usage example::
dpdk-testpmd -a 0000:00:00.0,enetc4_txq_prior=1|2|3 -- -i
+
+``nc``
+ Select non-cacheable RX/TX ops (BD rings mapped as non-cacheable memory).
+ Set to ``1`` to use non-cacheable descriptor ring operations.
+ By default, cacheable BD rings with software cache maintenance are used.
+ Applies to both PF and VF.
+
+ Usage example::
+
+ dpdk-testpmd -a 0000:00:00.0,nc=1 -- -i
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 62206d7..ef5f1e6 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
@@ -1370,6 +1394,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;
@@ -1477,5 +1509,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
* [PATCH v3 8/9] net/enetc: set user configurable priority to TX rings
From: Gagandeep Singh @ 2026-06-23 6:00 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Vanshika Shukla
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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/nics/enetc4.rst | 12 ++++
doc/guides/rel_notes/release_26_07.rst | 1 +
drivers/net/enetc/enetc.h | 1 +
drivers/net/enetc/enetc4_ethdev.c | 81 +++++++++++++++++++++++++-
4 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/doc/guides/nics/enetc4.rst b/doc/guides/nics/enetc4.rst
index 3c4af22..844b290 100644
--- a/doc/guides/nics/enetc4.rst
+++ b/doc/guides/nics/enetc4.rst
@@ -128,3 +128,15 @@ VF-specific devargs
Usage example::
dpdk-testpmd -a 0000:00:01.0,enetc4_vsi_delay=10 -- -i
+
+PF/Common devargs
+~~~~~~~~~~~~~~~~~
+
+``enetc4_txq_prior``
+ Set per-queue TX ring priority (TBMR bits).
+ The value is a ``|``-separated list of priority values, one per TX queue.
+ Values beyond the maximum supported TX queue count are discarded.
+
+ Usage example::
+
+ dpdk-testpmd -a 0000:00:00.0,enetc4_txq_prior=1|2|3 -- -i
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
* [PATCH v3 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay
From: Gagandeep Singh @ 2026-06-23 6:00 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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/nics/enetc4.rst | 18 +++++++
doc/guides/rel_notes/release_26_07.rst | 2 +
drivers/net/enetc/enetc.h | 2 +
drivers/net/enetc/enetc4_vf.c | 68 +++++++++++++++++++-------
4 files changed, 73 insertions(+), 17 deletions(-)
diff --git a/doc/guides/nics/enetc4.rst b/doc/guides/nics/enetc4.rst
index 7b94941..3c4af22 100644
--- a/doc/guides/nics/enetc4.rst
+++ b/doc/guides/nics/enetc4.rst
@@ -110,3 +110,21 @@ VF-specific devargs
Usage example::
dpdk-testpmd -a 0000:00:01.0,enetc4_vsi_disable -- -i
+
+``enetc4_vsi_timeout``
+ Set the VSI-PSI message wait timeout as an iteration count.
+ Controls how many polling iterations the driver waits for a VSI-PSI
+ response before timing out.
+ Defaults to ``ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE`` when not set.
+
+ Usage example::
+
+ dpdk-testpmd -a 0000:00:01.0,enetc4_vsi_timeout=200 -- -i
+
+``enetc4_vsi_delay``
+ Set the VSI-PSI message wait delay in microseconds between polling iterations.
+ Defaults to ``ENETC4_DEF_VSI_WAIT_DELAY_UPDATE`` when not set.
+
+ Usage example::
+
+ dpdk-testpmd -a 0000:00:01.0,enetc4_vsi_delay=10 -- -i
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..62206d7 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,43 @@ 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);
+ rte_kvargs_free(kvlist);
+ 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);
+ rte_kvargs_free(kvlist);
+ 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 +1475,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
* [PATCH v3 5/9] net/enetc: support scatter-gather
From: Gagandeep Singh @ 2026-06-23 6:00 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Vanshika Shukla
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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
* [PATCH v3 6/9] net/enetc: add option to disable VSI messaging
From: Gagandeep Singh @ 2026-06-23 6:00 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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/nics/enetc4.rst | 22 +++++++++-
doc/guides/rel_notes/release_26_07.rst | 2 +
drivers/net/enetc/enetc4_vf.c | 61 ++++++++++++++++++++++++--
3 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/doc/guides/nics/enetc4.rst b/doc/guides/nics/enetc4.rst
index 866d389..7b94941 100644
--- a/doc/guides/nics/enetc4.rst
+++ b/doc/guides/nics/enetc4.rst
@@ -1,5 +1,5 @@
.. SPDX-License-Identifier: BSD-3-Clause
- Copyright 2024-2025 NXP
+ Copyright 2024-2026 NXP
ENETC4 Poll Mode Driver
=======================
@@ -90,3 +90,23 @@ Driver compilation and testing
Follow instructions available in the document
:ref:`compiling and testing a PMD for a NIC <pmd_build_and_test>`
to launch **testpmd**.
+
+
+Driver Arguments (devargs)
+--------------------------
+
+The ENETC4 PMD supports the following device arguments (devargs)
+that can be passed via ``-a`` (allow-list) option in DPDK applications.
+
+VF-specific devargs
+~~~~~~~~~~~~~~~~~~~
+
+``enetc4_vsi_disable``
+ Disable VSI-PSI messaging for the VF.
+ When present, features that require VSI-PSI communication
+ (link update, MAC filter, VLAN filter) are replaced with no-op stubs.
+ Useful when the PF driver does not support VSI-PSI messages.
+
+ Usage example::
+
+ dpdk-testpmd -a 0000:00:01.0,enetc4_vsi_disable -- -i
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
* [PATCH v3 4/9] net/enetc: update random MAC generation code
From: Gagandeep Singh @ 2026-06-23 5:59 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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
* [PATCH v3 3/9] net/enetc: support ESP packet type in packet parsing
From: Gagandeep Singh @ 2026-06-23 5:59 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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
* [PATCH v3 2/9] net/enetc: fix queue initialization
From: Gagandeep Singh @ 2026-06-23 5:59 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, stable, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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
* [PATCH v3 1/9] net/enetc: fix TX BD structure
From: Gagandeep Singh @ 2026-06-23 5:59 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, stable, Gagandeep Singh
In-Reply-To: <20260623060004.2187716-1-g.singh@nxp.com>
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
* [PATCH v3 0/9] ENETC driver related changes series
From: Gagandeep Singh @ 2026-06-23 5:59 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal
In-Reply-To: <20260622113517.1616028-1-g.singh@nxp.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 2475 bytes --]
V3 changes:
- Added documentation for all devargs in enetc4.rst.
- Fixed kvlist memory leak issue.
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/enetc4.rst | 62 +++-
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 | 206 ++++++++++--
drivers/net/enetc/enetc_ethdev.c | 25 +-
drivers/net/enetc/enetc_rxtx.c | 430 ++++++++++++++++++++++---
9 files changed, 831 insertions(+), 119 deletions(-)
--
2.25.1
^ permalink raw reply
* [PATCH v2 1/1] common/cnxk: add bulk Rx queue enable/disable
From: rkudurumalla @ 2026-06-23 5:44 UTC (permalink / raw)
To: Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori, Satha Rao,
Harman Kalra
Cc: dev, jerinj, Rakesh Kudurumalla
In-Reply-To: <20260617054943.287815-1-rkudurumalla@marvell.com>
From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
Add roc_nix_rq_multi_ena_dis() to batch RQ enable/disable mailbox
AQ operations and process them in a single mbox_process() call.
Skip mbox_process() when no messages were queued (e.g. all qid are
UINT16_MAX) by checking num_msgs and msg_size via mbox_nonempty_nolock().
Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
drivers/common/cnxk/roc_mbox_priv.h | 6 +-
drivers/common/cnxk/roc_nix.h | 2 +
drivers/common/cnxk/roc_nix_queue.c | 102 ++++++++++++++++++
.../common/cnxk/roc_platform_base_symbols.c | 1 +
4 files changed, 107 insertions(+), 4 deletions(-)
diff --git a/drivers/common/cnxk/roc_mbox_priv.h b/drivers/common/cnxk/roc_mbox_priv.h
index 354c8fa52a..e9da1959b6 100644
--- a/drivers/common/cnxk/roc_mbox_priv.h
+++ b/drivers/common/cnxk/roc_mbox_priv.h
@@ -113,14 +113,12 @@ mbox_rsp_init(uint16_t mbox_id, void *msghdr)
}
static inline bool
-mbox_nonempty(struct mbox *mbox, int devid)
+mbox_nonempty_nolock(struct mbox *mbox, int devid)
{
struct mbox_dev *mdev = &mbox->dev[devid];
bool ret;
- plt_spinlock_lock(&mdev->mbox_lock);
- ret = mdev->num_msgs != 0;
- plt_spinlock_unlock(&mdev->mbox_lock);
+ ret = mdev->num_msgs != 0 && mdev->msg_size != 0;
return ret;
}
diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index 8ba8b3e0b6..f495e2a5ad 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -1094,6 +1094,8 @@ int __roc_api roc_nix_rq_modify(struct roc_nix *roc_nix, struct roc_nix_rq *rq,
bool ena);
int __roc_api roc_nix_rq_cman_config(struct roc_nix *roc_nix, struct roc_nix_rq *rq);
int __roc_api roc_nix_rq_ena_dis(struct roc_nix_rq *rq, bool enable);
+int __roc_api roc_nix_rq_multi_ena_dis(struct roc_nix *roc_nix, struct roc_nix_rq *rqs,
+ int nb_rx_queues, bool enable);
int __roc_api roc_nix_rq_is_sso_enable(struct roc_nix *roc_nix, uint32_t qid);
int __roc_api roc_nix_rq_fini(struct roc_nix_rq *rq);
int __roc_api roc_nix_cq_init(struct roc_nix *roc_nix, struct roc_nix_cq *cq);
diff --git a/drivers/common/cnxk/roc_nix_queue.c b/drivers/common/cnxk/roc_nix_queue.c
index ef9b651022..075c9c1591 100644
--- a/drivers/common/cnxk/roc_nix_queue.c
+++ b/drivers/common/cnxk/roc_nix_queue.c
@@ -10,6 +10,49 @@
/* Default SQB slack per SQ */
#define ROC_NIX_SQB_SLACK_DFLT 24
+typedef void *(*nix_aq_enq_alloc_t)(struct mbox *mbox);
+
+static inline void
+nix_aq_enq_write_rq_ena(void *msg, uint16_t qid, bool enable)
+{
+ struct nix_aq_enq_req *aq = msg;
+
+ aq->qidx = qid;
+ aq->ctype = NIX_AQ_CTYPE_RQ;
+ aq->op = NIX_AQ_INSTOP_WRITE;
+ aq->rq.ena = enable;
+ aq->rq_mask.ena = ~(aq->rq_mask.ena);
+}
+
+static inline int
+nix_rq_bulk_ena_dis_fill(struct mbox *mbox, struct roc_nix_rq *rqs, int nb_rx_queues,
+ bool enable, nix_aq_enq_alloc_t alloc)
+{
+ int i;
+
+ for (i = 0; i < nb_rx_queues; i++) {
+ void *aq;
+ int rc;
+
+ if (rqs[i].qid == UINT16_MAX)
+ continue;
+
+ aq = alloc(mbox);
+ if (!aq) {
+ rc = mbox_process(mbox);
+ if (rc)
+ return rc;
+ aq = alloc(mbox);
+ if (!aq)
+ return -ENOSPC;
+ }
+
+ nix_aq_enq_write_rq_ena(aq, rqs[i].qid, enable);
+ }
+
+ return 0;
+}
+
static inline uint32_t
nix_qsize_to_val(enum nix_q_size qsize)
{
@@ -47,6 +90,28 @@ nix_rq_vwqe_flush(struct roc_nix_rq *rq, uint16_t vwqe_interval)
}
}
+static int
+nix_rq_bulk_ena_dis(struct nix *nix, struct roc_nix_rq *rqs, int nb_rx_queues, bool enable)
+{
+ struct mbox *mbox = mbox_get((&nix->dev)->mbox);
+ nix_aq_enq_alloc_t alloc;
+ int rc;
+
+ if (roc_model_is_cn9k())
+ alloc = (nix_aq_enq_alloc_t)mbox_alloc_msg_nix_aq_enq;
+ else if (roc_model_is_cn10k())
+ alloc = (nix_aq_enq_alloc_t)mbox_alloc_msg_nix_cn10k_aq_enq;
+ else /* CN20K */
+ alloc = (nix_aq_enq_alloc_t)mbox_alloc_msg_nix_cn20k_aq_enq;
+
+ rc = nix_rq_bulk_ena_dis_fill(mbox, rqs, nb_rx_queues, enable, alloc);
+ if (!rc && mbox_nonempty_nolock(mbox, 0))
+ rc = mbox_process(mbox);
+
+ mbox_put(mbox);
+ return rc;
+}
+
int
nix_rq_ena_dis(struct dev *dev, struct roc_nix_rq *rq, bool enable)
{
@@ -126,6 +191,43 @@ roc_nix_sq_ena_dis(struct roc_nix_sq *sq, bool enable)
return rc;
}
+int
+roc_nix_rq_multi_ena_dis(struct roc_nix *roc_nix, struct roc_nix_rq *rqs, int nb_rx_queues,
+ bool enable)
+{
+ struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+ struct roc_nix_rq *rq;
+ int rc, i;
+
+ rc = nix_rq_bulk_ena_dis(nix, rqs, nb_rx_queues, enable);
+ if (rc) {
+ plt_err("Failed to %s Rx queues rc=%d pf=%d vf=%d nb_rx_queues=%d",
+ enable ? "enable" : "disable", rc, nix->dev.pf, nix->dev.vf,
+ nb_rx_queues);
+ return rc;
+ }
+
+ for (i = 0; i < nb_rx_queues; i++) {
+ rq = &rqs[i];
+
+ if (rq->qid == UINT16_MAX)
+ continue;
+
+ nix_rq_vwqe_flush(rq, nix->vwqe_interval);
+
+ /* Check for meta aura if RQ is enabled */
+ if (enable && nix->need_meta_aura) {
+ rc = roc_nix_inl_meta_aura_check(rq->roc_nix, rq);
+ if (rc) {
+ plt_err("Failed meta aura check for rq=%u rc=%d pf=%d vf=%d",
+ rq->qid, rc, nix->dev.pf, nix->dev.vf);
+ return rc;
+ }
+ }
+ }
+ return 0;
+}
+
int
roc_nix_rq_ena_dis(struct roc_nix_rq *rq, bool enable)
{
diff --git a/drivers/common/cnxk/roc_platform_base_symbols.c b/drivers/common/cnxk/roc_platform_base_symbols.c
index ed34d4b05b..08b2f4c6f8 100644
--- a/drivers/common/cnxk/roc_platform_base_symbols.c
+++ b/drivers/common/cnxk/roc_platform_base_symbols.c
@@ -353,6 +353,7 @@ RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_ena_dis)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_is_sso_enable)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_init)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_modify)
+RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_multi_ena_dis)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_cman_config)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_fini)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_cq_init)
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v5] graph: add optional profiling stats
From: Jerin Jacob @ 2026-06-23 5:13 UTC (permalink / raw)
To: Morten Brørup
Cc: dev, Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Zhirun Yan
In-Reply-To: <20260621184140.2878132-1-mb@smartsharesystems.com>
On Mon, Jun 22, 2026 at 12:11 AM Morten Brørup <mb@smartsharesystems.com> wrote:
>
> Added graph node profiling stats, build time configurable by enabling
> RTE_GRAPH_PROFILE in rte_config.h.
>
> Signed-off-by: Morten Brørup <mb@smartsharesystems.com>
> ---
> v5:
> * Added stats for a half burst and a full burst.
> v4:
> * Added documentation. (AI)
> * Added more comments. (AI)
> * Improved dump. (AI)
> * Debug shows both cycles/call and cycles/obj.
> v3:
> * Debug shows cycles/obj instead of cycles/call.
> * Fixed missing --in-reply-to.
> v2:
> * Fixed indentation.
> ---
> config/rte_config.h | 1 +
> doc/guides/prog_guide/graph_lib.rst | 1 +
> lib/graph/graph_debug.c | 57 ++++++++++++++++++++++++++++-
> lib/graph/node.c | 2 +
> lib/graph/rte_graph_worker_common.h | 33 +++++++++++++++--
Please update app/test/test_graph.c to validate this featue.
> 5 files changed, 90 insertions(+), 4 deletions(-)
>
> diff --git a/config/rte_config.h b/config/rte_config.h
> index 0447cdf2ad..1942c1b1ec 100644
> --- a/config/rte_config.h
> +++ b/config/rte_config.h
> @@ -106,6 +106,7 @@
> /* rte_graph defines */
> #define RTE_GRAPH_BURST_SIZE 256
> #define RTE_LIBRTE_GRAPH_STATS 1
> +/* RTE_GRAPH_PROFILE is not set */
>
> /****** driver defines ********/
>
> diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
> index 8dd49c19d2..bc36042296 100644
> --- a/doc/guides/prog_guide/graph_lib.rst
> +++ b/doc/guides/prog_guide/graph_lib.rst
> @@ -49,6 +49,7 @@ Performance tuning parameters
> RTE_GRAPH_BURST_SIZE config option.
> The testing shows, on x86 and arm64 servers, The sweet spot is 256 burst
> size. While on arm64 embedded SoCs, it is either 64 or 128.
> +- Enable the ``RTE_GRAPH_PROFILE`` config option for more profiling details.
> - Disable node statistics (using ``RTE_LIBRTE_GRAPH_STATS`` config option)
> if not needed.
>
> diff --git a/lib/graph/graph_debug.c b/lib/graph/graph_debug.c
> index e3b8cccdc1..7c97e23748 100644
> --- a/lib/graph/graph_debug.c
> +++ b/lib/graph/graph_debug.c
> @@ -92,7 +92,62 @@ rte_graph_obj_dump(FILE *f, struct rte_graph *g, bool all)
> fprintf(f, " total_sched_fail=%" PRId64 "\n",
> n->dispatch.total_sched_fail);
> }
> - fprintf(f, " total_calls=%" PRId64 "\n", n->total_calls);
> + fprintf(f, " total_calls=%" PRIu64 "\n", n->total_calls);
> + if (rte_graph_has_stats_feature()) {
> + fprintf(f, " total_cycles=%" PRIu64 ", avg cycles/call=%.1f\n",
> + n->total_cycles,
> + n->total_calls == 0 ? (double)0 :
> + (double)n->total_cycles / (double)n->total_calls);
> + }
> +#ifdef RTE_GRAPH_PROFILE
Please introduce rte_graph_has_profile_featue() similar to
rte_graph_has_stats_feature() to reduce if def clutter as possible.
> + uint64_t calls = n->usage_stats[0].calls;
> + fprintf(f, " objs[0]\n");
> + fprintf(f, " calls=%" PRIu64 ", cycles=%" PRIu64 ", avg cycles/call=%.1f\n",
> + calls,
>
> diff --git a/lib/graph/rte_graph_worker_common.h b/lib/graph/rte_graph_worker_common.h
> index 4ab53a533e..0d8039575d 100644
> --- a/lib/graph/rte_graph_worker_common.h
> +++ b/lib/graph/rte_graph_worker_common.h
> @@ -144,12 +144,26 @@ struct __rte_cache_aligned rte_node {
> rte_node_process_t process; /**< Process function. */
> uint64_t process_u64;
> };
> + /** Fast path area cache line 3. */
> +#ifdef RTE_GRAPH_PROFILE
> + struct {
> + uint64_t calls; /**< Calls processing resp. 0 or 1 objects. */
> + uint64_t cycles; /**< Cycles spent processing resp. 0 or 1 objects. */
> + } usage_stats[2]; /**< Usage when this node processed 0 or 1 objects. */
> + uint64_t full_burst_calls; /**< Calls processing a full burst of objects. */
> + uint64_t full_burst_cycles; /**< Cycles spent processing a full burst of objects. */
> + uint64_t half_burst_calls; /**< Calls processing a half burst of objects. */
> + uint64_t half_burst_cycles; /**< Cycles spent processing a half burst of objects. */
> + /** Fast path area cache line 4. */
> +#endif
Is it an ABI breakage?
> alignas(RTE_CACHE_LINE_MIN_SIZE) struct rte_node *nodes[]; /**< Next nodes. */
> };
> };
>
^ permalink raw reply
* [PATCH] app/dma_perf: skip case if worker maps to main lcore
From: Rupesh Chiluka @ 2026-06-23 4:58 UTC (permalink / raw)
To: Cheng Jiang, Chengwen Feng; +Cc: dev, gakhil, anoobj, ktejasree, Rupesh Chiluka
Refuse to run DMA/CPU mem-copy cases when any worker is bound to the
EAL main lcore.
Signed-off-by: Rupesh Chiluka <rchiluka@marvell.com>
---
app/test-dma-perf/main.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/app/test-dma-perf/main.c b/app/test-dma-perf/main.c
index 4249dcfd3d..b6aa5b8401 100644
--- a/app/test-dma-perf/main.c
+++ b/app/test-dma-perf/main.c
@@ -109,6 +109,7 @@ run_test_case(struct test_configure *case_cfg)
static void
run_test(uint32_t case_id, struct test_configure *case_cfg)
{
+ uint32_t main_lcore = rte_get_main_lcore();
uint32_t nb_lcores = rte_lcore_count();
struct test_configure_entry *mem_size = &case_cfg->mem_size;
struct test_configure_entry *buf_size = &case_cfg->buf_size;
@@ -122,6 +123,14 @@ run_test(uint32_t case_id, struct test_configure *case_cfg)
return;
}
+ for (uint32_t i = 0; i < case_cfg->num_worker; i++) {
+ if (case_cfg->dma_config[i].lcore_dma_map.lcore == main_lcore) {
+ printf("Case %u: worker %u cannot run on the EAL main lcore (%u).\n",
+ case_id, i, main_lcore);
+ return;
+ }
+ }
+
printf("Number of used lcores: %u.\n", nb_lcores);
if (mem_size->incr != 0)
--
2.48.1
^ permalink raw reply related
* [PATCH v2 3/3] test/crypto: add unit test for Rx inject multi seg
From: Tejasree Kondoj @ 2026-06-23 4:27 UTC (permalink / raw)
To: Akhil Goyal, Fan Zhang; +Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260623042723.89226-1-ktejasree@marvell.com>
From: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Add unit test to verify the multi segment support in RX Inject
Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
app/test/test_cryptodev.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index 884629ec8c..fd02107baf 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -1564,7 +1564,8 @@ ut_setup_security_rx_inject(void)
struct rte_eth_conf port_conf = {
.rxmode = {
.offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM |
- RTE_ETH_RX_OFFLOAD_SECURITY,
+ RTE_ETH_RX_OFFLOAD_SECURITY |
+ RTE_ETH_RX_OFFLOAD_SCATTER,
},
.txmode = {
.offloads = RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE,
@@ -10781,6 +10782,25 @@ test_ipsec_proto_known_vec_inb_rx_inject(const void *test_data)
return test_ipsec_proto_process(&td_inb, NULL, 1, false, &flags);
}
+static int
+test_ipsec_proto_known_vec_inb_rx_inject_multi_seg(const void *test_data)
+{
+ const struct ipsec_test_data *td = test_data;
+ struct ipsec_test_flags flags;
+ struct ipsec_test_data td_inb;
+
+ memset(&flags, 0, sizeof(flags));
+ flags.rx_inject = true;
+ flags.nb_segs_in_mbuf = 4;
+
+ if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+ test_ipsec_td_in_from_out(td, &td_inb);
+ else
+ memcpy(&td_inb, td, sizeof(td_inb));
+
+ return test_ipsec_proto_process(&td_inb, NULL, 1, false, &flags);
+}
+
static int
test_ipsec_proto_all(const struct ipsec_test_flags *flags)
{
@@ -18389,6 +18409,11 @@ static struct unit_test_suite ipsec_proto_testsuite = {
"Inbound known vector (ESP tunnel mode IPv4 AES-GCM 128) Rx inject",
ut_setup_security_rx_inject, ut_teardown_rx_inject,
test_ipsec_proto_known_vec_inb_rx_inject, &pkt_aes_128_gcm),
+ TEST_CASE_NAMED_WITH_DATA(
+ "Inbound known vector (ESP tunnel mode IPv4 AES-GCM 128) Rx inject multi seg",
+ ut_setup_security_rx_inject, ut_teardown_rx_inject,
+ test_ipsec_proto_known_vec_inb_rx_inject_multi_seg, &pkt_aes_128_gcm),
+
TEST_CASES_END() /**< NULL terminate unit test array */
}
};
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/3] test/crypto: add autotest support for cn20k
From: Tejasree Kondoj @ 2026-06-23 4:27 UTC (permalink / raw)
To: Akhil Goyal, Fan Zhang; +Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260623042723.89226-1-ktejasree@marvell.com>
From: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Add crypto autotest support for cn20k
Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
app/test/test_cryptodev.c | 15 +++++++++++++++
app/test/test_cryptodev.h | 1 +
2 files changed, 16 insertions(+)
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index b908f10317..884629ec8c 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -20863,6 +20863,18 @@ test_cryptodev_cn10k_raw_api(void)
return run_cryptodev_raw_testsuite(RTE_STR(CRYPTODEV_NAME_CN10K_PMD));
}
+static int
+test_cryptodev_cn20k(void)
+{
+ return run_cryptodev_testsuite(RTE_STR(CRYPTODEV_NAME_CN20K_PMD));
+}
+
+static int
+test_cryptodev_cn20k_raw_api(void)
+{
+ return run_cryptodev_raw_testsuite(RTE_STR(CRYPTODEV_NAME_CN20K_PMD));
+}
+
static int
test_cryptodev_dpaa2_sec_raw_api(void)
{
@@ -20883,6 +20895,8 @@ test_cryptodev_zsda(void)
REGISTER_DRIVER_TEST(cryptodev_cn10k_raw_api_autotest,
test_cryptodev_cn10k_raw_api);
+REGISTER_DRIVER_TEST(cryptodev_cn20k_raw_api_autotest,
+ test_cryptodev_cn20k_raw_api);
REGISTER_DRIVER_TEST(cryptodev_dpaa2_sec_raw_api_autotest,
test_cryptodev_dpaa2_sec_raw_api);
REGISTER_DRIVER_TEST(cryptodev_dpaa_sec_raw_api_autotest,
@@ -20915,4 +20929,5 @@ REGISTER_DRIVER_TEST(cryptodev_nitrox_autotest, test_cryptodev_nitrox);
REGISTER_DRIVER_TEST(cryptodev_bcmfs_autotest, test_cryptodev_bcmfs);
REGISTER_DRIVER_TEST(cryptodev_cn9k_autotest, test_cryptodev_cn9k);
REGISTER_DRIVER_TEST(cryptodev_cn10k_autotest, test_cryptodev_cn10k);
+REGISTER_DRIVER_TEST(cryptodev_cn20k_autotest, test_cryptodev_cn20k);
REGISTER_DRIVER_TEST(cryptodev_zsda_autotest, test_cryptodev_zsda);
diff --git a/app/test/test_cryptodev.h b/app/test/test_cryptodev.h
index 49aa45ec17..d125dea958 100644
--- a/app/test/test_cryptodev.h
+++ b/app/test/test_cryptodev.h
@@ -74,6 +74,7 @@
#define CRYPTODEV_NAME_BCMFS_PMD crypto_bcmfs
#define CRYPTODEV_NAME_CN9K_PMD crypto_cn9k
#define CRYPTODEV_NAME_CN10K_PMD crypto_cn10k
+#define CRYPTODEV_NAME_CN20K_PMD crypto_cn20k
#define CRYPTODEV_NAME_MLX5_PMD crypto_mlx5
#define CRYPTODEV_NAME_UADK_PMD crypto_uadk
#define CRYPTODEV_NAME_ZSDA_SYM_PMD crypto_zsda
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/3] test/crypto: add asym autotest support for cn20k
From: Tejasree Kondoj @ 2026-06-23 4:27 UTC (permalink / raw)
To: Akhil Goyal, Fan Zhang; +Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260623042723.89226-1-ktejasree@marvell.com>
From: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Add crypto asym autotest support for cn20k
Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
app/test/test_cryptodev_asym.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/app/test/test_cryptodev_asym.c b/app/test/test_cryptodev_asym.c
index 90af49e485..7b8afe5f92 100644
--- a/app/test/test_cryptodev_asym.c
+++ b/app/test/test_cryptodev_asym.c
@@ -5500,6 +5500,12 @@ test_cryptodev_cn10k_asym(void)
return run_cryptodev_asym_testsuite(RTE_STR(CRYPTODEV_NAME_CN10K_PMD));
}
+static int
+test_cryptodev_cn20k_asym(void)
+{
+ return run_cryptodev_asym_testsuite(RTE_STR(CRYPTODEV_NAME_CN20K_PMD));
+}
+
static int
test_cryptodev_virtio_asym(void)
{
@@ -5517,5 +5523,6 @@ REGISTER_DRIVER_TEST(cryptodev_qat_asym_autotest, test_cryptodev_qat_asym);
REGISTER_DRIVER_TEST(cryptodev_octeontx_asym_autotest, test_cryptodev_octeontx_asym);
REGISTER_DRIVER_TEST(cryptodev_cn9k_asym_autotest, test_cryptodev_cn9k_asym);
REGISTER_DRIVER_TEST(cryptodev_cn10k_asym_autotest, test_cryptodev_cn10k_asym);
+REGISTER_DRIVER_TEST(cryptodev_cn20k_asym_autotest, test_cryptodev_cn20k_asym);
REGISTER_DRIVER_TEST(cryptodev_virtio_asym_autotest, test_cryptodev_virtio_asym);
REGISTER_DRIVER_TEST(cryptodev_virtio_user_asym_autotest, test_cryptodev_virtio_user_asym);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/3] update tests with CN20K support
From: Tejasree Kondoj @ 2026-06-23 4:27 UTC (permalink / raw)
To: Akhil Goyal, Fan Zhang; +Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
Add CN20K sym/asym autotests and Rx-inject multi-segment unit test.
v2:
- Removed asym sessionless test patch
- Fixed test names ordering
Vidya Sagar Velumuri (3):
test/crypto: add asym autotest support for cn20k
test/crypto: add autotest support for cn20k
test/crypto: add unit test for Rx inject multi seg
app/test/test_cryptodev.c | 42 +++++++++++++++++++++++++++++++++-
app/test/test_cryptodev.h | 1 +
app/test/test_cryptodev_asym.c | 7 ++++++
3 files changed, 49 insertions(+), 1 deletion(-)
--
2.34.1
^ permalink raw reply
* [PATCH] examples/l3fwd: dynamic NUMA-aware alloc lcore_conf
From: Chengwen Feng @ 2026-06-23 3:23 UTC (permalink / raw)
To: thomas, stephen; +Cc: dev
Currently lcore_conf is a global static array. When multiple
ports/lcores are distributed across different NUMA nodes, datapath
suffers from severe cross-NUMA memory access penalty.
On Kunpeng platform, sizeof(struct lcore_conf) reaches 133760 bytes.
Such a huge per-lcore structure significantly amplifies cross-NUMA
overhead in multi-port multi-NUMA deployment scenarios.
This commit refactors lcore_conf to pointer array and implements
per-lcore NUMA-aware hugepage allocation, allocating each lcore's
configuration on its local socket to eliminate remote memory access.
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
examples/l3fwd/l3fwd.h | 2 +-
examples/l3fwd/l3fwd_acl.c | 2 +-
examples/l3fwd/l3fwd_em.c | 8 ++++----
examples/l3fwd/l3fwd_fib.c | 6 +++---
examples/l3fwd/l3fwd_lpm.c | 8 ++++----
examples/l3fwd/main.c | 42 ++++++++++++++++++++++++++++++--------
6 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/examples/l3fwd/l3fwd.h b/examples/l3fwd/l3fwd.h
index 349fc37c79..20c457ee7f 100644
--- a/examples/l3fwd/l3fwd.h
+++ b/examples/l3fwd/l3fwd.h
@@ -104,7 +104,7 @@ extern uint32_t hash_entry_number;
extern xmm_t val_eth[RTE_MAX_ETHPORTS];
-extern struct lcore_conf lcore_conf[RTE_MAX_LCORE];
+extern struct lcore_conf *lcore_conf[RTE_MAX_LCORE];
extern struct parm_cfg parm_config;
diff --git a/examples/l3fwd/l3fwd_acl.c b/examples/l3fwd/l3fwd_acl.c
index 4ee3411d2a..0605f6feb9 100644
--- a/examples/l3fwd/l3fwd_acl.c
+++ b/examples/l3fwd/l3fwd_acl.c
@@ -1090,7 +1090,7 @@ acl_main_loop(__rte_unused void *dummy)
prev_tsc = 0;
lcore_id = rte_lcore_id();
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
socketid = rte_lcore_to_socket_id(lcore_id);
if (qconf->n_rx_queue == 0) {
diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c
index d8748a0edd..9aa23759d3 100644
--- a/examples/l3fwd/l3fwd_em.c
+++ b/examples/l3fwd/l3fwd_em.c
@@ -597,7 +597,7 @@ em_main_loop(__rte_unused void *dummy)
US_PER_S * BURST_TX_DRAIN_US;
lcore_id = rte_lcore_id();
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
const uint16_t n_rx_q = qconf->n_rx_queue;
const uint16_t n_tx_p = qconf->n_tx_port;
@@ -685,7 +685,7 @@ em_event_loop_single(struct l3fwd_event_resources *evt_rsrc,
return;
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
while (!force_quit) {
@@ -747,7 +747,7 @@ em_event_loop_burst(struct l3fwd_event_resources *evt_rsrc,
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
@@ -877,7 +877,7 @@ em_event_loop_vector(struct l3fwd_event_resources *evt_rsrc,
if (dst_ports == NULL)
return;
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
diff --git a/examples/l3fwd/l3fwd_fib.c b/examples/l3fwd/l3fwd_fib.c
index 4fc6bf90d5..32c8847130 100644
--- a/examples/l3fwd/l3fwd_fib.c
+++ b/examples/l3fwd/l3fwd_fib.c
@@ -192,7 +192,7 @@ fib_main_loop(__rte_unused void *dummy)
US_PER_S * BURST_TX_DRAIN_US;
lcore_id = rte_lcore_id();
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
const uint16_t n_rx_q = qconf->n_rx_queue;
const uint16_t n_tx_p = qconf->n_tx_port;
@@ -282,7 +282,7 @@ fib_event_loop(struct l3fwd_event_resources *evt_rsrc,
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
@@ -446,7 +446,7 @@ fib_process_event_vector(struct rte_event_vector *vec, uint8_t *type_arr,
uint16_t nh;
int i;
- lconf = &lcore_conf[rte_lcore_id()];
+ lconf = lcore_conf[rte_lcore_id()];
/* Reset counters. */
ipv4_cnt = 0;
diff --git a/examples/l3fwd/l3fwd_lpm.c b/examples/l3fwd/l3fwd_lpm.c
index 2d2651e750..77701503f7 100644
--- a/examples/l3fwd/l3fwd_lpm.c
+++ b/examples/l3fwd/l3fwd_lpm.c
@@ -154,7 +154,7 @@ lpm_main_loop(__rte_unused void *dummy)
US_PER_S * BURST_TX_DRAIN_US;
lcore_id = rte_lcore_id();
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
const uint16_t n_rx_q = qconf->n_rx_queue;
const uint16_t n_tx_p = qconf->n_tx_port;
@@ -270,7 +270,7 @@ lpm_event_loop_single(struct l3fwd_event_resources *evt_rsrc,
return;
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
while (!force_quit) {
@@ -324,7 +324,7 @@ lpm_event_loop_burst(struct l3fwd_event_resources *evt_rsrc,
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
@@ -468,7 +468,7 @@ lpm_event_loop_vector(struct l3fwd_event_resources *evt_rsrc,
return;
lcore_id = rte_lcore_id();
- lconf = &lcore_conf[lcore_id];
+ lconf = lcore_conf[lcore_id];
dst_port_list =
rte_zmalloc("", sizeof(uint16_t) * evt_rsrc->vector_size,
RTE_CACHE_LINE_SIZE);
diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index df035b508c..c533a90bb4 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -96,7 +96,7 @@ uint32_t enabled_port_mask;
/* Used only in exact match mode. */
bool ipv6_enabled; /**< ipv6 is false by default. */
-struct lcore_conf lcore_conf[RTE_MAX_LCORE];
+struct lcore_conf *lcore_conf[RTE_MAX_LCORE];
struct parm_cfg parm_config;
@@ -368,17 +368,17 @@ init_lcore_rx_queues(void)
for (i = 0; i < nb_lcore_params; ++i) {
lcore = lcore_params[i].lcore_id;
- nb_rx_queue = lcore_conf[lcore].n_rx_queue;
+ nb_rx_queue = lcore_conf[lcore]->n_rx_queue;
if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
printf("error: too many queues (%u) for lcore: %u\n",
(unsigned int)nb_rx_queue + 1, lcore);
return -1;
} else {
- lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
+ lcore_conf[lcore]->rx_queue_list[nb_rx_queue].port_id =
lcore_params[i].port_id;
- lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
+ lcore_conf[lcore]->rx_queue_list[nb_rx_queue].queue_id =
lcore_params[i].queue_id;
- lcore_conf[lcore].n_rx_queue++;
+ lcore_conf[lcore]->n_rx_queue++;
}
}
return 0;
@@ -1118,6 +1118,26 @@ print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
printf("%s%s", name, buf);
}
+static int
+init_lcore_conf(void)
+{
+ unsigned int lcore_id;
+ int socketid;
+
+ for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+ if (rte_lcore_is_enabled(lcore_id) == 0)
+ continue;
+
+ socketid = rte_lcore_to_socket_id(lcore_id);
+ lcore_conf[lcore_id] = rte_zmalloc_socket(NULL, sizeof(struct lcore_conf),
+ RTE_CACHE_LINE_SIZE, socketid);
+ if (lcore_conf[lcore_id] == NULL)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
int
init_mem(uint16_t portid, unsigned int nb_mbuf)
{
@@ -1189,7 +1209,7 @@ init_mem(uint16_t portid, unsigned int nb_mbuf)
}
#endif
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
qconf->ipv4_lookup_struct =
l3fwd_lkp.get_ipv4_lookup_struct(socketid);
qconf->ipv6_lookup_struct =
@@ -1492,7 +1512,7 @@ l3fwd_poll_resource_setup(void)
"rte_eth_tx_queue_setup: err=%d, "
"port=%d\n", ret, portid);
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
qconf->tx_queue_id[portid] = queueid;
queueid++;
@@ -1505,7 +1525,7 @@ l3fwd_poll_resource_setup(void)
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
if (rte_lcore_is_enabled(lcore_id) == 0)
continue;
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
printf("\nInitializing rx queues on lcore %u ... ", lcore_id );
fflush(stdout);
/* init RX queues */
@@ -1667,6 +1687,10 @@ main(int argc, char **argv)
argc -= ret;
argv += ret;
+ ret = init_lcore_conf();
+ if (ret)
+ rte_exit(EXIT_FAILURE, "Init lcore conf failed!\n");
+
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
@@ -1749,7 +1773,7 @@ main(int argc, char **argv)
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
if (rte_lcore_is_enabled(lcore_id) == 0)
continue;
- qconf = &lcore_conf[lcore_id];
+ qconf = lcore_conf[lcore_id];
for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
portid = qconf->rx_queue_list[queue].port_id;
queueid = qconf->rx_queue_list[queue].queue_id;
--
2.17.1
^ permalink raw reply related
* RE: [PATCH v9 00/21] Wangxun Fixes
From: Zaiyu Wang @ 2026-06-23 3:15 UTC (permalink / raw)
To: 'Stephen Hemminger'; +Cc: dev
In-Reply-To: <20260622083000.16a572ee@phoenix.local>
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Monday, June 22, 2026 11:30 PM
> To: Zaiyu Wang <zaiyuwang@trustnetic.com>; Zaiyu Wang <zaiyuwang@trustnetic.com>
> Cc: dev@dpdk.org; dev@dpdk.org
> Subject: Re: [PATCH v9 00/21] Wangxun Fixes
>
> On Mon, 22 Jun 2026 19:10:48 +0800
> Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:
>
> > This series fixes several issues found on Wangxun Emerald, Sapphire
> > and Amber-lite NICs, with a focus on link-related problems.
> > ---
> > v9:
> > - Fixed several checkpatch errors
> > ---
> > v8:
> > - Fixed compilation error by replacing RTE_ETH_DEV_TO_PCI with
> > RTE_CLASS_TO_BUS_DEVICE
> > ---
> > v7:
> > - Fixed inverted semantics of is_flat_mem to match SFF8636
> > ---
> > v6:
> > - Fixed more issues identified by AI review
> > ---
> > v5:
> > - Fixed issues identified by AI review
> > ---
> > v4:
> > - Fixed issues identified by devtools scripts
> > ---
> > v3:
> > - Addressed Stephen's comments
> > ---
> > v2:
> > - Fixed compilation error and code style issues
> > ---
> >
> > Zaiyu Wang (21):
> > net/txgbe: remove duplicate xstats counters
> > net/ngbe: remove duplicate xstats counters
> > net/ngbe: add missing CDR config for YT PHY
> > net/ngbe: fix VF promiscuous and allmulticast
> > net/txgbe: fix inaccuracy in Tx rate limiting
> > net/txgbe: fix link status check condition
> > net/txgbe: fix Tx desc free logic
> > net/txgbe: fix link flow control registers for Amber-Lite
> > net/txgbe: fix link flow control config for Sapphire
> > net/txgbe: fix a mass of unknown interrupts
> > net/txgbe: fix traffic class priority configuration
> > net/txgbe: fix link stability for 25G NIC
> > net/txgbe: fix link stability for 40G NIC
> > net/txgbe: fix link stability for Amber-Lite backplane mode
> > net/txgbe: fix FEC mode configuration on 25G NIC
> > net/txgbe: fix SFP module identification
> > net/txgbe: fix get module info operation
> > net/txgbe: fix get EEPROM operation
> > net/txgbe: fix to reset Tx write-back pointer
> > net/txgbe: fix to enable Tx desc check
> > net/txgbe: fix temperature track for AML NIC
> >
> > drivers/net/ngbe/base/ngbe_phy_yt.c | 3 +
> > drivers/net/ngbe/ngbe_ethdev.c | 5 -
> > drivers/net/ngbe/ngbe_ethdev_vf.c | 11 +-
> > drivers/net/txgbe/base/meson.build | 2 +
> > drivers/net/txgbe/base/txgbe.h | 2 +
> > drivers/net/txgbe/base/txgbe_aml.c | 185 +-
> > drivers/net/txgbe/base/txgbe_aml.h | 6 +-
> > drivers/net/txgbe/base/txgbe_aml40.c | 114 +-
> > drivers/net/txgbe/base/txgbe_aml40.h | 6 +-
> > drivers/net/txgbe/base/txgbe_dcb_hw.c | 2 +-
> > drivers/net/txgbe/base/txgbe_e56.c | 3773 +++++++++++++++++++++
> > drivers/net/txgbe/base/txgbe_e56.h | 1753 ++++++++++
> > drivers/net/txgbe/base/txgbe_e56_bp.c | 2597 ++++++++++++++
> > drivers/net/txgbe/base/txgbe_e56_bp.h | 282 ++
> > drivers/net/txgbe/base/txgbe_hw.c | 54 +-
> > drivers/net/txgbe/base/txgbe_hw.h | 4 +-
> > drivers/net/txgbe/base/txgbe_osdep.h | 4 +
> > drivers/net/txgbe/base/txgbe_phy.c | 362 +-
> > drivers/net/txgbe/base/txgbe_phy.h | 46 +-
> > drivers/net/txgbe/base/txgbe_regs.h | 13 +-
> > drivers/net/txgbe/base/txgbe_type.h | 43 +-
> > drivers/net/txgbe/txgbe_ethdev.c | 472 ++-
> > drivers/net/txgbe/txgbe_ethdev.h | 7 +-
> > drivers/net/txgbe/txgbe_rxtx.c | 109 +-
> > drivers/net/txgbe/txgbe_rxtx.h | 36 +
> > drivers/net/txgbe/txgbe_rxtx_vec_common.h | 17 +-
> > 26 files changed, 9464 insertions(+), 444 deletions(-) create mode
> > 100644 drivers/net/txgbe/base/txgbe_e56.c
> > create mode 100644 drivers/net/txgbe/base/txgbe_e56.h
> > create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
> > create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.h
> >
>
> Applied to next-net, but this driver still has some unprefixed symbols:
>
> $ nm ./drivers/librte_net_txgbe.a | grep ' [TD] ' | grep -v ' txgbe'
> 0000000000000510 T set_fields_e56
> 0000000000007ca0 T handle_e56_bkp_an73_flow
>
Thanks.
^ permalink raw reply
* RE: [PATCH v8 12/21] net/txgbe: fix link stability for 25G NIC
From: Zaiyu Wang @ 2026-06-23 3:15 UTC (permalink / raw)
To: 'Stephen Hemminger'; +Cc: dev
In-Reply-To: <20260622075323.276cb2de@phoenix.local>
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Monday, June 22, 2026 10:53 PM
> To: Zaiyu Wang <zaiyuwang@trustnetic.com>; Zaiyu Wang <zaiyuwang@trustnetic.com>
> Cc: dev@dpdk.org; dev@dpdk.org
> Subject: Re: [PATCH v8 12/21] net/txgbe: fix link stability for 25G NIC
>
> On Mon, 22 Jun 2026 19:09:32 +0800
> Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:
>
> > > > +void
> > > > +set_fields_e56(unsigned int *src_data, unsigned int bit_high,
> > > > + unsigned int bit_low, unsigned int set_value) {
> > >
> > > Function could be static here?
> >
> > Hi Stephen,
> > Thanks for your time. This function is used in both txgbe_e56.c (for
> > general PHY
> > configuration) and txgbe_e56_bp.c (for backplane mode configuration).
> > Therefore, making it static would not be feasible?
> > I have also fixed the other issues you pointed out, including the
> > spelling corrections, replacing tabs with spaces in log messages, and removing the
term "master"
> from comments.
> >
> > Best regards,
> > Zaiyu
>
>
> Why I noticed was that it is a global function not following naming conventions.
> Either make it inline in a header or rename.
>
Thank you for the clarification.
I agree that renaming it would be a better approach.
^ permalink raw reply
* Re: [PATCH v3] dts: clean cryptodev environment after a test run
From: Patrick Robb @ 2026-06-23 0:39 UTC (permalink / raw)
To: Andrew Bailey; +Cc: luca.vizzarro, lylavoie, ahassick, knimoji, dev
In-Reply-To: <CABJ3N2XixQhhXEnfWJYU_rOou4zXUiYd2SuAV5WYkAgCDOFn6Q@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 29 bytes --]
Applied to next-dts, thanks.
[-- Attachment #2: Type: text/html, Size: 50 bytes --]
^ permalink raw reply
* [PATCH] test/pmd_af_packet: cleanups
From: Stephen Hemminger @ 2026-06-22 23:21 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
Fix two coverity bugs where fcntl() return value not checked.
Also mark some other cases as FAILED instead of skipped.
Such as failure to transmit or failure to allocate mbuf's.
Coverity ID: 503765
Coverity ID: 503766
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/test_pmd_af_packet.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/app/test/test_pmd_af_packet.c b/app/test/test_pmd_af_packet.c
index b668ca5b81..9fe595d606 100644
--- a/app/test/test_pmd_af_packet.c
+++ b/app/test/test_pmd_af_packet.c
@@ -556,19 +556,22 @@ test_af_packet_loopback(void)
/* Set TAP fd to non-blocking for reading */
int flags = fcntl(tap_fd, F_GETFL, 0);
- fcntl(tap_fd, F_SETFL, flags | O_NONBLOCK);
+ if (flags < 0 || fcntl(tap_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+ printf("fcntl failed: %s\n", strerror(errno));
+ return TEST_FAILED;
+ }
/* Allocate and send packets */
allocated = alloc_tx_mbufs(tx_bufs, BURST_SIZE);
if (allocated == 0) {
- printf("SKIPPED: Could not allocate mbufs\n");
- return TEST_SKIPPED;
+ printf("Could not allocate mbufs\n");
+ return TEST_FAILED;
}
nb_tx = do_tx_burst(port_id, 0, tx_bufs, allocated);
if (nb_tx == 0) {
- printf("SKIPPED: No packets transmitted\n");
- return TEST_SKIPPED;
+ printf("No packets transmitted\n");
+ return TEST_FAILED;
}
/*
--
2.53.0
^ permalink raw reply related
* RE: [EXTERNAL] [PATCH v5 14/24] bus/vmbus: convert from rte_atomic to stdatomic
From: Long Li @ 2026-06-22 20:57 UTC (permalink / raw)
To: Stephen Hemminger, dev@dpdk.org; +Cc: Wei Hu
In-Reply-To: <20260620023134.42877-15-stephen@networkplumber.org>
> Replace deprecated rte_atomic32 operations in the vmbus ring buffer
> producer with stdatomic equivalents, and replace the smp_wmb + CAS-spin
> publish with rte_wait_until_equal_32 + release-store.
>
> The two-cursor design is preserved: tbr->windex is the driver-private
> reservation cursor that lets producers reserve slots concurrently without a
> lock; vbr->windex is the host-visible commit cursor, updated in reservation
> order so the host never observes windex pointing past unwritten data. This is
> the lockless analogue of the spinlock-around- single-cursor pattern used by
> the Linux (drivers/hv/ring_buffer.c
> hv_ringbuffer_write) and FreeBSD (sys/dev/hyperv/vmbus/vmbus_br.c
> vmbus_txbr_write) implementations of the same host contract.
>
> The memory ordering mirrors __rte_ring_headtail_move_head and
> __rte_ring_update_tail in lib/ring/rte_ring_c11_pvt.h: relaxed wait for the
> previous producer's commit, release-store to publish. The rte_smp_wmb
> before the publish is folded into the release ordering on the store itself.
>
> The host-shared vbr->windex remains volatile uint32_t in the packed bufring
> struct; the atomic qualifier is added via cast at the access site. The (uintptr_t)
> launder on the store-side cast suppresses a spurious misaligned-atomic
> warning from the packed-struct attribute (windex is 4-byte aligned in practice,
> at offset 0 of a page-aligned struct).
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/bus/vmbus/private.h | 2 +-
> drivers/bus/vmbus/vmbus_bufring.c | 39 +++++++++++++++++--------------
> 2 files changed, 23 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/bus/vmbus/private.h b/drivers/bus/vmbus/private.h index
> 6efac86b77..6b7782724f 100644
> --- a/drivers/bus/vmbus/private.h
> +++ b/drivers/bus/vmbus/private.h
> @@ -25,7 +25,7 @@ extern int vmbus_logtype_bus; struct vmbus_br {
> struct vmbus_bufring *vbr;
> uint32_t dsize;
> - uint32_t windex; /* next available location */
> + RTE_ATOMIC(uint32_t) windex; /* next available location */
> };
>
> #define UIO_NAME_MAX 64
> diff --git a/drivers/bus/vmbus/vmbus_bufring.c
> b/drivers/bus/vmbus/vmbus_bufring.c
> index fcb97287dc..624fe8b6c5 100644
> --- a/drivers/bus/vmbus/vmbus_bufring.c
> +++ b/drivers/bus/vmbus/vmbus_bufring.c
> @@ -15,7 +15,7 @@
> #include <rte_tailq.h>
> #include <rte_log.h>
> #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
> #include <rte_memory.h>
> #include <rte_pause.h>
> #include <rte_bus_vmbus.h>
> @@ -114,6 +114,7 @@ vmbus_txbr_write(struct vmbus_br *tbr, const struct
> iovec iov[], int iovlen,
> uint32_t ring_size = tbr->dsize;
> uint32_t old_windex, next_windex, windex, total;
> uint64_t save_windex;
> + bool success;
> int i;
>
> total = 0;
> @@ -121,17 +122,13 @@ vmbus_txbr_write(struct vmbus_br *tbr, const
> struct iovec iov[], int iovlen,
> total += iov[i].iov_len;
> total += sizeof(save_windex);
>
> + /* Get current free location */
> + old_windex = rte_atomic_load_explicit(&tbr->windex,
> + rte_memory_order_relaxed);
> +
> /* Reserve space in ring */
> do {
> - uint32_t avail;
> -
> - /* Get current free location */
> - old_windex = tbr->windex;
> -
> - /* Prevent compiler reordering this with calculation */
> - rte_compiler_barrier();
> -
> - avail = vmbus_br_availwrite(tbr, old_windex);
> + uint32_t avail = vmbus_br_availwrite(tbr, old_windex);
>
> /* If not enough space in ring, then tell caller. */
> if (avail <= total)
> @@ -139,8 +136,13 @@ vmbus_txbr_write(struct vmbus_br *tbr, const
> struct iovec iov[], int iovlen,
>
> next_windex = vmbus_br_idxinc(old_windex, total, ring_size);
>
> - /* Atomic update of next write_index for other threads */
> - } while (!rte_atomic32_cmpset(&tbr->windex, old_windex,
> next_windex));
> + /* Atomic update of next write_index for other threads
> + * Can use weak since easy to recompute and retry.
> + */
> + success = rte_atomic_compare_exchange_weak_explicit(
> + &tbr->windex, &old_windex, next_windex,
> + rte_memory_order_acquire,
> rte_memory_order_relaxed);
> + } while (unlikely(!success));
>
> /* Space from old..new is now reserved */
> windex = old_windex;
> @@ -157,12 +159,15 @@ vmbus_txbr_write(struct vmbus_br *tbr, const
> struct iovec iov[], int iovlen,
> /* The region reserved should match region used */
> RTE_ASSERT(windex == next_windex);
>
> - /* Ensure that data is available before updating host index */
> - rte_smp_wmb();
> + /* Wait for previous producer to publish their windex update */
> + rte_wait_until_equal_32(&vbr->windex, old_windex,
> +rte_memory_order_relaxed);
>
> - /* Checkin for our reservation. wait for our turn to update host */
> - while (!rte_atomic32_cmpset(&vbr->windex, old_windex,
> next_windex))
> - rte_pause();
> + /* Publish our windex update; prior data writes ordered via release.
> + * windex is 4-byte aligned in practice (struct is page-aligned, windex
> + * at offset 0); cast launders the packed-struct alignment-1 attribute.
> + */
> + rte_atomic_store_explicit((volatile __rte_atomic uint32_t
> *)(uintptr_t)&vbr->windex,
> + next_windex, rte_memory_order_release);
>
> /* If host had read all data before this, then need to signal */
> *need_sig |= vmbus_txbr_need_signal(vbr, old_windex);
> --
> 2.53.0
^ permalink raw reply
* RE: [EXTERNAL] [PATCH v5 12/24] net/netvsc: replace rte_atomic32 with stdatomic
From: Long Li @ 2026-06-22 20:43 UTC (permalink / raw)
To: Stephen Hemminger, dev@dpdk.org; +Cc: Wei Hu
In-Reply-To: <20260620023134.42877-13-stephen@networkplumber.org>
>
> Change the rndis transaction id and buffer usage to use stdatomic functions.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/net/netvsc/hn_rndis.c | 28 +++++++++++++++++++---------
> drivers/net/netvsc/hn_rxtx.c | 12 +++++++-----
> drivers/net/netvsc/hn_var.h | 6 +++---
> 3 files changed, 29 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/netvsc/hn_rndis.c b/drivers/net/netvsc/hn_rndis.c
> index 7c54eebcef..4b1d3d5539 100644
> --- a/drivers/net/netvsc/hn_rndis.c
> +++ b/drivers/net/netvsc/hn_rndis.c
> @@ -17,7 +17,7 @@
> #include <rte_string_fns.h>
> #include <rte_memzone.h>
> #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
> #include <rte_alarm.h>
> #include <rte_branch_prediction.h>
> #include <rte_ether.h>
> @@ -59,7 +59,8 @@ hn_rndis_rid(struct hn_data *hv)
> uint32_t rid;
>
> do {
> - rid = rte_atomic32_add_return(&hv->rndis_req_id, 1);
> + rid = rte_atomic_fetch_add_explicit(&hv->rndis_req_id, 1,
> +
> rte_memory_order_seq_cst);
> } while (rid == 0);
>
> return rid;
> @@ -357,12 +358,14 @@ void hn_rndis_receive_response(struct hn_data
> *hv,
> memcpy(hv->rndis_resp, data, len);
>
> /* make sure response copied before update */
> - rte_smp_wmb();
> -
> - if (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {
> + uint32_t expected = hdr->rid;
> + if (!rte_atomic_compare_exchange_strong_explicit(&hv-
> >rndis_pending,
> + &expected, 0,
> +
> rte_memory_order_release,
> +
> rte_memory_order_relaxed)) {
> PMD_DRV_LOG(NOTICE,
> "received id %#x pending id %#x",
> - hdr->rid, (uint32_t)hv->rndis_pending);
> + hdr->rid, expected);
> }
> }
>
> @@ -388,8 +391,11 @@ static int hn_rndis_exec1(struct hn_data *hv,
> return -EINVAL;
> }
>
> + uint32_t expected = 0;
> if (comp != NULL &&
> - rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {
> + !rte_atomic_compare_exchange_strong_explicit(
> + &hv->rndis_pending, &expected, rid,
> + rte_memory_order_acquire, rte_memory_order_relaxed)) {
> PMD_DRV_LOG(ERR,
> "Request already pending");
> return -EBUSY;
> @@ -405,7 +411,8 @@ static int hn_rndis_exec1(struct hn_data *hv,
> time_t start = time(NULL);
>
> /* Poll primary channel until response received */
> - while (hv->rndis_pending == rid) {
> + while (rte_atomic_load_explicit(&hv->rndis_pending,
> + rte_memory_order_acquire)
> == rid) {
> if (hv->closed)
> return -ENETDOWN;
>
> @@ -413,7 +420,10 @@ static int hn_rndis_exec1(struct hn_data *hv,
> PMD_DRV_LOG(ERR,
> "RNDIS response timed out");
>
> - rte_atomic32_cmpset(&hv->rndis_pending,
> rid, 0);
> + expected = rid;
> +
> rte_atomic_compare_exchange_strong_explicit(
> + &hv->rndis_pending, &expected, 0,
> + rte_memory_order_release,
> rte_memory_order_relaxed);
> return -ETIMEDOUT;
> }
>
> diff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c index
> 0d770d1b25..6f536610f2 100644
> --- a/drivers/net/netvsc/hn_rxtx.c
> +++ b/drivers/net/netvsc/hn_rxtx.c
> @@ -17,7 +17,7 @@
> #include <rte_string_fns.h>
> #include <rte_memzone.h>
> #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
> #include <rte_bitmap.h>
> #include <rte_branch_prediction.h>
> #include <rte_ether.h>
> @@ -558,7 +558,8 @@ static void hn_rx_buf_free_cb(void *buf
> __rte_unused, void *opaque)
> struct hn_rx_queue *rxq = rxb->rxq;
> struct hn_data *hv = rxq->hv;
>
> - rte_atomic32_dec(&rxq->rxbuf_outstanding);
> + rte_atomic_fetch_sub_explicit(&rxq->rxbuf_outstanding, 1,
> + rte_memory_order_release);
> hn_nvs_ack_rxbuf(hv, rxb->chan, rxb->xactid); }
>
> @@ -602,8 +603,8 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct
> hn_rx_bufinfo *rxb,
> * some space available in receive area for later packets.
> */
> if (hv->rx_extmbuf_enable && dlen > hv->rx_copybreak &&
> - (uint32_t)rte_atomic32_read(&rxq->rxbuf_outstanding) <
> - hv->rxbuf_section_cnt / 2) {
> + rte_atomic_load_explicit(&rxq->rxbuf_outstanding,
> + rte_memory_order_relaxed) < hv-
> >rxbuf_section_cnt / 2) {
> struct rte_mbuf_ext_shared_info *shinfo;
> const void *rxbuf;
> rte_iova_t iova;
> @@ -619,7 +620,8 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct
> hn_rx_bufinfo *rxb,
>
> /* shinfo is already set to 1 by the caller */
> if (rte_mbuf_ext_refcnt_update(shinfo, 1) == 2)
> - rte_atomic32_inc(&rxq->rxbuf_outstanding);
> + rte_atomic_fetch_add_explicit(&rxq-
> >rxbuf_outstanding, 1,
> +
> rte_memory_order_acquire);
>
> rte_pktmbuf_attach_extbuf(m, data, iova,
> dlen + headroom, shinfo);
> diff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h index
> 574b909c82..d7124a7df9 100644
> --- a/drivers/net/netvsc/hn_var.h
> +++ b/drivers/net/netvsc/hn_var.h
> @@ -85,7 +85,7 @@ struct hn_rx_queue {
>
> void *event_buf;
> struct hn_rx_bufinfo *rxbuf_info;
> - rte_atomic32_t rxbuf_outstanding;
> + RTE_ATOMIC(uint32_t) rxbuf_outstanding;
> };
>
>
> @@ -167,8 +167,8 @@ struct hn_data {
> uint32_t rndis_agg_pkts;
> uint32_t rndis_agg_align;
>
> - volatile uint32_t rndis_pending;
> - rte_atomic32_t rndis_req_id;
> + RTE_ATOMIC(uint32_t) rndis_pending;
> + RTE_ATOMIC(uint32_t) rndis_req_id;
> uint8_t rndis_resp[256];
>
> uint32_t rss_hash;
> --
> 2.53.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox