DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 3/4] net/zxdh: optimize Rx recv pkts performance
From: Junlong Wang @ 2026-07-09 10:46 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260709104637.924861-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 16239 bytes --]

1. Add simple RX recv functions (zxdh_recv_single_pkts)
   for single-segment packet recv.
2. And optimize Rx recv pkts packed ops.
3. Remove unnecessary ZXDH_NET_F_MRG_RXBUF negotiation check and
   some unnecessary statistical counters form the xstats name tables.

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_ethdev.c     |  39 +++++--
 drivers/net/zxdh/zxdh_ethdev_ops.c |  23 ++--
 drivers/net/zxdh/zxdh_ethdev_ops.h |   4 +
 drivers/net/zxdh/zxdh_rxtx.c       | 174 +++++++++++++++++++++++------
 drivers/net/zxdh/zxdh_rxtx.h       |  16 +--
 5 files changed, 193 insertions(+), 63 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index a383619419..fe76139f3d 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -1263,18 +1263,43 @@ zxdh_dev_close(struct rte_eth_dev *dev)
 	return ret;
 }
 
-static int32_t
-zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
+/*
+ * Determine whether the current configuration requires support for scattered
+ * receive; return 1 if scattered receive is required and 0 if not.
+ */
+static int zxdh_scattered_rx(struct rte_eth_dev *eth_dev)
 {
-	struct zxdh_hw *hw = eth_dev->data->dev_private;
+	uint16_t buf_size;
 
-	if (!zxdh_pci_with_feature(hw, ZXDH_NET_F_MRG_RXBUF)) {
-		PMD_DRV_LOG(ERR, "port %u not support rx mergeable", eth_dev->data->port_id);
-		return -1;
+	if (eth_dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) {
+		eth_dev->data->lro = 1;
+		return 1;
 	}
+
+	if (eth_dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER)
+		return 1;
+
+	PMD_DRV_LOG(DEBUG, "port %u min_rx_buf_size %u",
+		eth_dev->data->port_id, eth_dev->data->min_rx_buf_size);
+	buf_size = eth_dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+	if (eth_dev->data->mtu + ZXDH_ETH_OVERHEAD > buf_size)
+		return 1;
+
+	return 0;
+}
+
+static int32_t
+zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
+{
 	eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+	eth_dev->data->scattered_rx = zxdh_scattered_rx(eth_dev);
+
 	eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
-	eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
+
+	if (eth_dev->data->scattered_rx)
+		eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
+	else
+		eth_dev->rx_pkt_burst = &zxdh_recv_single_pkts;
 
 	return 0;
 }
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.c b/drivers/net/zxdh/zxdh_ethdev_ops.c
index 50247116d9..9a8e05e941 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.c
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.c
@@ -95,10 +95,6 @@ static const struct rte_zxdh_xstats_name_off zxdh_rxq_stat_strings[] = {
 	{"good_bytes",             offsetof(struct zxdh_virtnet_rx, stats.bytes)},
 	{"errors",                 offsetof(struct zxdh_virtnet_rx, stats.errors)},
 	{"idle",                   offsetof(struct zxdh_virtnet_rx, stats.idle)},
-	{"full",                   offsetof(struct zxdh_virtnet_rx, stats.full)},
-	{"norefill",               offsetof(struct zxdh_virtnet_rx, stats.norefill)},
-	{"multicast_packets",      offsetof(struct zxdh_virtnet_rx, stats.multicast)},
-	{"broadcast_packets",      offsetof(struct zxdh_virtnet_rx, stats.broadcast)},
 	{"truncated_err",          offsetof(struct zxdh_virtnet_rx, stats.truncated_err)},
 	{"offload_cfg_err",        offsetof(struct zxdh_virtnet_rx, stats.offload_cfg_err)},
 	{"invalid_hdr_len_err",    offsetof(struct zxdh_virtnet_rx, stats.invalid_hdr_len_err)},
@@ -117,14 +113,12 @@ static const struct rte_zxdh_xstats_name_off zxdh_txq_stat_strings[] = {
 	{"good_packets",           offsetof(struct zxdh_virtnet_tx, stats.packets)},
 	{"good_bytes",             offsetof(struct zxdh_virtnet_tx, stats.bytes)},
 	{"errors",                 offsetof(struct zxdh_virtnet_tx, stats.errors)},
-	{"idle",                   offsetof(struct zxdh_virtnet_tx, stats.idle)},
-	{"norefill",               offsetof(struct zxdh_virtnet_tx, stats.norefill)},
-	{"multicast_packets",      offsetof(struct zxdh_virtnet_tx, stats.multicast)},
-	{"broadcast_packets",      offsetof(struct zxdh_virtnet_tx, stats.broadcast)},
+	{"idle",                 offsetof(struct zxdh_virtnet_tx, stats.idle)},
 	{"truncated_err",          offsetof(struct zxdh_virtnet_tx, stats.truncated_err)},
 	{"offload_cfg_err",        offsetof(struct zxdh_virtnet_tx, stats.offload_cfg_err)},
 	{"invalid_hdr_len_err",    offsetof(struct zxdh_virtnet_tx, stats.invalid_hdr_len_err)},
 	{"no_segs_err",            offsetof(struct zxdh_virtnet_tx, stats.no_segs_err)},
+	{"no_free_tx_desc_err",    offsetof(struct zxdh_virtnet_tx, stats.no_free_tx_desc_err)},
 	{"undersize_packets",      offsetof(struct zxdh_virtnet_tx, stats.size_bins[0])},
 	{"size_64_packets",        offsetof(struct zxdh_virtnet_tx, stats.size_bins[1])},
 	{"size_65_127_packets",    offsetof(struct zxdh_virtnet_tx, stats.size_bins[2])},
@@ -2026,6 +2020,19 @@ int zxdh_dev_mtu_set(struct rte_eth_dev *dev, uint16_t new_mtu)
 	uint16_t vfid = zxdh_vport_to_vfid(hw->vport);
 	int ret;
 
+	/* If device is started, refuse mtu that requires the support of
+	 * scattered packets when this feature has not been enabled before.
+	 */
+	if (dev->data->dev_started) {
+		uint32_t buf_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+		uint8_t need_scatter = (uint32_t)ZXDH_MTU_TO_PKTLEN(new_mtu) > buf_size;
+
+		if (need_scatter != dev->data->scattered_rx) {
+			PMD_DRV_LOG(ERR, "Stop port first.");
+			return -EINVAL;
+		}
+	}
+
 	if (hw->is_pf) {
 		ret = zxdh_get_panel_attr(dev, &panel);
 		if (ret != 0) {
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.h b/drivers/net/zxdh/zxdh_ethdev_ops.h
index 6dfe4be473..c49d79c232 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.h
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.h
@@ -40,6 +40,10 @@
 #define ZXDH_SPM_SPEED_4X_100G         RTE_BIT32(10)
 #define ZXDH_SPM_SPEED_4X_200G         RTE_BIT32(11)
 
+#define ZXDH_VLAN_TAG_LEN   4
+#define ZXDH_ETH_OVERHEAD  (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + ZXDH_VLAN_TAG_LEN * 2)
+#define ZXDH_MTU_TO_PKTLEN(mtu) ((mtu) + ZXDH_ETH_OVERHEAD)
+
 struct zxdh_np_stats_data {
 	uint64_t n_pkts_dropped;
 	uint64_t n_bytes_dropped;
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index 93506a4b49..ab0510a753 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -613,10 +613,12 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 	uint16_t i, used_idx;
 	uint16_t id;
 
+	used_idx = vq->vq_used_cons_idx;
+	rte_prefetch0(&desc[used_idx]);
+
 	for (i = 0; i < num; i++) {
 		used_idx = vq->vq_used_cons_idx;
-		/**
-		 * desc_is_used has a load-acquire or rte_io_rmb inside
+		/* desc_is_used has a load-acquire or rte_io_rmb inside
 		 * and wait for used desc in virtqueue.
 		 */
 		if (!desc_is_used(&desc[used_idx], vq))
@@ -823,17 +825,52 @@ zxdh_rx_update_mbuf(struct zxdh_hw *hw, struct rte_mbuf *m, struct zxdh_net_hdr_
 	}
 }
 
-static void zxdh_discard_rxbuf(struct zxdh_virtqueue *vq, struct rte_mbuf *m)
+static void refill_desc_unwrap(struct zxdh_virtqueue *vq,
+		struct rte_mbuf **cookie, uint16_t nb_pkts)
 {
-	int32_t error = 0;
-	/*
-	 * Requeue the discarded mbuf. This should always be
-	 * successful since it was just dequeued.
-	 */
-	error = zxdh_enqueue_recv_refill_packed(vq, &m, 1);
-	if (unlikely(error)) {
-		PMD_RX_LOG(ERR, "cannot enqueue discarded mbuf");
-		rte_pktmbuf_free(m);
+	struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
+	struct zxdh_vq_desc_extra *dxp;
+	uint16_t flags = vq->cached_flags;
+	int32_t i;
+	uint16_t idx;
+
+	idx = vq->vq_avail_idx;
+	for (i = 0; i < nb_pkts; i++) {
+		dxp = &vq->vq_descx[idx];
+		dxp->cookie = (void *)cookie[i];
+		start_dp[idx].addr = rte_mbuf_iova_get(cookie[i]) + RTE_PKTMBUF_HEADROOM;
+		start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM;
+		zxdh_queue_store_flags_packed(&start_dp[idx], flags);
+		idx++;
+	}
+	vq->vq_avail_idx += nb_pkts;
+	vq->vq_free_cnt = vq->vq_free_cnt - nb_pkts;
+}
+
+static void refill_que_descs(struct zxdh_virtqueue *vq, struct rte_eth_dev *dev)
+{
+	/* free_cnt may include mrg descs */
+	struct rte_mbuf *new_pkts[ZXDH_MBUF_BURST_SZ];
+	uint16_t free_cnt = RTE_MIN(ZXDH_MBUF_BURST_SZ, vq->vq_free_cnt);
+	struct zxdh_virtnet_rx *rxvq = &vq->rxq;
+	uint16_t  unwrap_cnt, left_cnt;
+
+	if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
+		left_cnt = free_cnt;
+		unwrap_cnt = 0;
+		if ((vq->vq_avail_idx + free_cnt) >= vq->vq_nentries) {
+			unwrap_cnt = vq->vq_nentries - vq->vq_avail_idx;
+			left_cnt = free_cnt - unwrap_cnt;
+			refill_desc_unwrap(vq, new_pkts, unwrap_cnt);
+			vq->vq_avail_idx = 0;
+			vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+		}
+		if (left_cnt)
+			refill_desc_unwrap(vq, new_pkts + unwrap_cnt, left_cnt);
+
+		rte_io_wmb();
+	} else {
+		dev->data->rx_mbuf_alloc_failed += free_cnt;
 	}
 }
 
@@ -852,7 +889,6 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 	uint16_t len = 0;
 	uint32_t seg_num = 0;
 	uint32_t seg_res = 0;
-	uint32_t error = 0;
 	uint16_t hdr_size = 0;
 	uint16_t nb_rx = 0;
 	uint16_t i;
@@ -873,7 +909,8 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 		rx_pkts[nb_rx] = rxm;
 		prev = rxm;
 		len = lens[i];
-		header = rte_pktmbuf_mtod(rxm, struct zxdh_net_hdr_ul *);
+		header = (struct zxdh_net_hdr_ul *)((char *)
+					rxm->buf_addr + RTE_PKTMBUF_HEADROOM);
 
 		seg_num  = header->type_hdr.num_buffers;
 
@@ -886,7 +923,7 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			rxvq->stats.invalid_hdr_len_err++;
 			continue;
 		}
-		rxm->data_off += hdr_size;
+		rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
 		rxm->nb_segs = seg_num;
 		rxm->ol_flags = 0;
 		rcvd_pkt_len = len - hdr_size;
@@ -902,18 +939,19 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			len = lens[i];
 			rxm = rcv_pkts[i];
 			rxm->data_len = len;
+			rxm->data_off = RTE_PKTMBUF_HEADROOM;
 			rcvd_pkt_len += len;
 			prev->next = rxm;
 			prev = rxm;
 			rxm->next = NULL;
-			seg_res -= 1;
+			seg_res--;
 		}
 
 		if (!seg_res) {
 			if (rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len) {
 				PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
 					rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
-				zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
+				rte_pktmbuf_free(rx_pkts[nb_rx]);
 				rxvq->stats.errors++;
 				rxvq->stats.truncated_err++;
 				continue;
@@ -942,14 +980,14 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			prev->next = rxm;
 			prev = rxm;
 			rxm->next = NULL;
-			extra_idx += 1;
+			extra_idx++;
 		}
 		seg_res -= rcv_cnt;
 		if (!seg_res) {
 			if (unlikely(rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len)) {
 				PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
 					rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
-				zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
+				rte_pktmbuf_free(rx_pkts[nb_rx]);
 				rxvq->stats.errors++;
 				rxvq->stats.truncated_err++;
 				continue;
@@ -961,26 +999,88 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 	rxvq->stats.packets += nb_rx;
 
 refill:
-	/* Allocate new mbuf for the used descriptor */
-	if (likely(!zxdh_queue_full(vq))) {
-		struct rte_mbuf *new_pkts[ZXDH_MBUF_BURST_SZ];
-		/* free_cnt may include mrg descs */
-		uint16_t free_cnt = RTE_MIN(vq->vq_free_cnt, ZXDH_MBUF_BURST_SZ);
-
-		if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
-			error = zxdh_enqueue_recv_refill_packed(vq, new_pkts, free_cnt);
-			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
-			}
+	if (vq->vq_free_cnt > 0) {
+		struct rte_eth_dev *dev = hw->eth_dev;
+		refill_que_descs(vq, dev);
+		zxdh_queue_notify(vq);
+	}
 
-			if (unlikely(zxdh_queue_kick_prepare_packed(vq)))
-				zxdh_queue_notify(vq);
-		} else {
-			struct rte_eth_dev *dev = hw->eth_dev;
+	return nb_rx;
+}
 
-			dev->data->rx_mbuf_alloc_failed += free_cnt;
-		}
+static inline int zxdh_init_mbuf(struct rte_mbuf *rxm, uint16_t len,
+		struct zxdh_hw *hw, struct zxdh_virtnet_rx *rxvq)
+{
+	uint16_t hdr_size = 0;
+	struct zxdh_net_hdr_ul *header;
+
+	header = rte_pktmbuf_mtod(rxm, struct zxdh_net_hdr_ul *);
+	rxm->ol_flags = 0;
+	rxm->vlan_tci = 0;
+	rxm->vlan_tci_outer = 0;
+
+	hdr_size = header->type_hdr.pd_len << 1;
+	if (unlikely(header->type_hdr.num_buffers != 1)) {
+		PMD_RX_LOG(DEBUG, "hdr_size:%u nb_segs %d is invalid",
+			hdr_size, header->type_hdr.num_buffers);
+		rte_pktmbuf_free(rxm);
+		rxvq->stats.invalid_hdr_len_err++;
+		return -1;
+	}
+	zxdh_rx_update_mbuf(hw, rxm, header);
+
+	rxm->nb_segs = 1;
+	rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
+	rxm->data_len = len - hdr_size;
+	rxm->port = hw->port_id;
+
+	if (rxm->data_len != rxm->pkt_len) {
+		PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d  bufaddr %p.",
+					rxm->data_len, rxm->pkt_len, rxm->buf_addr);
+		rte_pktmbuf_free(rxm);
+		rxvq->stats.truncated_err++;
+		rxvq->stats.errors++;
+		return -1;
+	}
+	return 0;
+}
+
+uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts)
+{
+	struct zxdh_virtnet_rx *rxvq = rx_queue;
+	struct zxdh_virtqueue *vq = rxvq->vq;
+	struct zxdh_hw *hw = vq->hw;
+	uint32_t lens[ZXDH_MBUF_BURST_SZ];
+	uint16_t nb_rx = 0;
+	uint16_t num;
+	uint16_t i;
+
+	num = nb_pkts;
+	if (unlikely(num > ZXDH_MBUF_BURST_SZ))
+		num = ZXDH_MBUF_BURST_SZ;
+	num = zxdh_dequeue_burst_rx_packed(vq, rcv_pkts, lens, num);
+	if (num == 0) {
+		rxvq->stats.idle++;
+		goto refill;
+	}
+
+	for (i = 0; i < num; i++) {
+		struct rte_mbuf *rxm = rcv_pkts[i];
+		uint16_t len = lens[i];
+
+		if (unlikely(zxdh_init_mbuf(rxm, len, hw, &vq->rxq) < 0))
+			continue;
+		rcv_pkts[nb_rx] = rxm;
+		zxdh_update_packet_stats(&rxvq->stats, rxm);
+		nb_rx++;
+	}
+	rxvq->stats.packets += nb_rx;
+
+refill:
+	if (vq->vq_free_cnt > 0) {
+		struct rte_eth_dev *dev = hw->eth_dev;
+		refill_que_descs(vq, dev);
+		zxdh_queue_notify(vq);
 	}
 	return nb_rx;
 }
diff --git a/drivers/net/zxdh/zxdh_rxtx.h b/drivers/net/zxdh/zxdh_rxtx.h
index 424048607e..dba9567414 100644
--- a/drivers/net/zxdh/zxdh_rxtx.h
+++ b/drivers/net/zxdh/zxdh_rxtx.h
@@ -36,29 +36,22 @@ struct zxdh_virtnet_stats {
 	uint64_t bytes;
 	uint64_t errors;
 	uint64_t idle;
-	uint64_t full;
-	uint64_t norefill;
-	uint64_t multicast;
-	uint64_t broadcast;
 	uint64_t truncated_err;
 	uint64_t offload_cfg_err;
 	uint64_t invalid_hdr_len_err;
 	uint64_t no_segs_err;
+	uint64_t no_free_tx_desc_err;
 	uint64_t size_bins[8];
 };
 
 struct __rte_cache_aligned zxdh_virtnet_rx {
 	struct zxdh_virtqueue         *vq;
-
-	uint64_t                  mbuf_initializer; /* value to init mbufs. */
 	struct rte_mempool       *mpool;            /* mempool for mbuf allocation */
-	uint16_t                  queue_id;         /* DPDK queue index. */
-	uint16_t                  port_id;          /* Device port identifier. */
 	struct zxdh_virtnet_stats      stats;
 	const struct rte_memzone *mz;               /* mem zone to populate RX ring. */
-
-	/* dummy mbuf, for wraparound when processing RX ring. */
-	struct rte_mbuf           fake_mbuf;
+	uint64_t offloads;
+	uint16_t                  queue_id;         /* DPDK queue index. */
+	uint16_t                  port_id;          /* Device port identifier. */
 };
 
 struct __rte_cache_aligned zxdh_virtnet_tx {
@@ -75,5 +68,6 @@ struct __rte_cache_aligned zxdh_virtnet_tx {
 uint16_t zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts);
 
 #endif  /* ZXDH_RXTX_H */
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 39105 bytes --]

^ permalink raw reply related

* [PATCH v9 2/4] net/zxdh: optimize queue structure to improve performance
From: Junlong Wang @ 2026-07-09 10:46 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260709104637.924861-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 16846 bytes --]

1. Reorganize structure fields for better cache locality.
2. Remove RX software ring (sw_ring) to reduce memory allocation and
   copy.
3. Remove zxdh_mb(), use native rte_mb().
4. optimize zxdh_queue_notify() functions, remove unnecessary feature
   check.

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_ethdev.c |  33 +--------
 drivers/net/zxdh/zxdh_pci.c    |   2 +-
 drivers/net/zxdh/zxdh_queue.c  |  11 ++-
 drivers/net/zxdh/zxdh_queue.h  | 120 ++++++++++++++++-----------------
 drivers/net/zxdh/zxdh_rxtx.c   |  22 +++---
 5 files changed, 77 insertions(+), 111 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index 80ff19b3ea..a383619419 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -644,7 +644,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	struct zxdh_virtnet_tx *txvq = NULL;
 	struct zxdh_virtqueue *vq = NULL;
 	size_t sz_hdr_mz = 0;
-	void *sw_ring = NULL;
 	int32_t queue_type = zxdh_get_queue_type(vtpci_logic_qidx);
 	int32_t numa_node = dev->device->numa_node;
 	uint16_t vtpci_phy_qidx = 0;
@@ -692,11 +691,10 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	vq->vq_queue_index = vtpci_phy_qidx;
 	vq->vq_nentries = vq_size;
 
-	vq->vq_packed.used_wrap_counter = 1;
-	vq->vq_packed.cached_flags = ZXDH_VRING_PACKED_DESC_F_AVAIL;
-	vq->vq_packed.event_flags_shadow = 0;
+	vq->used_wrap_counter = 1;
+	vq->cached_flags = ZXDH_VRING_PACKED_DESC_F_AVAIL;
 	if (queue_type == ZXDH_VTNET_RQ)
-		vq->vq_packed.cached_flags |= ZXDH_VRING_DESC_F_WRITE;
+		vq->cached_flags |= ZXDH_VRING_DESC_F_WRITE;
 
 	/*
 	 * Reserve a memzone for vring elements
@@ -741,16 +739,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	}
 
 	if (queue_type == ZXDH_VTNET_RQ) {
-		size_t sz_sw = (ZXDH_MBUF_BURST_SZ + vq_size) * sizeof(vq->sw_ring[0]);
-
-		sw_ring = rte_zmalloc_socket("sw_ring", sz_sw, RTE_CACHE_LINE_SIZE, numa_node);
-		if (!sw_ring) {
-			PMD_DRV_LOG(ERR, "can not allocate RX soft ring");
-			ret = -ENOMEM;
-			goto fail_q_alloc;
-		}
-
-		vq->sw_ring = sw_ring;
 		rxvq = &vq->rxq;
 		rxvq->vq = vq;
 		rxvq->port_id = dev->data->port_id;
@@ -764,23 +752,9 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 		txvq->zxdh_net_hdr_mem = hdr_mz->iova;
 	}
 
-	vq->offset = offsetof(struct rte_mbuf, buf_iova);
 	if (queue_type == ZXDH_VTNET_TQ) {
 		struct zxdh_tx_region *txr = hdr_mz->addr;
-		uint32_t i;
-
 		memset(txr, 0, vq_size * sizeof(*txr));
-		for (i = 0; i < vq_size; i++) {
-			/* first indirect descriptor is always the tx header */
-			struct zxdh_vring_packed_desc *start_dp = txr[i].tx_packed_indir;
-
-			zxdh_vring_desc_init_indirect_packed(start_dp,
-					RTE_DIM(txr[i].tx_packed_indir));
-			start_dp->addr = txvq->zxdh_net_hdr_mem + i * sizeof(*txr) +
-					offsetof(struct zxdh_tx_region, tx_hdr);
-			/* length will be updated to actual pi hdr size when xmit pkt */
-			start_dp->len = 0;
-		}
 	}
 	if (ZXDH_VTPCI_OPS(hw)->setup_queue(hw, vq) < 0) {
 		PMD_DRV_LOG(ERR, "setup_queue failed");
@@ -788,7 +762,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	}
 	return 0;
 fail_q_alloc:
-	rte_free(sw_ring);
 	rte_memzone_free(hdr_mz);
 	rte_memzone_free(mz);
 	rte_free(vq);
diff --git a/drivers/net/zxdh/zxdh_pci.c b/drivers/net/zxdh/zxdh_pci.c
index 4ba31905fc..0bc27ed111 100644
--- a/drivers/net/zxdh/zxdh_pci.c
+++ b/drivers/net/zxdh/zxdh_pci.c
@@ -231,7 +231,7 @@ zxdh_notify_queue(struct zxdh_hw *hw, struct zxdh_virtqueue *vq)
 
 	notify_data = ((uint32_t)vq->vq_avail_idx << 16) | vq->vq_queue_index;
 	if (zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) &&
-			(vq->vq_packed.cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
+			(vq->cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
 		notify_data |= RTE_BIT32(31);
 
 	PMD_DRV_LOG(DEBUG, "queue:%d notify_data 0x%x notify_addr 0x%p",
diff --git a/drivers/net/zxdh/zxdh_queue.c b/drivers/net/zxdh/zxdh_queue.c
index 7162593b16..4668cb5d13 100644
--- a/drivers/net/zxdh/zxdh_queue.c
+++ b/drivers/net/zxdh/zxdh_queue.c
@@ -407,7 +407,7 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
 {
 	struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
 	struct zxdh_vq_desc_extra *dxp;
-	uint16_t flags = vq->vq_packed.cached_flags;
+	uint16_t flags = vq->cached_flags;
 	int32_t i;
 	uint16_t idx;
 
@@ -415,7 +415,6 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
 		idx = vq->vq_avail_idx;
 		dxp = &vq->vq_descx[idx];
 		dxp->cookie = (void *)cookie[i];
-		dxp->ndescs = 1;
 		/* rx pkt fill in data_off */
 		start_dp[idx].addr = rte_mbuf_iova_get(cookie[i]) + RTE_PKTMBUF_HEADROOM;
 		start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM;
@@ -423,8 +422,8 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
 		zxdh_queue_store_flags_packed(&start_dp[idx], flags);
 		if (++vq->vq_avail_idx >= vq->vq_nentries) {
 			vq->vq_avail_idx -= vq->vq_nentries;
-			vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
-			flags = vq->vq_packed.cached_flags;
+			vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+			flags = vq->cached_flags;
 		}
 	}
 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
@@ -467,7 +466,7 @@ void zxdh_queue_rxvq_flush(struct zxdh_virtqueue *vq)
 	int32_t cnt = 0;
 
 	i = vq->vq_used_cons_idx;
-	while (zxdh_desc_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
+	while (desc_is_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
 		dxp = &vq->vq_descx[descs[i].id];
 		if (dxp->cookie != NULL) {
 			rte_pktmbuf_free(dxp->cookie);
@@ -477,7 +476,7 @@ void zxdh_queue_rxvq_flush(struct zxdh_virtqueue *vq)
 		vq->vq_used_cons_idx++;
 		if (vq->vq_used_cons_idx >= vq->vq_nentries) {
 			vq->vq_used_cons_idx -= vq->vq_nentries;
-			vq->vq_packed.used_wrap_counter ^= 1;
+			vq->used_wrap_counter ^= 1;
 		}
 		i = vq->vq_used_cons_idx;
 	}
diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index 711ea291d0..b079272162 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -9,6 +9,7 @@
 
 #include <rte_common.h>
 #include <rte_atomic.h>
+#include <rte_io.h>
 
 #include "zxdh_ethdev.h"
 #include "zxdh_rxtx.h"
@@ -117,7 +118,6 @@ struct zxdh_vring_packed_desc_event {
 };
 
 struct zxdh_vring_packed {
-	uint32_t num;
 	struct zxdh_vring_packed_desc *desc;
 	struct zxdh_vring_packed_desc_event *driver;
 	struct zxdh_vring_packed_desc_event *device;
@@ -129,50 +129,59 @@ struct zxdh_vq_desc_extra {
 	uint16_t next;
 };
 
+struct zxdh_vring {
+	uint32_t num;
+	struct zxdh_vring_desc  *desc;
+	struct zxdh_vring_avail *avail;
+	struct zxdh_vring_used  *used;
+};
+
 struct zxdh_virtqueue {
+	union {
+		struct {
+			struct zxdh_vring ring; /**< vring keeping desc, used and avail */
+		} vq_split;
+		struct __rte_packed_begin {
+			struct zxdh_vring_packed ring;
+		} __rte_packed_end vq_packed;
+	};
 	struct zxdh_hw  *hw; /* < zxdh_hw structure pointer. */
 
-	struct {
-		/* vring keeping descs and events */
-		struct zxdh_vring_packed ring;
-		uint8_t used_wrap_counter;
-		uint8_t rsv;
-		uint16_t cached_flags; /* < cached flags for descs */
-		uint16_t event_flags_shadow;
-		uint16_t rsv1;
-	} vq_packed;
-
-	uint16_t vq_used_cons_idx; /* < last consumed descriptor */
-	uint16_t vq_nentries;  /* < vring desc numbers */
-	uint16_t vq_free_cnt;  /* < num of desc available */
-	uint16_t vq_avail_idx; /* < sync until needed */
-	uint16_t vq_free_thresh; /* < free threshold */
-	uint16_t rsv2;
-
-	void *vq_ring_virt_mem;  /* < linear address of vring */
-	uint32_t vq_ring_size;
+	uint16_t vq_used_cons_idx; /**< last consumed descriptor */
+	uint16_t vq_avail_idx; /**< sync until needed */
+	uint16_t vq_nentries;  /**< vring desc numbers */
+	uint16_t vq_free_cnt;  /**< num of desc available */
+
+	uint16_t cached_flags; /**< cached flags for descs */
+	uint8_t used_wrap_counter;
+	uint8_t rsv;
+	uint16_t vq_free_thresh; /**< free threshold */
+	uint16_t next_qidx;
+
+	void *notify_addr;
 
 	union {
 		struct zxdh_virtnet_rx rxq;
 		struct zxdh_virtnet_tx txq;
 	};
 
-	/*
-	 * physical address of vring, or virtual address
-	 */
-	rte_iova_t vq_ring_mem;
+	uint16_t vq_queue_index; /* PACKED: phy_idx, SPLIT: logic_idx */
+	uint16_t event_flags_shadow;
+	uint32_t vq_ring_size;
 
-	/*
+	/**
 	 * Head of the free chain in the descriptor table. If
 	 * there are no free descriptors, this will be set to
 	 * VQ_RING_DESC_CHAIN_END.
-	 */
+	 **/
 	uint16_t  vq_desc_head_idx;
 	uint16_t  vq_desc_tail_idx;
-	uint16_t  vq_queue_index;   /* < PCI queue index */
-	uint16_t  offset; /* < relative offset to obtain addr in mbuf */
-	uint16_t *notify_addr;
-	struct rte_mbuf **sw_ring;  /* < RX software ring. */
+	uint32_t rsv_8B;
+
+	void *vq_ring_virt_mem;  /**< linear address of vring*/
+	/* physical address of vring, or virtual address for virtio_user. */
+	rte_iova_t vq_ring_mem;
+
 	struct zxdh_vq_desc_extra vq_descx[];
 };
 
@@ -296,10 +305,9 @@ static inline void
 zxdh_vring_init_packed(struct zxdh_vring_packed *vr, uint8_t *p,
 		unsigned long align, uint32_t num)
 {
-	vr->num    = num;
 	vr->desc   = (struct zxdh_vring_packed_desc *)p;
 	vr->driver = (struct zxdh_vring_packed_desc_event *)(p +
-				 vr->num * sizeof(struct zxdh_vring_packed_desc));
+				 num * sizeof(struct zxdh_vring_packed_desc));
 	vr->device = (struct zxdh_vring_packed_desc_event *)RTE_ALIGN_CEIL(((uintptr_t)vr->driver +
 				 sizeof(struct zxdh_vring_packed_desc_event)), align);
 }
@@ -331,30 +339,21 @@ zxdh_vring_desc_init_indirect_packed(struct zxdh_vring_packed_desc *dp, int32_t
 static inline void
 zxdh_queue_disable_intr(struct zxdh_virtqueue *vq)
 {
-	if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_DISABLE) {
-		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
-		vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
+	if (vq->event_flags_shadow != ZXDH_RING_EVENT_FLAGS_DISABLE) {
+		vq->event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
+		vq->vq_packed.ring.driver->desc_event_flags = vq->event_flags_shadow;
 	}
 }
 
 static inline void
 zxdh_queue_enable_intr(struct zxdh_virtqueue *vq)
 {
-	if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
-		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
-		vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
+	if (vq->event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
+		vq->event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
+		vq->vq_packed.ring.driver->desc_event_flags = vq->event_flags_shadow;
 	}
 }
 
-static inline void
-zxdh_mb(uint8_t weak_barriers)
-{
-	if (weak_barriers)
-		rte_atomic_thread_fence(rte_memory_order_seq_cst);
-	else
-		rte_mb();
-}
-
 static inline
 int32_t desc_is_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue *vq)
 {
@@ -365,7 +364,7 @@ int32_t desc_is_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue
 	rte_io_rmb();
 	used = !!(flags & ZXDH_VRING_PACKED_DESC_F_USED);
 	avail = !!(flags & ZXDH_VRING_PACKED_DESC_F_AVAIL);
-	return avail == used && used == vq->vq_packed.used_wrap_counter;
+	return avail == used && used == vq->used_wrap_counter;
 }
 
 static inline int32_t
@@ -381,22 +380,17 @@ zxdh_queue_store_flags_packed(struct zxdh_vring_packed_desc *dp, uint16_t flags)
 	dp->flags = flags;
 }
 
-static inline int32_t
-zxdh_desc_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue *vq)
-{
-	uint16_t flags;
-	uint16_t used, avail;
-
-	flags = desc->flags;
-	rte_io_rmb();
-	used = !!(flags & ZXDH_VRING_PACKED_DESC_F_USED);
-	avail = !!(flags & ZXDH_VRING_PACKED_DESC_F_AVAIL);
-	return avail == used && used == vq->vq_packed.used_wrap_counter;
-}
-
 static inline void zxdh_queue_notify(struct zxdh_virtqueue *vq)
 {
-	ZXDH_VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
+	/* Bit[0:15]: vq queue index
+	 * Bit[16:30]: avail index
+	 * Bit[31]: avail wrap counter
+	 */
+	uint32_t notify_data = ((uint32_t)(!!(vq->cached_flags &
+		ZXDH_VRING_PACKED_DESC_F_AVAIL)) << 31) |
+		((uint32_t)vq->vq_avail_idx << 16) |
+		vq->vq_queue_index;
+	rte_write32(notify_data, vq->notify_addr);
 }
 
 static inline int32_t
@@ -404,7 +398,7 @@ zxdh_queue_kick_prepare_packed(struct zxdh_virtqueue *vq)
 {
 	uint16_t flags = 0;
 
-	zxdh_mb(1);
+	rte_mb();
 	flags = vq->vq_packed.ring.device->desc_event_flags;
 
 	return (flags != ZXDH_RING_EVENT_FLAGS_DISABLE);
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index db86922aea..93506a4b49 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -216,7 +216,7 @@ zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
 	/* desc_is_used has a load-acquire or rte_io_rmb inside
 	 * and wait for used desc in virtqueue.
 	 */
-	while (num > 0 && zxdh_desc_used(&desc[used_idx], vq)) {
+	while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
 		id = desc[used_idx].id;
 		do {
 			curr_id = used_idx;
@@ -226,7 +226,7 @@ zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
 			num -= dxp->ndescs;
 			if (used_idx >= size) {
 				used_idx -= size;
-				vq->vq_packed.used_wrap_counter ^= 1;
+				vq->used_wrap_counter ^= 1;
 			}
 			if (dxp->cookie != NULL) {
 				rte_pktmbuf_free(dxp->cookie);
@@ -340,7 +340,7 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
 	struct zxdh_virtqueue *vq = txvq->vq;
 	uint16_t id = vq->vq_avail_idx;
 	struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
-	uint16_t flags = vq->vq_packed.cached_flags;
+	uint16_t flags = vq->cached_flags;
 	struct zxdh_net_hdr_dl *hdr = NULL;
 	uint8_t hdr_len = vq->hw->dl_net_hdr_len;
 	struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[id];
@@ -355,7 +355,7 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
 	dp->id   = id;
 	if (++vq->vq_avail_idx >= vq->vq_nentries) {
 		vq->vq_avail_idx -= vq->vq_nentries;
-		vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+		vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 	}
 	vq->vq_free_cnt--;
 	zxdh_queue_store_flags_packed(dp, flags);
@@ -381,7 +381,7 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 
 	dxp->ndescs = needed;
 	dxp->cookie = cookie;
-	head_flags |= vq->vq_packed.cached_flags;
+	head_flags |= vq->cached_flags;
 
 	start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
 	start_dp[idx].len  = hdr_len;
@@ -392,7 +392,7 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 	idx++;
 	if (idx >= vq->vq_nentries) {
 		idx -= vq->vq_nentries;
-		vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+		vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 	}
 
 	zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
@@ -404,14 +404,14 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 		if (likely(idx != head_idx)) {
 			uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
 
-			flags |= vq->vq_packed.cached_flags;
+			flags |= vq->cached_flags;
 			start_dp[idx].flags = flags;
 		}
 
 		idx++;
 		if (idx >= vq->vq_nentries) {
 			idx -= vq->vq_nentries;
-			vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+			vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 		}
 	} while ((cookie = cookie->next) != NULL);
 
@@ -480,7 +480,7 @@ zxdh_xmit_flush(struct zxdh_virtqueue *vq)
 			free_cnt += dxp->ndescs;
 			if (used_idx >= size) {
 				used_idx -= size;
-				vq->vq_packed.used_wrap_counter ^= 1;
+				vq->used_wrap_counter ^= 1;
 			}
 			if (dxp->cookie != NULL) {
 				rte_pktmbuf_free(dxp->cookie);
@@ -619,7 +619,7 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 		 * desc_is_used has a load-acquire or rte_io_rmb inside
 		 * and wait for used desc in virtqueue.
 		 */
-		if (!zxdh_desc_used(&desc[used_idx], vq))
+		if (!desc_is_used(&desc[used_idx], vq))
 			return i;
 		len[i] = desc[used_idx].len;
 		id = desc[used_idx].id;
@@ -637,7 +637,7 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 		vq->vq_used_cons_idx++;
 		if (vq->vq_used_cons_idx >= vq->vq_nentries) {
 			vq->vq_used_cons_idx -= vq->vq_nentries;
-			vq->vq_packed.used_wrap_counter ^= 1;
+			vq->used_wrap_counter ^= 1;
 		}
 	}
 	return i;
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 38856 bytes --]

^ permalink raw reply related

* [PATCH v9 1/4] net/zxdh: fix queue enable intr issues
From: Junlong Wang @ 2026-07-09 10:46 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang, stable
In-Reply-To: <20260709104637.924861-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 1196 bytes --]

Fix incorrect condition check in zxdh_queue_enable_intr.
Change "==" to "!=", consistent with zxdh_queue_disable_intr logic,
to properly enable interrupts when event_flags_shadow is not
already set to ENABLE state.

Fixes: 7677f3871ef3 ("net/zxdh: setup Rx/Tx queues and interrupt")
Cc: stable@dpdk.org

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_queue.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index 1a0c8a0d90..711ea291d0 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -340,8 +340,8 @@ zxdh_queue_disable_intr(struct zxdh_virtqueue *vq)
 static inline void
 zxdh_queue_enable_intr(struct zxdh_virtqueue *vq)
 {
-	if (vq->vq_packed.event_flags_shadow == ZXDH_RING_EVENT_FLAGS_DISABLE) {
-		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
+	if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
+		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
 		vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
 	}
 }
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 2002 bytes --]

^ permalink raw reply related

* [PATCH v9 0/4] net/zxdh: optimize Rx/Tx path performance
From: Junlong Wang @ 2026-07-09 10:46 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 4284 bytes --]

v9:
  - Remove add simple Tx xmit functions (zxdh_xmit_pkts_simple) in the last patch.

v8:
  - Add checked the size of ZXDH_DL_NET_HDR_SIZE and RTE_PKTMBUF_HEADROOM in
    zxdh_xmit_pkts_simple() before submitting. Add static_assert to reject builds with insufficient
    default headroom at compile time.

v7:
  - Add a new xmit prepare func for xmit_pkts_simple, which will checked the size of
    ZXDH_DL_NET_HDR_SIZE and RTE_PKTMBUF_HEADROOM.

v6:
  - Remove unnecessary error checking code in submit_to_backend_simple() and
    pkt_padding(). Since as the max dl_net_hdr_len is always less than
    RTE_PKTMBUF_HEADROOM, rte_pktmbuf_prepend() cannot fail in the
    simple path (single-segment mbufs).
v5:
  - Reorganize patch series, placing interrupt fix as the first patch
    and fix condition check to properly enable interrupts.
  - Fix zxdh_recv_single_pkts() not compacting rcv_pkts[] on failure,
    which could cause use-after-free and mbuf leak.
  - Fix tx_bunch() and tx1() missing store barrier before setting AVAIL flag,
    preventing data race on weakly-ordered architectures.
  - Fix submit_to_backend_simple() writing descriptors for packets that
    failed pkt_padding(), causing mbuf leak.
v4:
  - fix some AI review issues.
  - fix queue enable intr bug.
v3:
  - remove unnecessary NULL check in zxdh_init_queue.
  - Split Ring: Bit[31] is unused and reserved, zxdh_queue_notify(): removing the
    zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) check;
  - remove unnecessary double-free in in zxdh_recv_single_pkts();
  - used rte_pktmbuf_mtod();
  - remove rxq_get_vq(q) macro, use q->vq and apply it consistently;
  - Refactoring scatter and mtu check logic in zxdh_dev_mtu_set();
  - set txdp->id = avail_idx + i in tx_bunch/tx1.
  - add comment documenting zxdh_xmit_enqueue_append() now sets dxp->cookie = NULL for
    the head slot and stores cookies per descriptor via dep[idx].cookie.
  - add one-line comment noting tx_bunch() is the simple path handles single-segment.
  - remove unnecessary Extra initialization and the uint32_t cast.
v2:
  - zxdh_rxtx.c, pkt_padding(): modifyed the return value of pkt_padding();
  - zxdh_rxtx.c, zxdh_recv_single_pkts(): modifyed When zxdh_init_mbuf() fails
    the loop does "continue" and free mbufs;
  - zxdh_rxtx.c, refill_desc_unwrap(): Add rte_io_wmb() before writing flags
    in the refill_que_descs();
  - zxdh_queue.h, zxdh_queue_enable_intr(): Remove unnecessary function of zxdh_queue_enable_intr;
  - zxdh_ethdev.c, zxdh_init_queue(): changed the hdr_mz NULL check logic;
  - zxdh_rxtx.c, zxdh_xmit_pkts_simple()、zxdh_recv_single_pkts(): add stats.bytes count;
  - zxdh_rxtx.c, zxdh_init_mbuf():remove  rte_pktmbuf_dump(stdout, rxm, 40);
  - zxdh_ethdev.c, zxdh_dev_free_mbufs(): using rte_pktmbuf_free() to free mbufs;
  - Splitting into separate patches, structure reorganization and sw_ring removal、
    RX recv optimize、Tx xmit optimize、Tx;
v1:
  This patch optimizes the ZXDH PMD's receive and transmit path for better
  performance through several improvements:
- Add simple TX/RX burst functions (zxdh_xmit_pkts_simple and
  zxdh_recv_single_pkts) for single-segment packet scenarios.
- Remove RX software ring (sw_ring) to reduce memory allocation and
  copy.
- Optimize descriptor management with prefetching and simplified
  cleanup.
- Reorganize structure fields for better cache locality.

  These changes reduce CPU cycles and memory bandwidth consumption,
  resulting in improved packet processing throughput.

Junlong Wang (4):
  net/zxdh: fix queue enable intr issues
  net/zxdh: optimize queue structure to improve performance
  net/zxdh: optimize Rx recv pkts performance
  net/zxdh: optimize Tx xmit pkts performance

 drivers/net/zxdh/zxdh_ethdev.c     |  76 ++++---
 drivers/net/zxdh/zxdh_ethdev_ops.c |  23 +-
 drivers/net/zxdh/zxdh_ethdev_ops.h |   4 +
 drivers/net/zxdh/zxdh_pci.c        |   2 +-
 drivers/net/zxdh/zxdh_queue.c      |  11 +-
 drivers/net/zxdh/zxdh_queue.h      | 122 ++++++-----
 drivers/net/zxdh/zxdh_rxtx.c       | 324 ++++++++++++++++++-----------
 drivers/net/zxdh/zxdh_rxtx.h       |  27 +--
 8 files changed, 329 insertions(+), 260 deletions(-)

-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 7721 bytes --]

^ permalink raw reply

* RE: [PATCH] net/enic: fix potential null dereference in flow mask check
From: Hyong Youb Kim (hyonkim) @ 2026-07-09  9:57 UTC (permalink / raw)
  To: Alexey Simakov, Thomas Monjalon, John Daley (johndale),
	Nelson Escobar (neescoba)
  Cc: dev@dpdk.org, stable@dpdk.org
In-Reply-To: <20260707085831.40355-1-bigalex934@gmail.com>

> -----Original Message-----
> From: Alexey Simakov <bigalex934@gmail.com>
> Sent: Tuesday, July 7, 2026 5:59 PM
> To: Thomas Monjalon <thomas@monjalon.net>; John Daley (johndale)
> <johndale@cisco.com>; Hyong Youb Kim (hyonkim) <hyonkim@cisco.com>;
> Nelson Escobar (neescoba) <neescoba@cisco.com>
> Cc: dev@dpdk.org; stable@dpdk.org; Alexey Simakov
> <bigalex934@gmail.com>
> Subject: [PATCH] net/enic: fix potential null dereference in flow mask check
> 
> The functions enic_copy_item_ipv4_v1(), enic_copy_item_udp_v1(), and
> enic_copy_item_tcp_v1() each initialize a local 'mask' variable from
> item->mask and substitute it with a hardcoded mask if NULL. However,
> the subsequent mask_exact_match() call uses item->mask directly
> instead of the local 'mask' variable, which will dereference NULL
> when item->mask is NULL.
> 
> Use the local 'mask' variable (which has been validated and possibly
> substituted) instead of item->mask.
> 
> Fixes: aa3d2ff82198 ("net/enic: flow API for Legacy NICs")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Alexey Simakov <bigalex934@gmail.com>
> ---
>  .mailmap                     | 1 +
>  drivers/net/enic/enic_flow.c | 6 +++---
>  2 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/.mailmap b/.mailmap
> index 4b5eb0c841..b154cd25a9 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -71,6 +71,7 @@ Alexander Skorichenko <askorichenko@netgate.com>
>  Alexander Solganik <solganik@gmail.com>
>  Alexander V Gutkin <alexander.v.gutkin@intel.com>
>  Alexandre Ferrieux <alexandre.ferrieux@orange.com>
> +Alexey Simakov <bigalex934@gmail.com>
>  Alexey Kardashevskiy <aik@ozlabs.ru>
>  Alfredo Cardigliano <cardigliano@ntop.org>
>  Ali Alnubani <alialnu@nvidia.com> <alialnu@mellanox.com>
> diff --git a/drivers/net/enic/enic_flow.c b/drivers/net/enic/enic_flow.c
> index 758000ea21..539b0eb725 100644
> --- a/drivers/net/enic/enic_flow.c
> +++ b/drivers/net/enic/enic_flow.c
> @@ -407,7 +407,7 @@ enic_copy_item_ipv4_v1(struct copy_item_args *arg)
> 
>  	/* check that the supplied mask exactly matches capability */
>  	if (!mask_exact_match((const uint8_t *)&supported_mask,
> -			      (const uint8_t *)item->mask, sizeof(*mask))) {
> +			      (const uint8_t *)mask, sizeof(*mask))) {
>  		ENICPMD_LOG(ERR, "IPv4 exact match mask");
>  		return ENOTSUP;
>  	}
> @@ -445,7 +445,7 @@ enic_copy_item_udp_v1(struct copy_item_args *arg)
> 
>  	/* check that the supplied mask exactly matches capability */
>  	if (!mask_exact_match((const uint8_t *)&supported_mask,
> -			      (const uint8_t *)item->mask, sizeof(*mask))) {
> +			      (const uint8_t *)mask, sizeof(*mask))) {
>  		ENICPMD_LOG(ERR, "UDP exact match mask");
>  		return ENOTSUP;
>  	}
> @@ -484,7 +484,7 @@ enic_copy_item_tcp_v1(struct copy_item_args *arg)
> 
>  	/* check that the supplied mask exactly matches capability */
>  	if (!mask_exact_match((const uint8_t *)&supported_mask,
> -			     (const uint8_t *)item->mask, sizeof(*mask))) {
> +			     (const uint8_t *)mask, sizeof(*mask))) {
>  		ENICPMD_LOG(ERR, "TCP exact match mask");
>  		return ENOTSUP;
>  	}
> --
> 2.34.1

Can you remove .mailmap diff?

The enic patch looks like a valid fix.
Acked-by: Hyong Youb Kim <hyonkim@cisco.com>

Thanks.
-Hyong


^ permalink raw reply

* RE: [PATCH] net/enic: fix possible null dereference in notify set
From: Hyong Youb Kim (hyonkim) @ 2026-07-09  9:51 UTC (permalink / raw)
  To: Alexey Simakov, John Daley (johndale), Sujith Sankar,
	David Marchand, Neil Horman
  Cc: dev@dpdk.org, stable@dpdk.org
In-Reply-To: <20260707112014.82821-1-bigalex934@gmail.com>

> -----Original Message-----
> From: Alexey Simakov <bigalex934@gmail.com>
> Sent: Tuesday, July 7, 2026 8:20 PM
> To: John Daley (johndale) <johndale@cisco.com>; Hyong Youb Kim (hyonkim)
> <hyonkim@cisco.com>; Sujith Sankar <ssujith@cisco.com>; David Marchand
> <david.marchand@redhat.com>; Neil Horman <nhorman@tuxdriver.com>
> Cc: dev@dpdk.org; stable@dpdk.org; Alexey Simakov <bigalex934@gmail.com>
> Subject: [PATCH] net/enic: fix possible null dereference in notify set
> 
> The memset of notify_addr in vnic_dev_notify_setcmd() was performed
> unconditionally before the device reset check. When the device is in
> reset, vnic_dev_notify_set() skips the notification buffer allocation,
> leaving notify_addr as NULL. The subsequent call to
> vnic_dev_notify_setcmd() would then dereference the NULL pointer via
> memset.
> 
> Move the memset inside the existing !vnic_dev_in_reset() guard where
> notify_addr is guaranteed to be valid.
> 
> Fixes: 9913fbb91df0 ("enic/base: common code")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Alexey Simakov <bigalex934@gmail.com>
> ---
>  drivers/net/enic/base/vnic_dev.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
> index ba8ecc16f2..e6d34622af 100644
> --- a/drivers/net/enic/base/vnic_dev.c
> +++ b/drivers/net/enic/base/vnic_dev.c
> @@ -964,8 +964,8 @@ int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
>  	int wait = 1000;
>  	int r;
> 
> -	memset(notify_addr, 0, sizeof(struct vnic_devcmd_notify));
>  	if (!vnic_dev_in_reset(vdev)) {
> +		memset(notify_addr, 0, sizeof(struct vnic_devcmd_notify));
>  		vdev->notify = notify_addr;
>  		vdev->notify_pa = notify_pa;

notify_addr == NULL (or bogus notify_pa) is a hard program error in
this function. Debug assertion might be more appropriate to make the
intention clear.

During init, the driver allocates the notify buffer while in_reset == 0.
enic_dev_init() does not check the return code from vnic_dev_notify_set().
I think that needs to be fixed.

Thanks.
-Hyong

>  	}
> --
> 2.34.1


^ permalink raw reply

* RE: [PATCH] net/enic: fix null dereference in flow query count
From: Hyong Youb Kim (hyonkim) @ 2026-07-09  9:11 UTC (permalink / raw)
  To: Alexey Simakov, John Daley (johndale), Hyong Youb Kim (hyonkim)
  Cc: dev@dpdk.org, stable@dpdk.org
In-Reply-To: <20260707114437.94425-1-bigalex934@gmail.com>

> -----Original Message-----
> From: Alexey Simakov <bigalex934@gmail.com>
> Sent: Tuesday, July 7, 2026 8:45 PM
> To: John Daley (johndale) <johndale@cisco.com>; Hyong Youb Kim (hyonkim)
> <hyonkim@cisco.com>
> Cc: dev@dpdk.org; stable@dpdk.org; Alexey Simakov <bigalex934@gmail.com>
> Subject: [PATCH] net/enic: fix null dereference in flow query count
> 
> begin_fm() can return NULL when the flow manager is not initialized.
> enic_fm_flow_query_count() did not check the return value, leading
> to a NULL pointer dereference on flowman_cmd() and end_fm().
> 
> Add NULL check that returns -ENOTSUP with a descriptive error
> message via rte_flow_error_set().
> 
> Fixes: ea7768b5bba8 ("net/enic: add flow implementation based on Flow
> Manager API")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Alexey Simakov <bigalex934@gmail.com>
> ---
>  drivers/net/enic/enic_fm_flow.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/drivers/net/enic/enic_fm_flow.c b/drivers/net/enic/enic_fm_flow.c
> index 4b0a513977..28e2a9c1e4 100644
> --- a/drivers/net/enic/enic_fm_flow.c
> +++ b/drivers/net/enic/enic_fm_flow.c
> @@ -2904,6 +2904,13 @@ enic_fm_flow_query_count(struct rte_eth_dev
> *dev,
> 
>  	ENICPMD_FUNC_TRACE();
>  	fm = begin_fm(pmd_priv(dev));
> +
> +	if (!fm) {
> +		return rte_flow_error_set(error, ENOTSUP,
> +			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> +			"enic: flowman is not initialized");
> +	}
> +

This function (query) does not check the return value of begin_fm(). I
believe that is intentional. Instead, the driver checks it when the
app creates a flow (see enic_fm_flow_create).

fm == NULL in this function likely means a bug in the app
(e.g. passing a wrong pointer), or memory corruption, or ... Perhaps a
debug assertion is more appropriate. Not sure..

Thanks.
-Hyong

>  	query = data;
>  	fm_flow = flow->fm;
>  	if (!fm_flow->counter_valid) {
> --
> 2.34.1


^ permalink raw reply

* [PATCH v4 9/9] net/gve: restrict max ring size in GQ QPL to 2K
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Rushil Gupta,
	Harshitha Ramamurthy
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

The GQ QPL queue format has a maximum supported ring size of 2k.
However, it is possible in some cases for the device to pass a larger
ring size as the max ring size. Restrict the ring size in the driver to
ensure that rings with invalid queue depths are not created.

Fixes: cde01d164f8f ("net/gve: support modifying ring size in GQ format")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
v4
- Remove unnecesary include
---
 drivers/net/gve/base/gve_adminq.c | 11 ++++++++---
 drivers/net/gve/gve_ethdev.h      |  1 +
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/net/gve/base/gve_adminq.c b/drivers/net/gve/base/gve_adminq.c
index 2b25c7f390..89bf669c24 100644
--- a/drivers/net/gve/base/gve_adminq.c
+++ b/drivers/net/gve/base/gve_adminq.c
@@ -946,15 +946,20 @@ static void
 gve_set_max_desc_cnt(struct gve_priv *priv,
 	const struct gve_device_option_modify_ring *modify_ring)
 {
+	priv->max_rx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.rx);
+	priv->max_tx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.tx);
+
 	if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
 		PMD_DRV_LOG(DEBUG, "Overriding max ring size from device for DQ "
 			    "queue format to 4096.");
 		priv->max_rx_desc_cnt = GVE_MAX_QUEUE_SIZE_DQO;
 		priv->max_tx_desc_cnt = GVE_MAX_QUEUE_SIZE_DQO;
-		return;
+	} else if (priv->queue_format == GVE_GQI_QPL_FORMAT) {
+		priv->max_rx_desc_cnt = RTE_MIN(priv->max_rx_desc_cnt,
+						GVE_MAX_RING_SIZE_GQ_QPL);
+		priv->max_tx_desc_cnt = RTE_MIN(priv->max_tx_desc_cnt,
+						GVE_MAX_RING_SIZE_GQ_QPL);
 	}
-	priv->max_rx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.rx);
-	priv->max_tx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.tx);
 }
 
 static void gve_enable_supported_features(struct gve_priv *priv,
diff --git a/drivers/net/gve/gve_ethdev.h b/drivers/net/gve/gve_ethdev.h
index 4a7e5ecdf3..c9a176ff17 100644
--- a/drivers/net/gve/gve_ethdev.h
+++ b/drivers/net/gve/gve_ethdev.h
@@ -21,6 +21,7 @@
 #define DQO_TX_MULTIPLIER 4
 
 #define GVE_DEFAULT_MAX_RING_SIZE	1024
+#define GVE_MAX_RING_SIZE_GQ_QPL	2048
 #define GVE_DEFAULT_MIN_RX_RING_SIZE	512
 #define GVE_DEFAULT_MIN_TX_RING_SIZE	256
 
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 8/9] net/gve: don't reset ring size bounds to default on reset
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Jasper Tran O'Leary; +Cc: dev, stable
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

On device reset, GVE skips describe_device functionality, as the device
is not expected to change on a reset. However, before skipping the
describe_device functionality, GVE still sets the ring sizes to their
default values. This effectively removes the ability to create queues
with higher-than-default descriptor counts after a reset.

Fix this behavior by only setting the default ring size bounds is
describe_device is being executed.

Fixes: 1bf64edce3c4 ("net/gve: add reset path")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
 drivers/net/gve/gve_ethdev.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c
index f73784a109..c990920a4d 100644
--- a/drivers/net/gve/gve_ethdev.c
+++ b/drivers/net/gve/gve_ethdev.c
@@ -1579,12 +1579,12 @@ gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
 		goto free_adminq;
 	}
 
-	/* Set default descriptor counts */
-	gve_set_default_ring_size_bounds(priv);
-
 	if (skip_describe_device)
 		goto setup_device;
 
+	/* Set default descriptor counts */
+	gve_set_default_ring_size_bounds(priv);
+
 	/* Get the initial information we need from the device */
 	err = gve_adminq_describe_device(priv);
 	if (err) {
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 7/9] net/gve: increase range of DMA memzone ids to 64 bits
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Junfeng Guo, Haiyue Wang,
	Xiaoyun Li
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

Long running programs can very easily eclipse this 16-bit range, leading
to name collisions and failed DMA region allocations despite there being
plenty of available memory.

Fixes: c9ba2caf6302 ("net/gve/base: add OS-specific implementation")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
 drivers/net/gve/base/gve_osdep.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/gve/base/gve_osdep.h b/drivers/net/gve/base/gve_osdep.h
index c47ce4da85..55629a0e1a 100644
--- a/drivers/net/gve/base/gve_osdep.h
+++ b/drivers/net/gve/base/gve_osdep.h
@@ -175,14 +175,14 @@ struct gve_dma_mem {
 static inline void *
 gve_alloc_dma_mem(struct gve_dma_mem *mem, u64 size)
 {
-	static RTE_ATOMIC(uint16_t) gve_dma_memzone_id;
+	static RTE_ATOMIC(uint64_t) gve_dma_memzone_id;
 	const struct rte_memzone *mz = NULL;
 	char z_name[RTE_MEMZONE_NAMESIZE];
 
 	if (!mem)
 		return NULL;
 
-	snprintf(z_name, sizeof(z_name), "gve_dma_%u",
+	snprintf(z_name, sizeof(z_name), "gve_dma_%" PRIu64,
 		 rte_atomic_fetch_add_explicit(&gve_dma_memzone_id, 1, rte_memory_order_relaxed));
 	mz = rte_memzone_reserve_aligned(z_name, size, SOCKET_ID_ANY,
 					 RTE_MEMZONE_IOVA_CONTIG,
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 6/9] net/gve: free ctx mbuf if packet dropped after first segment
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Junfeng Guo, Rushil Gupta
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

GVE GQ has support for multi-descriptor RX. It is possible for a packet
to be dropped after the first descriptor has been processed an mbuf has
been added to the context. In such a case, the mbuf head should be freed
before clearing the context so that mbufs aren't leaked.

In addition, clear mbuf from sw_ring after adding the packet to the
context to avoid double-freeing buffers that have not been reposted, but
have been reported to the application.

Fixes: 496d4d2c8b54 ("net/gve: support jumbo frame for GQI")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
 drivers/net/gve/gve_rx.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/gve/gve_rx.c b/drivers/net/gve/gve_rx.c
index cda87af294..567b82d020 100644
--- a/drivers/net/gve/gve_rx.c
+++ b/drivers/net/gve/gve_rx.c
@@ -205,6 +205,8 @@ gve_rx_burst(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		if (gve_rx(rxq, rxd, rx_id)) {
 			if (!ctx->drop_pkt)
 				rx_pkts[nb_rx++] = ctx->mbuf_head;
+			else if (ctx->mbuf_head != NULL)
+				rte_pktmbuf_free(ctx->mbuf_head);
 			rxq->nb_avail += ctx->total_frags;
 			gve_rx_ctx_clear(ctx);
 		}
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 5/9] net/gve: set mbuf to null in software ring after use
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Junfeng Guo, Xiaoyun Li,
	Rushil Gupta
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

Currently, it is possible for mbufs to be uncleared in the sw_ring after
being returned to the application. This causes an erroneous
dual-ownership over the buffer until GVE cleans the buffer queue and
posts new mbufs, overwriting the older pointers. It is possible in such
a case for a double free to occur while tearing down rings, as both
the application and the driver could attempt to free the same mbuf.
Release ownership of the mbuf from the sw_ring as soon as appropriate to
avoid such a scenario.

Fixes: a46583cf43c8 ("net/gve: support Rx/Tx")
Fixes: 45da16b5b181 ("net/gve: support basic Rx data path for DQO")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
 drivers/net/gve/gve_rx.c     | 1 +
 drivers/net/gve/gve_rx_dqo.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/net/gve/gve_rx.c b/drivers/net/gve/gve_rx.c
index 625649cdcf..cda87af294 100644
--- a/drivers/net/gve/gve_rx.c
+++ b/drivers/net/gve/gve_rx.c
@@ -152,6 +152,7 @@ gve_rx(struct gve_rx_queue *rxq, volatile struct gve_rx_desc *rxd, uint16_t rx_i
 
 	rxe = rxq->sw_ring[rx_id];
 	gve_rx_mbuf(rxq, rxe, frag_size, rx_id);
+	rxq->sw_ring[rx_id] = NULL;
 	rxq->stats.bytes += frag_size;
 
 	if (is_first_frag) {
diff --git a/drivers/net/gve/gve_rx_dqo.c b/drivers/net/gve/gve_rx_dqo.c
index c4e2d32067..3665d9e4cd 100644
--- a/drivers/net/gve/gve_rx_dqo.c
+++ b/drivers/net/gve/gve_rx_dqo.c
@@ -207,6 +207,7 @@ gve_rx_burst_dqo(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 
 		rxm = rxq->sw_ring[rx_buf_id];
 		gve_completed_buf_list_push(rxq, rx_buf_id);
+		rxq->sw_ring[rx_buf_id] = NULL;
 
 		/* Free buffer and report error. */
 		if (unlikely(rx_desc->rx_error)) {
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 4/9] net/gve: validate buf ID before processing Rx packet
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Ankit Garg
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

The buffer id is part of the RX completion descriptor for packets in the
DQ format. This value can technically go up to 64K, while the max RX
ring size is 4K, meaning that there could similarly be an expected 4K RX
buffer IDs. Validate that the RX buffer ID is valid before attempting to
access it in the sw_ring to prevent a potential out of bounds in the
event of a hardware error.

Fixes: 1aed73b23ac0 ("net/gve: support out-of-order completions on DQ Rx")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
 drivers/net/gve/gve_rx_dqo.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/gve/gve_rx_dqo.c b/drivers/net/gve/gve_rx_dqo.c
index cc343f3fd8..c4e2d32067 100644
--- a/drivers/net/gve/gve_rx_dqo.c
+++ b/drivers/net/gve/gve_rx_dqo.c
@@ -200,6 +200,11 @@ gve_rx_burst_dqo(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		}
 
 		rx_buf_id = rte_le_to_cpu_16(rx_desc->buf_id);
+		if (unlikely(rx_buf_id >= rxq->nb_rx_desc)) {
+			PMD_DRV_DP_LOG(ERR, "Invalid buf_id %d", rx_buf_id);
+			continue;
+		}
+
 		rxm = rxq->sw_ring[rx_buf_id];
 		gve_completed_buf_list_push(rxq, rx_buf_id);
 
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 3/9] net/gve: copy data to QPL buffer when mbuf read does not
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Junfeng Guo, Xiaoyun Li
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

The rte_pktmbuf_read method does not guarantee that data will be copied
from an mbuf. If the requested data is all contiguous, the method will
instead return a pointer to the memory location within the buffer that
should be read from, leaving the destination buffer empty.

This is problematic for TSO/multi-segment TX packets which only make use
of two mbufs. If all data in the second mbuf is contiguous, the data
will not be read to QPL memory.

Update the QPL copy logic to copy if the rte_pktmbuf_read does not.

Fixes: a46583cf43c8 ("net/gve: support Rx/Tx")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
v3:
  - Fix 32-bit compile issue.
v2:
  - Remove unused declaration and definition of addr
---
 drivers/net/gve/gve_tx.c | 38 +++++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/net/gve/gve_tx.c b/drivers/net/gve/gve_tx.c
index 59c82b04ed..c0400b07bf 100644
--- a/drivers/net/gve/gve_tx.c
+++ b/drivers/net/gve/gve_tx.c
@@ -255,10 +255,10 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf **sw_ring = txq->sw_ring;
 	uint16_t mask = txq->nb_tx_desc - 1;
 	uint16_t tx_id = txq->tx_tail & mask;
-	uint64_t ol_flags, addr, fifo_addr;
 	uint32_t tx_tail = txq->tx_tail;
 	struct rte_mbuf *tx_pkt, *first;
 	uint16_t sw_id = txq->sw_tail;
+	uint64_t ol_flags, fifo_addr;
 	uint16_t nb_used, i;
 	uint64_t bytes = 0;
 	uint16_t nb_tx = 0;
@@ -273,6 +273,9 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		gve_tx_clean_swr_qpl(txq);
 
 	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+		const void *mbuf_header_addr;
+		void *qpl_write_addr;
+
 		tx_pkt = *tx_pkts++;
 		ol_flags = tx_pkt->ol_flags;
 
@@ -306,7 +309,6 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			if (!is_fifo_avail(txq, hlen))
 				goto end_of_tx;
 		}
-		addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off;
 		fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, hlen);
 
 		/* For TSO, check if there's enough fifo space for data first */
@@ -317,26 +319,32 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 					goto end_of_tx;
 			}
 		}
-		if (tx_pkt->nb_segs == 1 || ol_flags & RTE_MBUF_F_TX_TCP_SEG)
-			rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base),
-				   (void *)(size_t)addr, hlen);
-		else
-			rte_pktmbuf_read(tx_pkt, 0, hlen,
-					 (void *)(size_t)(fifo_addr + txq->fifo_base));
+
+		qpl_write_addr = (void *)(size_t)(fifo_addr + txq->fifo_base);
+		mbuf_header_addr = rte_pktmbuf_read(tx_pkt, 0, hlen, qpl_write_addr);
+
+		/* Header data is linear in the mbuf head. Copy directly. */
+		if (mbuf_header_addr != qpl_write_addr)
+			rte_memcpy(qpl_write_addr, mbuf_header_addr, hlen);
+
 		gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, fifo_addr);
 
 		if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+			const void *mbuf_payload_addr;
+
 			tx_id = (tx_id + 1) & mask;
 			txd = &txr[tx_id];
-			addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off + hlen;
 			fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, tx_pkt->pkt_len - hlen);
-			if (tx_pkt->nb_segs == 1)
-				rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base),
-					   (void *)(size_t)addr,
+			qpl_write_addr = (void *)(size_t)(txq->fifo_base + fifo_addr);
+			mbuf_payload_addr = rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len - hlen,
+							     qpl_write_addr);
+
+			/* Payload data is contiguous. Take the offset from the
+			 * read request and copy from there.
+			 */
+			if (mbuf_payload_addr != qpl_write_addr)
+				rte_memcpy(qpl_write_addr, mbuf_payload_addr,
 					   tx_pkt->pkt_len - hlen);
-			else
-				rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len - hlen,
-						 (void *)(size_t)(fifo_addr + txq->fifo_base));
 
 			gve_tx_fill_seg_desc(txd, ol_flags, tx_offload,
 					     tx_pkt->pkt_len - hlen, fifo_addr);
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 2/9] net/gve: delay adding mbuf head to software ring
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Junfeng Guo, Xiaoyun Li
  Cc: dev, stable, Jasper Tran O'Leary
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

The GQ TX datapath was set up to write the mbuf head into the sw_ring
before writing the descriptors. This poses a problem because it's
possible for the packet to be dropped due to lacking the FIFO space to
do a proper TX. In such a case, the packet won't be sent, and will lead
to leaked mbufs in the subsequent segments.

There is also no real reason that the head mbuf must be set in the
sw_ring separately from the others; the mbuf chain is not actually
walked as part of GQ TX.

Fixes: a46583cf43c8 ("net/gve: support Rx/Tx")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Jasper Tran O'Leary <jtranoleary@google.com>
---
 drivers/net/gve/gve_tx.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/gve/gve_tx.c b/drivers/net/gve/gve_tx.c
index 5c73c21b8d..59c82b04ed 100644
--- a/drivers/net/gve/gve_tx.c
+++ b/drivers/net/gve/gve_tx.c
@@ -301,7 +301,6 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 			(uint32_t)(tx_offload.l2_len + tx_offload.l3_len + tx_offload.l4_len) :
 			tx_pkt->pkt_len;
 
-		sw_ring[sw_id] = tx_pkt;
 		if (!is_fifo_avail(txq, hlen)) {
 			gve_tx_clean(txq);
 			if (!is_fifo_avail(txq, hlen))
@@ -344,13 +343,14 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		}
 
 		/* record mbuf in sw_ring for free */
-		for (i = 1; i < first->nb_segs; i++) {
+		for (i = 0; i < first->nb_segs; i++) {
+			if (!tx_pkt)
+				break;
+			sw_ring[sw_id] = tx_pkt;
 			sw_id = (sw_id + 1) & mask;
 			tx_pkt = tx_pkt->next;
-			sw_ring[sw_id] = tx_pkt;
 		}
 
-		sw_id = (sw_id + 1) & mask;
 		tx_id = (tx_id + 1) & mask;
 
 		txq->nb_free -= nb_used;
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 1/9] net/gve: clear out shared memory region for stats report
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  To: Jeroen de Borst, Joshua Washington, Rushil Gupta, Ferruh Yigit
  Cc: dev, stable, Mark Blasko
In-Reply-To: <20260709040739.3184955-1-joshwash@google.com>

The stats report memzone is allocated from hugepage memory which could
possibly have had sensitive data from a previous DPDK invocation.

Clear out the buffer before sharing the memory region with the virtual
device to protect guest memory.

Fixes: 458b53dec01e ("net/gve: enable imissed stats for GQ format")
Cc: stable@dpdk.org
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Mark Blasko <blasko@google.com>
---
 drivers/net/gve/gve_ethdev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c
index 0b02dcb3ad..f73784a109 100644
--- a/drivers/net/gve/gve_ethdev.c
+++ b/drivers/net/gve/gve_ethdev.c
@@ -306,6 +306,8 @@ gve_alloc_stats_report(struct gve_priv *priv,
 	if (!priv->stats_report_mem)
 		return -ENOMEM;
 
+	memset(priv->stats_report_mem->addr, 0, priv->stats_report_mem->len);
+
 	/* offset by skipping stats written by gve. */
 	priv->stats_start_idx = (GVE_TX_STATS_REPORT_NUM * nb_tx_queues) +
 		(GVE_RX_STATS_REPORT_NUM * nb_rx_queues);
-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply related

* [PATCH v4 0/9] Stability fixes for GVE
From: Joshua Washington @ 2026-07-09  4:07 UTC (permalink / raw)
  Cc: dev, Joshua Washington
In-Reply-To: <20260707164020.2936476-1-joshwash@google.com>

This patch series consists of mostly unrelated fixes in the GVE driver.

v4:
  - Remove unncessary include
v3:
  - Fix 32-bit compilation issue
v2:
  - Remove unused definition

Joshua Washington (9):
  net/gve: clear out shared memory region for stats report
  net/gve: delay adding mbuf head to software ring
  net/gve: copy data to QPL buffer when mbuf read does not
  net/gve: validate buf ID before processing Rx packet
  net/gve: set mbuf to null in software ring after use
  net/gve: free ctx mbuf if packet dropped after first segment
  net/gve: increase range of DMA memzone ids to 64 bits
  net/gve: don't reset ring size bounds to default on reset
  net/gve: restrict max ring size in GQ QPL to 2K

 drivers/net/gve/base/gve_adminq.c | 11 ++++++--
 drivers/net/gve/base/gve_osdep.h  |  4 +--
 drivers/net/gve/gve_ethdev.c      |  8 ++++--
 drivers/net/gve/gve_ethdev.h      |  1 +
 drivers/net/gve/gve_rx.c          |  3 ++
 drivers/net/gve/gve_rx_dqo.c      |  6 ++++
 drivers/net/gve/gve_tx.c          | 46 ++++++++++++++++++-------------
 7 files changed, 52 insertions(+), 27 deletions(-)

-- 
2.55.0.795.g602f6c329a-goog


^ permalink raw reply

* Re: [PATCH v2] dts: add ipgre test suite
From: Patrick Robb @ 2026-07-09  1:47 UTC (permalink / raw)
  To: Andrew Bailey; +Cc: luca.vizzarro, dev, ahassick, lylavoie, knimoji
In-Reply-To: <20260511154617.75903-1-abailey@iol.unh.edu>

[-- Attachment #1: Type: text/plain, Size: 7621 bytes --]

On Mon, May 11, 2026 at 11:46 AM Andrew Bailey <abailey@iol.unh.edu> wrote:

> Port over the IP GRE test suite from old DTS to next DTS. This test
> suite covers GRE tunneling and checksum offload verification using this
> protocol.
>
> Bugzilla ID: 1480
>
> Signed-off-by: Andrew Bailey <abailey@iol.unh.edu>
> ---
>  doc/api/dts/tests.TestSuite_ip_gre.rst |   8 +
>  dts/api/testpmd/__init__.py            |  23 ++
>  dts/tests/TestSuite_ip_gre.py          | 301 +++++++++++++++++++++++++
>  3 files changed, 332 insertions(+)
>  create mode 100644 doc/api/dts/tests.TestSuite_ip_gre.rst
>  create mode 100644 dts/tests/TestSuite_ip_gre.py
>
> diff --git a/doc/api/dts/tests.TestSuite_ip_gre.rst
> b/doc/api/dts/tests.TestSuite_ip_gre.rst
> new file mode 100644
> index 0000000000..e8ce01dc0b
> --- /dev/null
> +++ b/doc/api/dts/tests.TestSuite_ip_gre.rst
> @@ -0,0 +1,8 @@
> +.. SPDX-License-Identifier: BSD-3-Clause
> +
> +ip_gre Test Suite
> +=================
> +
> +.. automodule:: tests.TestSuite_ip_gre
> +   :members:
> +   :show-inheritance:
> diff --git a/dts/api/testpmd/__init__.py b/dts/api/testpmd/__init__.py
> index e9187440bb..bb5cbd6725 100644
> --- a/dts/api/testpmd/__init__.py
> +++ b/dts/api/testpmd/__init__.py
> @@ -951,6 +951,29 @@ def set_flow_control(
>                      f"Testpmd failed to set the {flow_ctrl} in port
> {port}."
>                  )
>
> +    def set_csum_parse_tunnel(self, port: int, on: bool, verify: bool =
> True) -> None:
> +        """Set parse tunnel on or of in testpmd for a given port.
>

Should be “off” not “of”


> +
> +        Args:
> +            port: The ID of the requested port
> +            on: set parse tunnel on if `on` is :data:`True`, otherwise off
> +            verify: if :data:`True`, the output of the command is scanned
> to verify that
> +                parse tunnel was set successfully
> +
> +        Raises:
> +            InteractiveCommandExecutionError: If `verify` is :data:`True`
> and the command
> +                fails to execute.
> +
> +        """
> +        output = self.send_command(f"csum parse-tunnel {'on' if on else
> 'off'} {port}")
> +        if verify and f"Parse tunnel is {'on' if on else'off'}" not in
> output:
>

Missing a space after "else".


> +            self._logger.debug(
> +                f"Testpmd failed to set csum parse-tunnel {'on' if on
> else 'off'} in port {port}"
> +            )
> +            raise InteractiveCommandExecutionError(
> +                f"Testpmd failed to set csum parse-tunnel {'on' if on
> else 'off'} in port {port}"
> +            )
> +
>      def show_port_flow_info(self, port: int) -> TestPmdPortFlowCtrl |
> None:
>          """Show port info flow.
>
> diff --git a/dts/tests/TestSuite_ip_gre.py b/dts/tests/TestSuite_ip_gre.py
> new file mode 100644
> index 0000000000..fc51eef181
> --- /dev/null
> +++ b/dts/tests/TestSuite_ip_gre.py
> @@ -0,0 +1,301 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2026 University of New Hampshire
> +
> +"""DPDK IP GRE test suite."""
> +
> +from scapy.layers.inet import GRE, IP, TCP, UDP
> +from scapy.layers.inet6 import IPv6
> +from scapy.layers.l2 import Dot1Q, Ether
> +from scapy.layers.sctp import SCTP
> +from scapy.packet import Packet
> +
> +from api.capabilities import (
> +    NicCapability,
> +    requires_nic_capability,
> +)
> +from api.packet import send_packet_and_capture
> +from api.test import verify
> +from api.testpmd import TestPmd
> +from api.testpmd.config import SimpleForwardingModes
> +from api.testpmd.types import (
> +    ChecksumOffloadOptions,
> +    PacketOffloadFlag,
> +    RtePTypes,
> +    TestPmdVerbosePacket,
> +)
> +from framework.test_suite import TestSuite, func_test
> +
> +SRC_ID = "FF:FF:FF:FF:FF:FF"
>

Why did you choose the broadcast address instead of a "normal" address?
Just want to hear your reasoning.


> +
> +
> +class TestIpGre(TestSuite):
> +    """IP GRE test suite."""
> +
> +    def _check_for_matching_packet(
> +        self, output: list[TestPmdVerbosePacket], flags: RtePTypes
> +    ) -> bool:
> +        """Returns :data:`True` if the packet in verbose output contains
> all specified flags."""
> +        for packet in output:
> +            if packet.src_mac == SRC_ID:
> +                if flags not in packet.hw_ptype and flags not in
> packet.sw_ptype:
> +                    return False
> +        return True
> +
> +    def _send_packet_and_verify_flags(
> +        self, expected_flag: RtePTypes, packet: Packet, testpmd: TestPmd
> +    ) -> None:
> +        """Sends a packet to the DUT and verifies the verbose ptype
> flags."""
> +        send_packet_and_capture(packet=packet)
> +        verbose_output =
> testpmd.extract_verbose_output(testpmd.stop(verify=True))
> +        valid = self._check_for_matching_packet(output=verbose_output,
> flags=expected_flag)
> +        verify(valid, f"Packet type flag did not match the expected flag:
> {expected_flag}.")


Is it worth logging a packet transmission issue vs a flag setting / flag
processing issue in different ways? And re the previous 2 functions if
verbose_output is None will _check_for_matching_packet return True in
error? Just checking that this is sound.


> +
> +    def _setup_session(
> +        self, testpmd: TestPmd, expected_flags: list[RtePTypes],
> packet_list=list[Packet]
> +    ) -> None:
> +        """Sets the forwarding and verbose mode of each test case
> interactive shell session."""
> +        testpmd.set_forward_mode(SimpleForwardingModes.rxonly)
> +        testpmd.set_verbose(level=1)
> +        for i in range(0, len(packet_list)):
> +            testpmd.start(verify=True)
> +            self._send_packet_and_verify_flags(
> +                expected_flag=expected_flags[i], packet=packet_list[i],
> testpmd=testpmd
> +            )
>

If expected_flags and packet_list are related lists of the same length, is
it better if we use 1 list of tuples [(expected flag, packet)]?

+
> +    def _send_packet_and_verify_checksum(
> +        self, packet: Packet, good_L4: bool, good_IP: bool, testpmd:
> TestPmd
>

If we are going to say good_L4 can we say good_L3 or does that reduce
clarity to you? Figure we should stay consistent.


> +    ) -> None:
> +        """Send packet and verify verbose output matches expected
> output."""
> +        testpmd.start()
> +        send_packet_and_capture(packet=packet)
> +        verbose_output = testpmd.extract_verbose_output(testpmd.stop())
> +        is_IP = is_L4 = None
> +        for testpmd_packet in verbose_output:
> +            if testpmd_packet.src_mac == SRC_ID:
> +                is_IP = PacketOffloadFlag.RTE_MBUF_F_RX_IP_CKSUM_GOOD in
> testpmd_packet.ol_flags
> +                is_L4 = PacketOffloadFlag.RTE_MBUF_F_RX_L4_CKSUM_GOOD in
> testpmd_packet.ol_flags
>

is_IP -> good_L3_checksum? If the meaning of the is_IP variable is that
there is an IP layer, I disagree with the name because it is possible for
there to be an IP layer and a bad checksum. I do see below the verify logic
is for if the checksum is correct.

Do we have any logic here to verify we are acting on the correct packet,
given that it may not be a quiet wire?


> +        verify(
> +            is_IP is not None and is_L4 is not None,
> +            "Test packet was dropped when it should have been received.",
>

Reviewed-by: Patrick Robb <patrickrobb1997@gmail.com>

[-- Attachment #2: Type: text/html, Size: 10362 bytes --]

^ permalink raw reply

* Re: [PATCH v5] dts: report dut/NIC info during DTS run
From: Patrick Robb @ 2026-07-09  1:04 UTC (permalink / raw)
  To: Koushik Bhargav Nimoji; +Cc: luca.vizzarro, dev, abailey, ahassick, lylavoie
In-Reply-To: <CAK6DuxskqPSX-wgxHLOmhd7U=HSYg2js99E7th76LeAY4CBbHA@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1392 bytes --]

Actually, please see the AI code review of this patch. Specifically, this
comment looks correct to me. What are your thoughts?

**File:** `dts/framework/testbed_model/linux_session.py`, line 228

The code checks `lshw_result.return_code != 0 and lshw_result.stdout == ""`
but the logic is incorrect. If the command fails, you should raise an
error. The `and` should likely be `or`:



Please read through the other suggestions too. There is some fluff but also
some good advice.

On Wed, Jul 8, 2026 at 8:57 PM Patrick Robb <patrickrobb1997@gmail.com>
wrote:

> Please make sure you always run checkpatches, check-git-log,
> dts-check-format, and a doc build or each patch you send. I will update the
> commit message before applying. The mailmap issue will go away when your
> other series (with the mailmap addition) is applied.
>
> Thanks for the patch! Applying to next-dts.
>
> ./devtools/check-git-log.sh -n 1
> Wrong headline case:
>                         "dts: report dut and nic info during DTS run": nic
> --> NIC
> Contributor name/email mismatch with .mailmap:
>         Koushik Bhargav Nimoji <knimoji@iol.unh.edu> is unknown in
> .mailmap
>
> Invalid patch(es) found - checked 1 patch
>
> On Tue, Jul 7, 2026 at 9:46 PM Patrick Robb <patrickrobb1997@gmail.com>
> wrote:
>
>> Tested-by: Patrick Robb <patrickrobb1997@gmail.com>
>>
>

[-- Attachment #2: Type: text/html, Size: 2231 bytes --]

^ permalink raw reply

* Re: [PATCH v5] dts: report dut/NIC info during DTS run
From: Patrick Robb @ 2026-07-09  0:57 UTC (permalink / raw)
  To: Koushik Bhargav Nimoji; +Cc: luca.vizzarro, dev, abailey, ahassick, lylavoie
In-Reply-To: <CAK6DuxvEjRGOQJMY-Amd+QUxQBAV9ihp35fX1PQ2D5p7bt=L8w@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 772 bytes --]

Please make sure you always run checkpatches, check-git-log,
dts-check-format, and a doc build or each patch you send. I will update the
commit message before applying. The mailmap issue will go away when your
other series (with the mailmap addition) is applied.

Thanks for the patch! Applying to next-dts.

./devtools/check-git-log.sh -n 1
Wrong headline case:
                        "dts: report dut and nic info during DTS run": nic
--> NIC
Contributor name/email mismatch with .mailmap:
        Koushik Bhargav Nimoji <knimoji@iol.unh.edu> is unknown in .mailmap

Invalid patch(es) found - checked 1 patch

On Tue, Jul 7, 2026 at 9:46 PM Patrick Robb <patrickrobb1997@gmail.com>
wrote:

> Tested-by: Patrick Robb <patrickrobb1997@gmail.com>
>

[-- Attachment #2: Type: text/html, Size: 1293 bytes --]

^ permalink raw reply

* [PATCH 2/2] net/iavf: disable runtime queue setup during queue rate limiting
From: Dawid Wesierski @ 2026-07-08 23:19 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, bruce.richardson, marek.kasiewicz,
	Dawid Wesierski
In-Reply-To: <20260708231926.1550698-1-dawid.wesierski@intel.com>

Runtime queue setup on E810 VFs causes queue state corruption when
queues are dynamically reconfigured while the hardware rate limiter
is actively pacing TX queues. Queue configuration messages to the PF
via virtchnl can race with ongoing TX operations, leading to undefined
behavior.

Rather than gating this behind a devarg that an application would have
to know to set (and could just as easily avoid triggering the race by
not calling rte_eth_{rx,tx}_queue_setup() on a running port), stop
advertising RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP and
RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP as soon as the application
commits a per-queue bandwidth rte_tm hierarchy, i.e. as soon as the
condition that causes the race actually exists. iavf_dev_info_get() is
re-queried by the ethdev layer on every rx/tx_queue_setup() call, so
this is enough for the generic layer to start rejecting runtime queue
(re)configuration with -EBUSY once queue rate limiting is active, and
to automatically allow it again once the rte_tm hierarchy is torn
down.

vf->qtc_map, already used elsewhere to look up a queue's TC mapping,
is repurposed as the "queue bandwidth committed" signal since it's set
by iavf_hierarchy_commit() exactly when a per-queue bandwidth mapping
has been pushed to the PF, regardless of whether the port was stopped
at the time. Fix two related issues found while making it load-bearing
for this check:

- iavf_hierarchy_commit() replaced vf->qtc_map on every successful
  commit without freeing the previous allocation, leaking memory.
- vf->qtc_map was never released on VF teardown, so
  iavf_uninit_vf()/iavf_init_vf() (e.g. across a VF reset) could leave
  a stale pointer referencing freed unrelated memory, and the runtime
  queue setup capability would never be re-advertised after a reset.

Both are fixed by freeing vf->qtc_map before replacing it in
iavf_hierarchy_commit(), and freeing and clearing it in
iavf_uninit_vf().

Signed-off-by: Marek Kasiewicz <marek.kasiewicz@intel.com>
Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
---
 doc/guides/nics/intel_vf.rst           | 10 ++++++++++
 doc/guides/rel_notes/release_26_07.rst |  3 +++
 drivers/net/intel/iavf/iavf_ethdev.c   | 23 ++++++++++++++++++++---
 drivers/net/intel/iavf/iavf_tm.c       |  2 ++
 4 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/intel_vf.rst b/doc/guides/nics/intel_vf.rst
index e010f852cf..a47e3f6736 100644
--- a/doc/guides/nics/intel_vf.rst
+++ b/doc/guides/nics/intel_vf.rst
@@ -150,6 +150,16 @@ Intel\ |reg| E800 Series Ethernet devices:
   for example: ``-a 18:00.0,quanta_size=2048``.
   The default value is 1024, and quanta size should be set as the product of 64 in legacy host interface mode.
 
+* Runtime (post-start) Rx/Tx queue setup can race with the hardware Tx rate
+  limiter on E810 VFs and corrupt queue state.
+  Once an application commits a per-queue bandwidth ``rte_tm`` hierarchy,
+  the driver automatically stops advertising
+  ``RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP`` and
+  ``RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP``,
+  so ``rte_eth_rx_queue_setup()``/``rte_eth_tx_queue_setup()``
+  are rejected with ``-EBUSY`` on a running port for as long as queue rate
+  limiting is active.
+
 * When using the Intel out-of-tree "ice" PF/kernel driver v1.13.7 or later,
   to create VFs with >16 queues (aka. "large VFs"),
   it is necessary to change the rss_lut_vf_addr setting in sysfs from the default of 64 to 512.
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 6352ef27ab..7ea80112f4 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -143,6 +143,9 @@ New Features
 
   * Added support for transmitting LLDP packets based on mbuf packet type.
   * Implemented AVX2 context descriptor transmit paths.
+  * Runtime Rx/Tx queue setup is now automatically disabled while a
+    per-queue bandwidth ``rte_tm`` hierarchy is committed, to avoid
+    corrupting queue state on E810 VFs.
 
 * **Updated Intel ice driver.**
 
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index 80e740ef29..5d0c361978 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -1160,9 +1160,18 @@ iavf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->reta_size = vf->vf_res->rss_lut_size;
 	dev_info->flow_type_rss_offloads = IAVF_RSS_OFFLOAD_ALL;
 	dev_info->max_mac_addrs = IAVF_NUM_MACADDR_MAX;
-	dev_info->dev_capa =
-		RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
-		RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
+	/*
+	 * Runtime queue setup can race with the hardware Tx rate limiter on
+	 * E810 VFs and corrupt queue state. Once a per-queue bandwidth rte_tm
+	 * hierarchy has been committed (vf->qtc_map is set), stop advertising
+	 * the capability so the ethdev layer rejects further rx/tx_queue_setup()
+	 * calls on a running port with -EBUSY. The capability is re-advertised
+	 * automatically once the rte_tm hierarchy is torn down.
+	 */
+	if (vf->qtc_map == NULL)
+		dev_info->dev_capa =
+			RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
+			RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
 	dev_info->rx_offload_capa =
 		RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
 		RTE_ETH_RX_OFFLOAD_QINQ_STRIP |
@@ -2756,6 +2765,14 @@ iavf_uninit_vf(struct rte_eth_dev *dev)
 	rte_free(vf->qos_cap);
 	vf->qos_cap = NULL;
 
+	/*
+	 * Drop the committed queue/TC bandwidth mapping so a subsequent
+	 * iavf_init_vf() (e.g. after a device reset) starts with runtime
+	 * Rx/Tx queue setup available again (see iavf_dev_info_get()).
+	 */
+	rte_free(vf->qtc_map);
+	vf->qtc_map = NULL;
+
 	rte_free(vf->rss_lut);
 	vf->rss_lut = NULL;
 	rte_free(vf->rss_key);
diff --git a/drivers/net/intel/iavf/iavf_tm.c b/drivers/net/intel/iavf/iavf_tm.c
index e3492ec491..c9d856e937 100644
--- a/drivers/net/intel/iavf/iavf_tm.c
+++ b/drivers/net/intel/iavf/iavf_tm.c
@@ -905,6 +905,8 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,
 	if (ret_val)
 		goto fail_clear;
 
+	/* replace the previously committed mapping, if any */
+	rte_free(vf->qtc_map);
 	vf->qtc_map = qtc_map;
 	if (adapter->stopped == 1)
 		vf->tm_conf.committed = true;
-- 
2.47.3

---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Spolka oswiadcza, ze posiada status duzego przedsiebiorcy w rozumieniu ustawy z dnia 8 marca 2013 r. o przeciwdzialaniu nadmiernym opoznieniom w transakcjach handlowych.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.


^ permalink raw reply related

* [PATCH 1/2] doc: fix ice scheduler rate-limiter burst size description
From: Dawid Wesierski @ 2026-07-08 23:19 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, bruce.richardson, marek.kasiewicz,
	Dawid Wesierski
In-Reply-To: <20260708231926.1550698-1-dawid.wesierski@intel.com>

The paragraph describing the ``rl_burst_size`` devarg was mangled
(a mid-sentence line break split "favours throughput" across two
lines with no space), and it did not mention that out-of-range
values are rejected by the driver, which can otherwise look like a
silent no-op to a reader.

Fixes: b3f2afb3b7ea ("net/ice: add scheduler rate-limiter burst size devarg")

Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
---
 doc/guides/nics/ice.rst | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 5589ce934f..6c2063d47e 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -160,9 +160,10 @@ Runtime Configuration
 
 - ``Scheduler rate-limiter burst size`` (default ``0``)
 
-  The hardware Tx scheduler uses a default rate-limiter burst size that favours throughput.
-  Time-sensitive applications can lower this value to reduce Tx latency jitter
-  at the cost of throughput by setting the ``rl_burst_size`` devargs parameter, in bytes.
+  The hardware Tx scheduler uses a default rate-limiter burst size that favours
+  throughput. Time-sensitive applications can lower this value to reduce Tx
+  latency jitter at the cost of throughput by setting the ``rl_burst_size``
+  devargs parameter, in bytes. Values that are out of range are rejected.
   A value of ``0`` (the default) keeps the hardware default.
 
   For example::
-- 
2.47.3

---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Spolka oswiadcza, ze posiada status duzego przedsiebiorcy w rozumieniu ustawy z dnia 8 marca 2013 r. o przeciwdzialaniu nadmiernym opoznieniom w transakcjach handlowych.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.


^ permalink raw reply related

* [PATCH v5 0/2] net/iavf, ice: fix runtime queue setup race and burst-size doc
From: Dawid Wesierski @ 2026-07-08 23:19 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, bruce.richardson, marek.kasiewicz,
	Dawid Wesierski
In-Reply-To: <20260703121952.1277387-6-dawid.wesierski@intel.com>

This addresses Bruce Richardson's review of the v4 "Intel network drivers
enhancements" series. Bruce questioned the no_runtime_queue_setup devarg
added in v4:

> Do we really need a commandline arg for this? If it's known enough to
> have the extra arg passed at device init, is it not also known enough
> to have the app not do dynamic reconfiguration in the first place?
>
> Alternatively, if the user configures packet pacing through rte_tm,
> can we not at that point adjust the driver to disallow runtime config
> by returning -ENOTSUP when reconfig is attempted, and no longer
> advertising the capabilities? Runtime configuration, whether with or
> without user interaction, should be preferred over devargs whenever
> possible.

Patch 2/2 drops the devarg and makes the driver withdraw
RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP / _TX_QUEUE_SETUP automatically
as soon as a per-queue bandwidth rte_tm hierarchy is committed, and
re-advertise them once it is torn down. Two bugs found while making the
committed-hierarchy pointer load-bearing for that check (a leak on
repeated commits, and a stale pointer surviving a VF reset) are fixed
alongside it.

Patch 1/2 is a small documentation fix for the rl_burst_size devarg
wording, spotted while touching the same area.

This v5 replaces v4 patches 3/5 and 4/5 with the two patches below.
v4 patches 1, 2 and 5 (max ring descriptors, queue rate limit
configuration, and the testpmd pinned-rxpool command) are unchanged
and are not reposted here.

Dawid Wesierski (2):
  doc: fix ice scheduler rate-limiter burst size description
  net/iavf: disable runtime queue setup during queue rate limiting

 doc/guides/nics/ice.rst                |  7 ++++---
 doc/guides/nics/intel_vf.rst           | 10 ++++++++++
 doc/guides/rel_notes/release_26_07.rst |  3 +++
 drivers/net/intel/iavf/iavf_ethdev.c   | 23 ++++++++++++++++++++---
 drivers/net/intel/iavf/iavf_tm.c       |  2 ++
 5 files changed, 39 insertions(+), 6 deletions(-)

-- 
2.47.3

---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Spolka oswiadcza, ze posiada status duzego przedsiebiorcy w rozumieniu ustawy z dnia 8 marca 2013 r. o przeciwdzialaniu nadmiernym opoznieniom w transakcjach handlowych.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.


^ permalink raw reply

* Re: [PATCH v3 5/6] net/iavf: disable runtime queue setup capability
From: Dawid Wesierski @ 2026-07-08 23:18 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, thomas, stephen, marek.kasiewicz
In-Reply-To: <20260630120657.1046588-6-dawid.wesierski@intel.com>

Thanks for the review, Bruce.

> Do we really need a commandline arg for this? If it's known enough to have
> the extra arg passed at device init, is it not also known enough to have
> the app not do dynamic reconfiguration in the first place?
>
> Alternatively, if the user configures packet pacing through rte_tm, can we
> not at that point adjust the driver to disallow runtime config by returning
> -ENOTSUP when reconfig is attempted, and no longer advertising the capabilities?
> Runtime configuration, whether with or without user interaction, should be
> preferred over devargs whenever possible.
>
> /Bruce

Agreed. v5 drops the no_runtime_queue_setup devarg entirely.
iavf_dev_info_get() now only advertises RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP
and RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP while no per-queue bandwidth
rte_tm hierarchy is committed; once one is committed, the capabilities are
withdrawn and the ethdev layer rejects a subsequent rx/tx_queue_setup() call
on a running port with -EBUSY, re-advertising automatically once the
hierarchy is torn down. No application opt-in is required anymore.

v5 (2 patches, replacing v4 3/5 and 4/5) is posted separately.

/Dawid
---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Spolka oswiadcza, ze posiada status duzego przedsiebiorcy w rozumieniu ustawy z dnia 8 marca 2013 r. o przeciwdzialaniu nadmiernym opoznieniom w transakcjach handlowych.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.


^ permalink raw reply

* Re: [PATCH v4 2/2] dts: add build arguments to test run configuration
From: Patrick Robb @ 2026-07-08 22:14 UTC (permalink / raw)
  To: Koushik Bhargav Nimoji; +Cc: luca.vizzarro, dev, abailey, ahassick, lylavoie
In-Reply-To: <20260625181557.2331771-2-knimoji@iol.unh.edu>

[-- Attachment #1: Type: text/plain, Size: 586 bytes --]

I think the polish on this patch is okay but also there are some moderate
importance cleanups that are recommended by the AI code review:
https://mails.dpdk.org/archives/test-report/2026-June/1011807.html

If you can't get time for this before RC3 I think we can merge this series,
but some of the cleanups (i.e. safely handling yaml string vs list of
strings format in the test_run.yaml) are valuable and if you can add that
either right now for RC3 or early in the 25.11 release window that is
ideal. Let me know what you think.

Reviewed-by: Patrick Robb <patrickrobb1997@gmail.com>

[-- Attachment #2: Type: text/html, Size: 796 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox