DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v4 0/4] Wangxun fixes and new features
From: Stephen Hemminger @ 2026-06-30 14:15 UTC (permalink / raw)
  To: Zaiyu Wang; +Cc: dev
In-Reply-To: <20260630111608.22196-1-zaiyuwang@trustnetic.com>

On Tue, 30 Jun 2026 19:16:00 +0800
Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:

> This patchset introduces three new features and critical fixes for our
> recent release cycle.
> 
> Patches 1-2 add support for UDP Segmentation Offload (USO) to improve
> large-packet transmission performance for UDP workloads.
> 
> Patch 3 enables VFs to sense PF ifconfig down/up events, allowing
> better fault tolerance and fast recovery in virtualized environments.
> 
> Patch 4 adds the missing VF support for the Amber-Lite 40G NICs, which
> was previously omitted in the initial integration.

Applied to net-next. Had to resolve a code merge conflict from earlier
changes in net-next and also release note conflicts.

^ permalink raw reply

* Re: [PATCH] net/dpaa2: drop the fake software VLAN strip offload
From: Stephen Hemminger @ 2026-06-30 13:39 UTC (permalink / raw)
  To: Maxime Leroy; +Cc: dev, hemant.agrawal, sachin.saxena, mb
In-Reply-To: <20260630124945.399268-1-maxime@leroys.fr>

On Tue, 30 Jun 2026 14:49:45 +0200
Maxime Leroy <maxime@leroys.fr> wrote:

> posts to the store buffer while the line fills in the background, and
> the rewritten fields are forwarded straight from there. buf_addr has
> nothing to forward, so it must be read from the line, whose fill is
> still in flight, and the read stalls. The ethertype read that follows,
> on the cold payload line, stalls again. Read later by the application,
> when the fill has completed, the same read hits. The offload just
> performs it at the worst possible moment.
> 
> Measured on a single-core port-to-port forwarding test over two 10G
> ports (one core at 2 GHz, 64-byte untagged frames):
> 
>   - throughput 4.22 -> 5.00 Mpps (+18 percent)
>   - IPC 0.93 -> 1.25: the cost was memory stall, not compute
>   - L3/DRAM-bound L2 refills 319M -> 200M over 10s (-37 percent)
> 
> perf confirms it: with the offload, the buf_addr load (the cold mbuf
> field) and the payload load account for about 84 percent of the Rx
> burst's L2 refills; removing it, those vanish and only the inherent DQRR
> dequeue misses remain.
> 
> Stop advertising VLAN_STRIP and remove the rte_vlan_strip() calls from
> every Rx path. This is a behavioural change: the tag is left in the
> frame, so an application must strip it itself, on the L2 header it
> already reads.
> 
> Signed-off-by: Maxime Leroy <maxime@leroys.fr>
> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> Acked-by: Stephen Hemminger <stephen@networkplumber.org>
> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

Applied to next-net

^ permalink raw reply

* Re: [PATCH 1/6] ip_frag: tolerate duplicate fragments
From: Stephen Hemminger @ 2026-06-30 13:32 UTC (permalink / raw)
  To: Konstantin Ananyev; +Cc: dev@dpdk.org, stable@dpdk.org, Samyak Jain
In-Reply-To: <de2ff0a594104b9b9cb4575f0ff4f8ed@huawei.com>

On Tue, 30 Jun 2026 08:08:46 +0000
Konstantin Ananyev <konstantin.ananyev@huawei.com> wrote:

> > The reassembly code tracked only a running byte total and reserved slots
> > for the first and last fragments, with no check for a fragment
> > duplicating data already received. A single duplicate could destroy a
> > recoverable datagram:
> >  - a duplicate first or last fragment collided with the reserved slot and
> >    sent the whole entry down the error path, freeing every collected
> >    fragment;
> >  - a duplicate intermediate fragment was appended to a new slot, inflating
> >    frag_size past total_size so reassembly never completed.
> > 
> > RFC 791 reassembly tolerates duplicates: a fragment covering bytes
> > already present carries no new information. Check for an exact duplicate
> > (stored fragment with the same offset and length) and drop only that
> > mbuf, before frag_size is updated, leaving the entry's accounting
> > unchanged.
> > 
> > Overlapping fragments with differing bounds are a separate issue
> > addressed in the next patch.
> > 
> > Fixes: cc8f4d020c0b ("examples/ip_reassembly: initial import")
> > Cc: stable@dpdk.org  
> 
> I am not sure it is a bug and needs to be propagated into the stable releases.
> To me it is more like feature improvement.
> BTW, as this and next patch does change the behavior and probably overall
> performance numbers, - it probably worth to add a line in the release notes.
> As another thought - it might be squashed with next patch in the series
> (ip_frag: discard datagrams with overlapping fragments).
> Apart from that:
> Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>

The problem is that duplicate fragments are used to workaround
firewalls. So latent security issue

^ permalink raw reply

* [PATCH v2] net/virtio-user: fix eventfd sharing in secondary process
From: Samar Yadav @ 2026-06-29 12:06 UTC (permalink / raw)
  To: dev; +Cc: chenbox, maxime.coquelin, stable, stephen, tiwei.bie, Samar Yadav
In-Reply-To: <20260626080513.2371033-1-ysamar@vmware.com>

virtio_user secondary processes cannot communicate with the vhost
backend: the kick/call eventfds are opened by the primary and never
shared, so a secondary's queue notification writes to an invalid fd
and traffic stalls.

Share the fds over a dedicated virtio-user multiprocess channel. The
primary registers a process-wide MP action that returns a port's
kick/call fds (looked up by port name); a secondary requests them at
probe time, before the port is announced.

The received fds are stored in eth_dev->process_private, which is
per-process, instead of the primary-owned shared dev->kickfds and
dev->callfds arrays; the secondary data path notifies the backend using
its own kickfd. In the primary, the MP handler reads the fd arrays under
dev->mutex, and the teardown path takes the same lock while closing and
freeing them, so the two cannot race.

Also fix the pre-existing pthread_mutex_init(&dev->mutex, NULL) call in
virtio_user_dev_init(): POSIX requires PTHREAD_PROCESS_SHARED for a mutex
stored in shared memory regardless of which processes actually lock it;
use rte_thread_mutex_init_shared() as other multiprocess-aware drivers do.

Fixes: 1c8489da561b ("net/virtio-user: fix multi-process support")
Cc: tiwei.bie@intel.com
Cc: stable@dpdk.org

Signed-off-by: Samar Yadav <samaryadav5@gmail.com>
---
v2:
- Use rte_calloc() instead of rte_malloc() for the kick/call fd arrays
  in virtio_user_sync_eventfds() so allocation failures are cleaner and
  unset entries are zero-initialised before the explicit -1 sentinel loop.
  (Stephen Hemminger)
- Fix the pre-existing pthread_mutex_init(&dev->mutex, NULL) call in
  virtio_user_dev_init() to use rte_thread_mutex_init_shared(), which
  sets PTHREAD_PROCESS_SHARED as POSIX requires for a mutex in shared
  memory. Add #include <rte_thread.h> to pull in the declaration.
  (Stephen Hemminger)

 .mailmap                                      |   1 +
 .../net/virtio/virtio_user/virtio_user_dev.c  |  59 +++-
 .../net/virtio/virtio_user/virtio_user_dev.h  |  20 ++
 drivers/net/virtio/virtio_user_ethdev.c       | 260 +++++++++++++++++-
 4 files changed, 335 insertions(+), 5 deletions(-)

diff --git a/.mailmap b/.mailmap
index 4001e5f..8f921d4 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1448,6 +1448,7 @@ Salem Sol <salems@nvidia.com>
 Sam Andrew <samandrew@microsoft.com>
 Sam Chen <sam.chen@nebula-matrix.com>
 Sam Grove <sam.grove@sifive.com>
+Samar Yadav <samaryadav5@gmail.com> <samar.yadav@broadcom.com>
 Sameer Vaze <svaze@qti.qualcomm.com>
 Sameh Gobriel <sameh.gobriel@intel.com>
 Samik Gupta <samik.gupta@broadcom.com>
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c
index f3df73c..82a8cf4 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.c
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c
@@ -15,6 +15,7 @@
 #include <sys/stat.h>
 
 #include <rte_alarm.h>
+#include <rte_thread.h>
 #include <rte_string_fns.h>
 #include <rte_eal_memconfig.h>
 #include <rte_malloc.h>
@@ -34,6 +35,54 @@ const char * const virtio_user_backend_strings[] = {
 	[VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA",
 };
 
+/*
+ * Collect the primary device's kick/call fds (interleaved kick,call per queue)
+ * for sharing with a secondary process. Caller must serialize against the
+ * control path (dev->mutex) so the fd arrays are not freed concurrently.
+ */
+int
+virtio_user_get_eventfds_from_dev(struct virtio_user_dev *dev,
+				 int fds[VIRTIO_USER_MAX_EVENTFDS])
+{
+	uint32_t max_queues;
+	int i, total_fds = 0;
+	int kickfd, callfd;
+
+	if (dev == NULL || fds == NULL)
+		return -EINVAL;
+
+	if (dev->kickfds == NULL || dev->callfds == NULL) {
+		PMD_INIT_LOG(ERR, "Device eventfd arrays not initialized");
+		return -EINVAL;
+	}
+
+	max_queues = dev->max_queue_pairs * 2;
+	if (dev->hw_cvq)
+		max_queues += 1;
+
+	/* each queue contributes a kick and a call fd */
+	if (max_queues * 2 > VIRTIO_USER_MAX_EVENTFDS) {
+		PMD_INIT_LOG(ERR,
+			     "Device needs %u eventfds, exceeds MP limit %d",
+			     max_queues * 2, VIRTIO_USER_MAX_EVENTFDS);
+		return -E2BIG;
+	}
+
+	for (i = 0; i < (int)max_queues; i++) {
+		kickfd = dev->kickfds[i];
+		callfd = dev->callfds[i];
+		if (kickfd < 0 || callfd < 0) {
+			PMD_INIT_LOG(ERR, "Queue %d has invalid fds (kick=%d call=%d)",
+				     i, kickfd, callfd);
+			return -EINVAL;
+		}
+		fds[total_fds++] = kickfd;
+		fds[total_fds++] = callfd;
+	}
+
+	return total_fds;
+}
+
 static int
 virtio_user_uninit_notify_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
 {
@@ -733,7 +782,7 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues,
 {
 	uint64_t backend_features;
 
-	pthread_mutex_init(&dev->mutex, NULL);
+	rte_thread_mutex_init_shared(&dev->mutex);
 	strlcpy(dev->path, path, PATH_MAX);
 
 	dev->started = 0;
@@ -865,9 +914,15 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev)
 
 	rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev);
 
+	/*
+	 * Serialize closing/freeing the kick/call fd arrays against the MP
+	 * handler, which reads them under the same lock to share them with
+	 * secondary processes.
+	 */
+	pthread_mutex_lock(&dev->mutex);
 	virtio_user_dev_uninit_notify(dev);
-
 	virtio_user_free_vrings(dev);
+	pthread_mutex_unlock(&dev->mutex);
 
 	free(dev->ifname);
 
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h
index 66400b3..1a7334d 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.h
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h
@@ -11,6 +11,11 @@
 #include "../virtio.h"
 #include "../virtio_ring.h"
 
+#include <rte_eal.h>
+
+/* Max eventfds shareable over the MP channel (bounded by SCM_RIGHTS). */
+#define VIRTIO_USER_MAX_EVENTFDS RTE_MP_MAX_FD_NUM
+
 enum virtio_user_backend_type {
 	VIRTIO_USER_BACKEND_UNKNOWN,
 	VIRTIO_USER_BACKEND_VHOST_USER,
@@ -89,5 +94,20 @@ int virtio_user_dev_get_rss_config(struct virtio_user_dev *dev, void *dst, size_
 				   int length);
 void virtio_user_dev_delayed_disconnect_handler(void *param);
 int virtio_user_dev_server_reconnect(struct virtio_user_dev *dev);
+
+/**
+ * Collect a primary device's kick/call eventfds for sharing with a
+ * secondary process over the multiprocess channel.
+ *
+ * @param dev
+ *   Pointer to the virtio_user device (primary).
+ * @param fds
+ *   Output array, must hold at least VIRTIO_USER_MAX_EVENTFDS elements.
+ * @return
+ *   Number of fds written on success, negative errno on error.
+ */
+int virtio_user_get_eventfds_from_dev(struct virtio_user_dev *dev,
+				     int fds[VIRTIO_USER_MAX_EVENTFDS]);
+
 extern const char * const virtio_user_backend_strings[];
 #endif
diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c
index 747ddde..9817142 100644
--- a/drivers/net/virtio/virtio_user_ethdev.c
+++ b/drivers/net/virtio/virtio_user_ethdev.c
@@ -27,6 +27,35 @@
 #include "virtio_rxtx.h"
 #include "virtio_user/virtio_user_dev.h"
 #include "virtio_user/vhost.h"
+#include <errno.h>
+#include <rte_errno.h>
+#include <rte_string_fns.h>
+#include <rte_spinlock.h>
+
+/* Virtio-user multiprocess communication channel */
+#define VIRTIO_USER_MP_NAME "virtio_user_mp"
+
+struct virtio_user_mp_param {
+	char port_name[RTE_DEV_NAME_MAX_LEN];
+};
+
+/*
+ * Per-process private data, referenced by eth_dev->process_private which (unlike
+ * dev_private) is NOT shared between primary and secondary processes. A secondary
+ * stores the kick/call fds it receives from the primary here, so it never mutates
+ * the primary-owned shared dev->kickfds/dev->callfds arrays. callfds are kept for
+ * a complete per-process view of the backend fds; only kickfds are used by the
+ * secondary data path today.
+ */
+struct virtio_user_proc_priv {
+	uint32_t nr_queues;
+	int *kickfds;
+	int *callfds;
+};
+
+/* Guards one-time registration of the process-wide MP action. */
+static rte_spinlock_t virtio_user_mp_lock = RTE_SPINLOCK_INITIALIZER;
+static bool virtio_user_mp_registered;
 
 #define virtio_user_get_dev(hwp) container_of(hwp, struct virtio_user_dev, hw)
 
@@ -269,6 +298,26 @@ virtio_user_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 		virtio_user_dev_destroy_shadow_cvq(dev);
 }
 
+/*
+ * Return the kick fd to notify the backend for a queue in the running process.
+ * The secondary uses its own fds (process_private); the primary owns dev->kickfds.
+ */
+static int
+virtio_user_get_kickfd(struct virtio_hw *hw, struct virtio_user_dev *dev,
+		      uint16_t queue_idx)
+{
+	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
+		struct rte_eth_dev *eth_dev = &rte_eth_devices[hw->port_id];
+		struct virtio_user_proc_priv *pp = eth_dev->process_private;
+
+		if (pp == NULL || queue_idx >= pp->nr_queues)
+			return -1;
+		return pp->kickfds[queue_idx];
+	}
+
+	return dev->kickfds[queue_idx];
+}
+
 static void
 virtio_user_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
@@ -282,8 +331,10 @@ virtio_user_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	}
 
 	if (!dev->notify_area) {
-		if (write(dev->kickfds[vq->vq_queue_index], &notify_data,
-			  sizeof(notify_data)) < 0)
+		int kickfd = virtio_user_get_kickfd(hw, dev, vq->vq_queue_index);
+
+		if (kickfd < 0 || write(kickfd, &notify_data,
+				sizeof(notify_data)) < 0)
 			PMD_DRV_LOG(ERR, "failed to kick backend: %s",
 				    strerror(errno));
 		return;
@@ -495,6 +546,166 @@ virtio_user_eth_dev_free(struct rte_eth_dev *eth_dev)
 	rte_eth_dev_release_port(eth_dev);
 }
 
+/* Close and free a secondary's per-process eventfd storage. */
+static void
+virtio_user_free_proc_priv(struct rte_eth_dev *eth_dev)
+{
+	struct virtio_user_proc_priv *pp = eth_dev->process_private;
+	uint32_t i;
+
+	if (pp == NULL)
+		return;
+
+	for (i = 0; i < pp->nr_queues; i++) {
+		if (pp->kickfds != NULL && pp->kickfds[i] >= 0)
+			close(pp->kickfds[i]);
+		if (pp->callfds != NULL && pp->callfds[i] >= 0)
+			close(pp->callfds[i]);
+	}
+
+	rte_free(pp->kickfds);
+	rte_free(pp->callfds);
+	rte_free(pp);
+	eth_dev->process_private = NULL;
+}
+
+/*
+ * Primary-side MP handler: reply with this port's kick/call eventfds so the
+ * requesting secondary can talk to the vhost backend. Always sends a reply
+ * (num_fds == 0 on error) so the secondary fails fast instead of timing out.
+ */
+static int
+virtio_user_mp_primary_handler(const struct rte_mp_msg *msg, const void *peer)
+{
+	const struct virtio_user_mp_param *param =
+		(const struct virtio_user_mp_param *)msg->param;
+	int eventfds[VIRTIO_USER_MAX_EVENTFDS];
+	struct rte_eth_dev *eth_dev;
+	struct virtio_user_dev *dev;
+	struct rte_mp_msg reply;
+	int num_fds;
+	int i;
+
+	memset(&reply, 0, sizeof(reply));
+	strlcpy(reply.name, msg->name, sizeof(reply.name));
+	reply.len_param = 0;
+	reply.num_fds = 0;
+
+	eth_dev = rte_eth_dev_get_by_name(param->port_name);
+	if (eth_dev == NULL || eth_dev->data->dev_private == NULL) {
+		PMD_INIT_LOG(ERR, "Failed to find virtio_user port: %s",
+			     param->port_name);
+		return rte_mp_reply(&reply, peer);
+	}
+
+	dev = eth_dev->data->dev_private;
+
+	/* serialize against control-path changes to the fd arrays */
+	pthread_mutex_lock(&dev->mutex);
+	num_fds = virtio_user_get_eventfds_from_dev(dev, eventfds);
+	if (num_fds >= 0 && num_fds <= RTE_MP_MAX_FD_NUM) {
+		reply.num_fds = num_fds;
+		for (i = 0; i < num_fds; i++)
+			reply.fds[i] = eventfds[i];
+	} else {
+		PMD_INIT_LOG(ERR, "Cannot share eventfds for %s (ret=%d)",
+			     param->port_name, num_fds);
+	}
+	pthread_mutex_unlock(&dev->mutex);
+
+	return rte_mp_reply(&reply, peer);
+}
+
+/*
+ * Secondary-side: request the primary's kick/call eventfds and store them in
+ * this process's eth_dev->process_private. The shared dev->kickfds/dev->callfds
+ * arrays (owned by the primary) are never touched.
+ */
+static int
+virtio_user_sync_eventfds(struct rte_eth_dev *eth_dev, struct virtio_user_dev *dev)
+{
+	struct rte_mp_msg mp_req, *mp_rep;
+	struct rte_mp_reply mp_reply = {0};
+	struct virtio_user_mp_param *req_param;
+	struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
+	struct virtio_user_proc_priv *pp;
+	uint32_t total_queues, i;
+	int nr_fds, ret = 0;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (rte_eal_process_type() != RTE_PROC_SECONDARY)
+		return -EINVAL;
+
+	total_queues = dev->max_queue_pairs * 2 + (dev->hw_cvq ? 1 : 0);
+
+	pp = rte_zmalloc("virtio_user_proc_priv", sizeof(*pp), 0);
+	if (pp == NULL)
+		return -ENOMEM;
+
+	pp->kickfds = rte_calloc("virtio_user_proc_priv",
+				 total_queues, sizeof(int), 0);
+	pp->callfds = rte_calloc("virtio_user_proc_priv",
+				 total_queues, sizeof(int), 0);
+	if (pp->kickfds == NULL || pp->callfds == NULL) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+	for (i = 0; i < total_queues; i++) {
+		pp->kickfds[i] = -1;
+		pp->callfds[i] = -1;
+	}
+
+	memset(&mp_req, 0, sizeof(mp_req));
+	req_param = (struct virtio_user_mp_param *)mp_req.param;
+	strlcpy(req_param->port_name, eth_dev->data->name,
+		sizeof(req_param->port_name));
+	strlcpy(mp_req.name, VIRTIO_USER_MP_NAME, RTE_MP_MAX_NAME_LEN);
+	mp_req.len_param = sizeof(*req_param);
+	mp_req.num_fds = 0;
+
+	if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) < 0 ||
+	    mp_reply.nb_received != 1) {
+		PMD_INIT_LOG(ERR, "Failed to request eventfds from primary");
+		free(mp_reply.msgs);
+		ret = -EIO;
+		goto err_free;
+	}
+
+	mp_rep = &mp_reply.msgs[0];
+	nr_fds = mp_rep->num_fds;
+
+	/* a partially-synced device cannot work: treat any mismatch as fatal */
+	if (nr_fds != (int)total_queues * 2) {
+		PMD_INIT_LOG(ERR, "Expected %u eventfds, received %d",
+			     total_queues * 2, nr_fds);
+		for (i = 0; i < (uint32_t)nr_fds; i++)
+			close(mp_rep->fds[i]);
+		free(mp_reply.msgs);
+		ret = -EPROTO;
+		goto err_free;
+	}
+
+	for (i = 0; i < total_queues; i++) {
+		pp->kickfds[i] = mp_rep->fds[i * 2];
+		pp->callfds[i] = mp_rep->fds[i * 2 + 1];
+	}
+	pp->nr_queues = total_queues;
+	free(mp_reply.msgs);
+
+	eth_dev->process_private = pp;
+	PMD_INIT_LOG(DEBUG, "Synced %u queue eventfds for secondary port %s",
+		     total_queues, eth_dev->data->name);
+	return 0;
+
+err_free:
+	rte_free(pp->kickfds);
+	rte_free(pp->callfds);
+	rte_free(pp);
+	return ret;
+}
+
 /* Dev initialization routine. Invoked once for each virtio vdev at
  * EAL init time, see rte_bus_probe().
  * Returns 0 on success.
@@ -542,6 +753,17 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
 
 		eth_dev->dev_ops = &virtio_user_secondary_eth_dev_ops;
 		eth_dev->device = &vdev->device;
+
+		/* populate this process's eventfds before announcing the port */
+		ret = virtio_user_sync_eventfds(eth_dev, dev);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				     "Failed to sync eventfds in secondary: %d",
+				     ret);
+			rte_eth_dev_release_port(eth_dev);
+			return ret;
+		}
+
 		rte_eth_dev_probing_finish(eth_dev);
 		return 0;
 	}
@@ -722,6 +944,36 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev)
 		}
 	}
 
+	/*
+	 * Register the process-wide MP action once so secondaries can fetch a
+	 * port's eventfds by name. It is intentionally left registered for the
+	 * lifetime of the process (cleaned up at exit): unregistering per device
+	 * cannot drain handler calls already dispatched on the EAL MP thread.
+	 */
+	rte_spinlock_lock(&virtio_user_mp_lock);
+	if (!virtio_user_mp_registered) {
+		ret = rte_mp_action_register(VIRTIO_USER_MP_NAME,
+					     virtio_user_mp_primary_handler);
+		if (ret < 0 && rte_errno != EEXIST) {
+			rte_spinlock_unlock(&virtio_user_mp_lock);
+			if (rte_errno == ENOTSUP) {
+				PMD_INIT_LOG(WARNING,
+					"MP unsupported, secondary eventfd sharing disabled");
+				rte_eth_dev_probing_finish(eth_dev);
+				ret = 0;
+				goto end;
+			}
+			PMD_INIT_LOG(ERR, "Failed to register MP handler: %s",
+				     strerror(rte_errno));
+			virtio_user_dev_uninit(dev);
+			virtio_user_eth_dev_free(eth_dev);
+			ret = -1;
+			goto end;
+		}
+		virtio_user_mp_registered = true;
+	}
+	rte_spinlock_unlock(&virtio_user_mp_lock);
+
 	rte_eth_dev_probing_finish(eth_dev);
 	ret = 0;
 
@@ -749,8 +1001,10 @@ virtio_user_pmd_remove(struct rte_vdev_device *vdev)
 	if (!eth_dev)
 		return 0;
 
-	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		virtio_user_free_proc_priv(eth_dev);
 		return rte_eth_dev_release_port(eth_dev);
+	}
 
 	/* make sure the device is stopped, queues freed */
 	return rte_eth_dev_close(eth_dev->data->port_id);
-- 
2.43.0


^ permalink raw reply related

* [PATCH 2/2] test/dmadev: add config and vchan validation tests
From: datshan @ 2026-06-29  4:17 UTC (permalink / raw)
  To: thomas; +Cc: dev
In-Reply-To: <20260629041735.301180-1-datshan@qq.com>

From: Chengwen Feng <fengchengwen@huawei.com>

Add negative-case tests for new checks in rte_dma_configure()
(undefined flags, capa-unaware flags/priority) and in
rte_dma_vchan_setup() (enum values, reserved fields, domain
mismatch, capability enforcement).

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev_api.c | 186 ++++++++++++++++++++++++++++++++++---
 1 file changed, 174 insertions(+), 12 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 1ba053696b..fb2a1afcaa 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -130,6 +130,55 @@ test_dma_info_get(void)
 	return TEST_SUCCESS;
 }
 
+static int
+check_configure_extra(struct rte_dma_info *info)
+{
+	struct rte_dma_conf conf = { 0 };
+	int ret;
+
+	/* Check undefined flags */
+	for (int i = 2; i < 64; i++) {
+		memset(&conf, 0, sizeof(conf));
+		conf.nb_vchans = info->max_vchans;
+		conf.flags = RTE_BIT64(i);
+		ret = rte_dma_configure(test_dev_id, &conf);
+		RTE_TEST_ASSERT(ret == -EINVAL,
+			"Expected -EINVAL for undefined flag bit %d, %d", i, ret);
+	}
+
+	/* Check enable silent mode without support */
+	if (!(info->dev_capa & RTE_DMA_CAPA_SILENT)) {
+		memset(&conf, 0, sizeof(conf));
+		conf.nb_vchans = info->max_vchans;
+		conf.flags = RTE_DMA_CFG_FLAG_SILENT;
+		ret = rte_dma_configure(test_dev_id, &conf);
+		RTE_TEST_ASSERT(ret == -EINVAL,
+			"Expected -EINVAL for SILENT without capa, %d", ret);
+	}
+
+	/* Check enable enqueue/dequeue mode without support */
+	if (!(info->dev_capa & RTE_DMA_CAPA_OPS_ENQ_DEQ)) {
+		memset(&conf, 0, sizeof(conf));
+		conf.nb_vchans = info->max_vchans;
+		conf.flags = RTE_DMA_CFG_FLAG_ENQ_DEQ;
+		ret = rte_dma_configure(test_dev_id, &conf);
+		RTE_TEST_ASSERT(ret == -EINVAL,
+			"Expected -EINVAL for ENQ_DEQ without capa, %d", ret);
+	}
+
+	/* Check non-zero priority without SP capability */
+	if (!(info->dev_capa & RTE_DMA_CAPA_PRI_POLICY_SP)) {
+		memset(&conf, 0, sizeof(conf));
+		conf.nb_vchans = info->max_vchans;
+		conf.priority = 1;
+		ret = rte_dma_configure(test_dev_id, &conf);
+		RTE_TEST_ASSERT(ret == -EINVAL,
+			"Expected -EINVAL for non-zero priority without SP, %d", ret);
+	}
+
+	return 0;
+}
+
 static int
 test_dma_configure(void)
 {
@@ -156,12 +205,9 @@ test_dma_configure(void)
 	ret = rte_dma_configure(test_dev_id, &conf);
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
-	/* Check enable silent mode */
-	memset(&conf, 0, sizeof(conf));
-	conf.nb_vchans = info.max_vchans;
-	conf.flags = RTE_DMA_CFG_FLAG_SILENT;
-	ret = rte_dma_configure(test_dev_id, &conf);
-	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	/* Check flags, priority extra validations */
+	ret = check_configure_extra(&info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to check configure extra");
 
 	/* Configure success */
 	memset(&conf, 0, sizeof(conf));
@@ -209,12 +255,21 @@ check_direction(void)
 }
 
 static int
-check_port_type(struct rte_dma_info *dev_info)
+check_vchan_port(struct rte_dma_info *dev_info)
 {
 	struct rte_dma_vchan_conf vchan_conf;
 	int ret;
 
-	/* Check src port type validation */
+	/* Check invalid port_type enum values */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.src_port.port_type = RTE_DMA_PORT_PCIE + 1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for invalid port_type, %d", ret);
+
+	/* Check src port type vs direction mismatch */
 	memset(&vchan_conf, 0, sizeof(vchan_conf));
 	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
 	vchan_conf.nb_desc = dev_info->min_desc;
@@ -222,7 +277,7 @@ check_port_type(struct rte_dma_info *dev_info)
 	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
-	/* Check dst port type validation */
+	/* Check dst port type vs direction mismatch */
 	memset(&vchan_conf, 0, sizeof(vchan_conf));
 	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
 	vchan_conf.nb_desc = dev_info->min_desc;
@@ -230,6 +285,105 @@ check_port_type(struct rte_dma_info *dev_info)
 	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
+	/* Check non-zero reserved fields in src_port */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.src_port.reserved[0] = 1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for non-zero src_port.reserved, %d", ret);
+
+	/* Check non-zero reserved fields in dst_port */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.dst_port.reserved[0] = 1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for non-zero dst_port.reserved, %d", ret);
+
+	return 0;
+}
+
+static int
+check_vchan_domain(struct rte_dma_info *dev_info)
+{
+	struct rte_dma_vchan_conf vchan_conf;
+	int ret;
+
+	/* Check invalid domain type enum */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.domain.type = RTE_DMA_INTER_OS_DOMAIN + 1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for invalid domain type, %d", ret);
+
+	/* Check non-zero domain.reserved */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.domain.reserved[0] = 1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for non-zero domain.reserved, %d", ret);
+
+	/* Check inter-domain type without MEM_TO_MEM direction */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_DEV;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.domain.type = RTE_DMA_INTER_PROCESS_DOMAIN;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for inter-domain non-MEM_TO_MEM, %d", ret);
+
+	/* Check domain INTER_PROCESS without capability */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.domain.type = RTE_DMA_INTER_PROCESS_DOMAIN;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for INTER_PROCESS without capa, %d", ret);
+
+	/* Check domain INTER_OS without capability */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.domain.type = RTE_DMA_INTER_OS_DOMAIN;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for INTER_OS without capa, %d", ret);
+
+	return 0;
+}
+
+static int
+check_auto_free_conf(struct rte_dma_info *dev_info)
+{
+	struct rte_dma_vchan_conf vchan_conf;
+	int ret;
+
+	/* Check non-zero reserved fields in auto_free */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.auto_free.reserved[0] = 1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for non-zero auto_free.reserved, %d", ret);
+
+	/* Check auto_free.m2d.pool without M2D auto-free capability */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info->min_desc;
+	vchan_conf.auto_free.m2d.pool = (struct rte_mempool *)(uintptr_t)0x1;
+	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL,
+		"Expected -EINVAL for auto_free without M2D capa, %d", ret);
+
 	return 0;
 }
 
@@ -274,9 +428,17 @@ test_dma_vchan_setup(void)
 	ret = rte_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
-	/* Check port type */
-	ret = check_port_type(&dev_info);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to check port type");
+	/* Check port type and reserved fields */
+	ret = check_vchan_port(&dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to check vchan port");
+
+	/* Check domain param validation */
+	ret = check_vchan_domain(&dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to check vchan domain");
+
+	/* Check auto_free config validation */
+	ret = check_auto_free_conf(&dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to check auto_free conf");
 
 	/* Check vchan setup success */
 	memset(&vchan_conf, 0, sizeof(vchan_conf));
-- 
2.54.0


^ permalink raw reply related

* [PATCH 1/2] dmadev: fix incomplete configuration validation
From: datshan @ 2026-06-29  4:17 UTC (permalink / raw)
  To: thomas; +Cc: dev
In-Reply-To: <20260629041735.301180-1-datshan@qq.com>

From: Chengwen Feng <fengchengwen@huawei.com>

Add a dma_check_vchan_conf() helper to validate rte_dma_vchan_conf
fields that do not depend on device capabilities: direction enum,
port_type enum, domain type enum, and all reserved[] arrays.

In rte_dma_configure(), reject undefined flag bits and non-zero
priority when the device lacks priority scheduling support.

Fixes: b36970f2e13e ("dmadev: introduce DMA device library")
Cc: stable@dpdk.org

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 lib/dmadev/rte_dmadev.c | 156 ++++++++++++++++++++++++++++------------
 1 file changed, 109 insertions(+), 47 deletions(-)

diff --git a/lib/dmadev/rte_dmadev.c b/lib/dmadev/rte_dmadev.c
index 822bb7c89f..2311f01906 100644
--- a/lib/dmadev/rte_dmadev.c
+++ b/lib/dmadev/rte_dmadev.c
@@ -480,6 +480,7 @@ RTE_EXPORT_SYMBOL(rte_dma_configure)
 int
 rte_dma_configure(int16_t dev_id, const struct rte_dma_conf *dev_conf)
 {
+	const uint64_t valid_flags = RTE_DMA_CFG_FLAG_SILENT | RTE_DMA_CFG_FLAG_ENQ_DEQ;
 	struct rte_dma_info dev_info;
 	struct rte_dma_dev *dev;
 	int ret;
@@ -510,18 +511,28 @@ rte_dma_configure(int16_t dev_id, const struct rte_dma_conf *dev_conf)
 			"Device %d configure too many vchans", dev_id);
 		return -EINVAL;
 	}
+
+	if (dev_info.dev_capa & RTE_DMA_CAPA_PRI_POLICY_SP) {
+		if (dev_conf->priority >= dev_info.nb_priorities) {
+			RTE_DMA_LOG(ERR, "Device %d configure invalid priority", dev_id);
+			return -EINVAL;
+		}
+	} else {
+		if (dev_conf->priority != 0) {
+			RTE_DMA_LOG(ERR, "Device %d should not configure priority", dev_id);
+			return -EINVAL;
+		}
+	}
+
+	if ((dev_conf->flags & ~valid_flags) != 0) {
+		RTE_DMA_LOG(ERR, "Device %d configure invalid flags", dev_id);
+		return -EINVAL;
+	}
 	if ((dev_conf->flags & RTE_DMA_CFG_FLAG_SILENT) &&
 	    !(dev_info.dev_capa & RTE_DMA_CAPA_SILENT)) {
 		RTE_DMA_LOG(ERR, "Device %d don't support silent", dev_id);
 		return -EINVAL;
 	}
-
-	if ((dev_info.dev_capa & RTE_DMA_CAPA_PRI_POLICY_SP) &&
-	    (dev_conf->priority >= dev_info.nb_priorities)) {
-		RTE_DMA_LOG(ERR, "Device %d configure invalid priority", dev_id);
-		return -EINVAL;
-	}
-
 	if ((dev_conf->flags & RTE_DMA_CFG_FLAG_ENQ_DEQ) &&
 	    !(dev_info.dev_capa & RTE_DMA_CAPA_OPS_ENQ_DEQ)) {
 		RTE_DMA_LOG(ERR, "Device %d don't support enqueue/dequeue", dev_id);
@@ -632,13 +643,85 @@ rte_dma_close(int16_t dev_id)
 	return ret;
 }
 
+/* Perform verification on rte_dma_vchan_conf only. */
+static int
+dma_check_vchan_conf(int16_t dev_id, const struct rte_dma_vchan_conf *conf)
+{
+	bool src_is_dev, dst_is_dev;
+
+	if (conf->direction != RTE_DMA_DIR_MEM_TO_MEM &&
+	    conf->direction != RTE_DMA_DIR_MEM_TO_DEV &&
+	    conf->direction != RTE_DMA_DIR_DEV_TO_MEM &&
+	    conf->direction != RTE_DMA_DIR_DEV_TO_DEV) {
+		RTE_DMA_LOG(ERR, "Device %d direction invalid!", dev_id);
+		return -EINVAL;
+	}
+
+	if (conf->src_port.port_type != RTE_DMA_PORT_NONE &&
+	    conf->src_port.port_type != RTE_DMA_PORT_PCIE) {
+		RTE_DMA_LOG(ERR, "Device %d source port type unsupported", dev_id);
+		return -EINVAL;
+	}
+	if (conf->src_port.reserved[0] != 0 || conf->src_port.reserved[1] != 0) {
+		RTE_DMA_LOG(ERR, "Device %d src_port has non-zero reserved fields", dev_id);
+		return -EINVAL;
+	}
+	src_is_dev = conf->direction == RTE_DMA_DIR_DEV_TO_MEM ||
+		     conf->direction == RTE_DMA_DIR_DEV_TO_DEV;
+	if ((conf->src_port.port_type == RTE_DMA_PORT_NONE && src_is_dev) ||
+	    (conf->src_port.port_type != RTE_DMA_PORT_NONE && !src_is_dev)) {
+		RTE_DMA_LOG(ERR, "Device %d source port type invalid", dev_id);
+		return -EINVAL;
+	}
+
+	if (conf->dst_port.port_type != RTE_DMA_PORT_NONE &&
+	    conf->dst_port.port_type != RTE_DMA_PORT_PCIE) {
+		RTE_DMA_LOG(ERR, "Device %d destination port type unsupported", dev_id);
+		return -EINVAL;
+	}
+	if (conf->dst_port.reserved[0] != 0 || conf->dst_port.reserved[1] != 0) {
+		RTE_DMA_LOG(ERR, "Device %d dst_port has non-zero reserved fields", dev_id);
+		return -EINVAL;
+	}
+	dst_is_dev = conf->direction == RTE_DMA_DIR_MEM_TO_DEV ||
+		     conf->direction == RTE_DMA_DIR_DEV_TO_DEV;
+	if ((conf->dst_port.port_type == RTE_DMA_PORT_NONE && dst_is_dev) ||
+	    (conf->dst_port.port_type != RTE_DMA_PORT_NONE && !dst_is_dev)) {
+		RTE_DMA_LOG(ERR,
+			"Device %d destination port type invalid", dev_id);
+		return -EINVAL;
+	}
+
+	if (conf->auto_free.reserved[0] != 0 || conf->auto_free.reserved[1] != 0) {
+		RTE_DMA_LOG(ERR, "Device %d auto_free has non-zero reserved fields", dev_id);
+		return -EINVAL;
+	}
+
+	if (conf->domain.type != RTE_DMA_INTER_DOMAIN_NONE &&
+	    conf->domain.type != RTE_DMA_INTER_PROCESS_DOMAIN &&
+	    conf->domain.type != RTE_DMA_INTER_OS_DOMAIN) {
+		RTE_DMA_LOG(ERR, "Device %d domain type invalid!", dev_id);
+		return -EINVAL;
+	}
+	if (conf->domain.reserved[0] != 0 || conf->domain.reserved[1] != 0) {
+		RTE_DMA_LOG(ERR, "Device %d domain has non-zero reserved fields", dev_id);
+		return -EINVAL;
+	}
+	if (conf->domain.type != RTE_DMA_INTER_DOMAIN_NONE &&
+	    conf->direction != RTE_DMA_DIR_MEM_TO_MEM) {
+		RTE_DMA_LOG(ERR, "Device %d inter domain only support mem-to-mem transfer", dev_id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 RTE_EXPORT_SYMBOL(rte_dma_vchan_setup)
 int
 rte_dma_vchan_setup(int16_t dev_id, uint16_t vchan,
 		    const struct rte_dma_vchan_conf *conf)
 {
 	struct rte_dma_info dev_info;
-	bool src_is_dev, dst_is_dev;
 	struct rte_dma_dev *dev;
 	int ret;
 
@@ -653,6 +736,10 @@ rte_dma_vchan_setup(int16_t dev_id, uint16_t vchan,
 		return -EBUSY;
 	}
 
+	ret = dma_check_vchan_conf(dev_id, conf);
+	if (ret != 0)
+		return ret;
+
 	ret = rte_dma_info_get(dev_id, &dev_info);
 	if (ret != 0) {
 		RTE_DMA_LOG(ERR, "Device %d get device info fail", dev_id);
@@ -666,34 +753,7 @@ rte_dma_vchan_setup(int16_t dev_id, uint16_t vchan,
 		RTE_DMA_LOG(ERR, "Device %d vchan out range!", dev_id);
 		return -EINVAL;
 	}
-	if (conf->domain.type != RTE_DMA_INTER_DOMAIN_NONE &&
-	    conf->direction != RTE_DMA_DIR_MEM_TO_MEM) {
-		RTE_DMA_LOG(ERR, "Device %d inter domain only support mem-to-mem transfer", dev_id);
-		return -EINVAL;
-	}
-	if (conf->domain.type == RTE_DMA_INTER_OS_DOMAIN &&
-	    !(dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN)) {
-		RTE_DMA_LOG(ERR, "Device %d does not support inter os domain", dev_id);
-		return -EINVAL;
-	}
-	if (conf->domain.type == RTE_DMA_INTER_PROCESS_DOMAIN &&
-	    !(dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN)) {
-		RTE_DMA_LOG(ERR, "Device %d does not support inter process domain", dev_id);
-		return -EINVAL;
-	}
-	if ((conf->domain.type == RTE_DMA_INTER_PROCESS_DOMAIN ||
-	    conf->domain.type == RTE_DMA_INTER_OS_DOMAIN) &&
-	    (conf->domain.reserved[0] != 0 || conf->domain.reserved[1] != 0)) {
-		RTE_DMA_LOG(ERR, "Device %d does not support non-zero reserved fields", dev_id);
-		return -EINVAL;
-	}
-	if (conf->direction != RTE_DMA_DIR_MEM_TO_MEM &&
-	    conf->direction != RTE_DMA_DIR_MEM_TO_DEV &&
-	    conf->direction != RTE_DMA_DIR_DEV_TO_MEM &&
-	    conf->direction != RTE_DMA_DIR_DEV_TO_DEV) {
-		RTE_DMA_LOG(ERR, "Device %d direction invalid!", dev_id);
-		return -EINVAL;
-	}
+
 	if (conf->direction == RTE_DMA_DIR_MEM_TO_MEM &&
 	    !(dev_info.dev_capa & RTE_DMA_CAPA_MEM_TO_MEM)) {
 		RTE_DMA_LOG(ERR,
@@ -724,19 +784,21 @@ rte_dma_vchan_setup(int16_t dev_id, uint16_t vchan,
 			"Device %d number of descriptors invalid", dev_id);
 		return -EINVAL;
 	}
-	src_is_dev = conf->direction == RTE_DMA_DIR_DEV_TO_MEM ||
-		     conf->direction == RTE_DMA_DIR_DEV_TO_DEV;
-	if ((conf->src_port.port_type == RTE_DMA_PORT_NONE && src_is_dev) ||
-	    (conf->src_port.port_type != RTE_DMA_PORT_NONE && !src_is_dev)) {
-		RTE_DMA_LOG(ERR, "Device %d source port type invalid", dev_id);
+
+	if (conf->auto_free.m2d.pool != NULL &&
+	    !(dev_info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE)) {
+		RTE_DMA_LOG(ERR, "Device %d does not support m2d auto free", dev_id);
 		return -EINVAL;
 	}
-	dst_is_dev = conf->direction == RTE_DMA_DIR_MEM_TO_DEV ||
-		     conf->direction == RTE_DMA_DIR_DEV_TO_DEV;
-	if ((conf->dst_port.port_type == RTE_DMA_PORT_NONE && dst_is_dev) ||
-	    (conf->dst_port.port_type != RTE_DMA_PORT_NONE && !dst_is_dev)) {
-		RTE_DMA_LOG(ERR,
-			"Device %d destination port type invalid", dev_id);
+
+	if (conf->domain.type == RTE_DMA_INTER_OS_DOMAIN &&
+	    !(dev_info.dev_capa & RTE_DMA_CAPA_INTER_OS_DOMAIN)) {
+		RTE_DMA_LOG(ERR, "Device %d does not support inter os domain", dev_id);
+		return -EINVAL;
+	}
+	if (conf->domain.type == RTE_DMA_INTER_PROCESS_DOMAIN &&
+	    !(dev_info.dev_capa & RTE_DMA_CAPA_INTER_PROCESS_DOMAIN)) {
+		RTE_DMA_LOG(ERR, "Device %d does not support inter process domain", dev_id);
 		return -EINVAL;
 	}
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH 0/2] fix dmadev incomplete ABI validation
From: datshan @ 2026-06-29  4:17 UTC (permalink / raw)
  To: thomas; +Cc: dev

From: datshan <datshan@qq.com>

Fix dmadev incomplete ABI validation.

Chengwen Feng (2):
  dmadev: fix incomplete configuration validation
  test/dmadev: add config and vchan validation tests

 app/test/test_dmadev_api.c | 186 ++++++++++++++++++++++++++++++++++---
 lib/dmadev/rte_dmadev.c    | 156 +++++++++++++++++++++----------
 2 files changed, 283 insertions(+), 59 deletions(-)

-- 
2.54.0


^ permalink raw reply

* Re: [PATCH v3] dts: update dts check format script and resolve errors
From: Koushik Bhargav Nimoji @ 2026-06-30 12:57 UTC (permalink / raw)
  To: Patrick Robb; +Cc: luca.vizzarro, dev, abailey, ahassick, lylavoie
In-Reply-To: <CAK6Duxvkpxh8XzwvmMaX2y=Am2ePXD092JwX61H5EizDv5f2Gg@mail.gmail.com>

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

On Mon, Jun 29, 2026 at 6:37 PM Patrick Robb <patrickrobb1997@gmail.com>
wrote:

> In the UNH jenkins repo, please read the jenkinsfile for running the
> dts-check-format script, check which image it is pulling, and check how it
> meets dependencies. I can't remember if the dependencies are met at runtime
> or build time, or even if it uses poetry or not. So, there is a risk that
> the checks in CI could continue to run with older dependency versions even
> after this patch hits main. Let me know if you have questions.
>

According to the check format jenkinsfile in the UNH jenkins repo, the
dependencies are resolved using poetry. As the patch updates the
pyproject.toml and poetry.lock files, the updated tool versions should
reflect in CI as well.


> On Thu, Jun 25, 2026 at 1:22 PM Koushik Bhargav Nimoji <
> knimoji@iol.unh.edu> wrote:
>
>>
>>
>> +Tar_modes: TypeAlias = Literal["w:gz", "w:bz2", "w:xz", "w:tar"]
>> +
>>
>
> Should this be tar_modes (snake case)?
>

Tar_modes is of type TypeAlias, which is a user-defined type. Keeping it
uppercase matches the naming convention for type aliases.


>>  def expand_range(range_str: str) -> list[int]:
>>      """Process `range_str` into a list of integers.
>> @@ -154,7 +156,11 @@ def extension(self) -> str:
>>          For other compression formats, the extension will be in the
>> format
>>          'tar.{compression format}'.
>>          """
>> -        return f"{self.value}" if self == self.none else
>> f"{type(self).none.value}.{self.value}"
>> +        return (
>> +            f"{self.value}"
>> +            if self == self.none
>> +            else f"{TarCompressionFormat.none.value}.{self.value}"
>> +        )
>>
>>
>>  def convert_to_list_of_string(value: Any | list[Any]) -> list[str]:
>> @@ -207,7 +213,8 @@ def filter_func(tarinfo: tarfile.TarInfo) ->
>> tarfile.TarInfo | None:
>>          return None
>>
>>      target_tarball_path =
>> dir_path.with_suffix(f".{compress_format.extension}")
>> -    with tarfile.open(target_tarball_path, f"w:{compress_format.value}")
>> as tar:
>> +    tarball_mode = cast(Tar_modes, f"w:{compress_format.value}")
>> +    with tarfile.open(target_tarball_path, tarball_mode) as tar:
>>
>
> Have you completed a testrun which flexes create_tarball(), i.e. running a
> DTS testrun which copies over a normal DPDK dir (instead of defining a
> tarball in test_run.yaml you define a normal dpdk dir source) to the SUT,
> i.e. it actually has to create the tarball?
>
>
>>          tar.add(dir_path, arcname=dir_path.name,
>> filter=create_filter_function(exclude))
>>
>>
I have tested create_tarball(), with DTS copying over a dpdk tree from the
DTS host. The dpdk tree was properly compressed into a tarball, copied over
to the SUT node, and unpacked on the SUT node before continuing DTS
execution.

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

^ permalink raw reply

* [PATCH] net/dpaa2: drop the fake software VLAN strip offload
From: Maxime Leroy @ 2026-06-30 12:49 UTC (permalink / raw)
  To: dev; +Cc: hemant.agrawal, sachin.saxena, stephen, mb, Maxime Leroy

RTE_ETH_RX_OFFLOAD_VLAN_STRIP is advertised, but no hardware VLAN strip
backs it: when enabled, the Rx burst calls rte_vlan_strip() on every
frame, a software op masquerading as a hardware offload.

It saves a forwarding application nothing: the datapath reads the L2
header anyway to classify or strip. The offload does not remove that
read, it relocates it into the driver Rx burst, where it is far more
expensive.

The cost is a matter of timing. rte_vlan_strip() reaches the L2 header
through rte_pktmbuf_mtod(), which dereferences mbuf->buf_addr. On a
freshly recycled buffer that mbuf cacheline is cold. eth_fd_to_mbuf()
has just written other fields of it (data_off, ol_flags), but buf_addr
is a persistent field it does not rewrite. A write does not stall: it
posts to the store buffer while the line fills in the background, and
the rewritten fields are forwarded straight from there. buf_addr has
nothing to forward, so it must be read from the line, whose fill is
still in flight, and the read stalls. The ethertype read that follows,
on the cold payload line, stalls again. Read later by the application,
when the fill has completed, the same read hits. The offload just
performs it at the worst possible moment.

Measured on a single-core port-to-port forwarding test over two 10G
ports (one core at 2 GHz, 64-byte untagged frames):

  - throughput 4.22 -> 5.00 Mpps (+18 percent)
  - IPC 0.93 -> 1.25: the cost was memory stall, not compute
  - L3/DRAM-bound L2 refills 319M -> 200M over 10s (-37 percent)

perf confirms it: with the offload, the buf_addr load (the cold mbuf
field) and the payload load account for about 84 percent of the Rx
burst's L2 refills; removing it, those vanish and only the inherent DQRR
dequeue misses remain.

Stop advertising VLAN_STRIP and remove the rte_vlan_strip() calls from
every Rx path. This is a behavioural change: the tag is left in the
frame, so an application must strip it itself, on the L2 header it
already reads.

Signed-off-by: Maxime Leroy <maxime@leroys.fr>
Acked-by: Morten Brørup <mb@smartsharesystems.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
---
 doc/guides/rel_notes/release_26_07.rst | 3 +++
 drivers/net/dpaa2/dpaa2_ethdev.c       | 1 -
 drivers/net/dpaa2/dpaa2_rxtx.c         | 9 ---------
 3 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 9c724e7cc5..c40d3d73a2 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -152,6 +152,9 @@ New Features
 
   * Added inner RSS level support for tunnelled traffic.
   * Added RSS RETA query and update support.
+  * Removed the software VLAN strip offload: ``RTE_ETH_RX_OFFLOAD_VLAN_STRIP``
+    is no longer advertised, as no hardware strip backs it. An application
+    that needs the tag removed must now strip it itself.
 
 * **Updated PCAP ethernet driver.**
 
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index 56682717cf..a68404ee5e 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -45,7 +45,6 @@ static uint64_t dev_rx_offloads_sup =
 		RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
 		RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
 		RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM |
-		RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
 		RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
 		RTE_ETH_RX_OFFLOAD_TIMESTAMP;
 
diff --git a/drivers/net/dpaa2/dpaa2_rxtx.c b/drivers/net/dpaa2/dpaa2_rxtx.c
index b316e23e87..884cea43c9 100644
--- a/drivers/net/dpaa2/dpaa2_rxtx.c
+++ b/drivers/net/dpaa2/dpaa2_rxtx.c
@@ -890,10 +890,6 @@ dpaa2_dev_prefetch_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		}
 #endif
 
-		if (eth_data->dev_conf.rxmode.offloads &
-				RTE_ETH_RX_OFFLOAD_VLAN_STRIP)
-			rte_vlan_strip(bufs[num_rx]);
-
 		dq_storage++;
 		num_rx++;
 	} while (pending);
@@ -1100,11 +1096,6 @@ dpaa2_dev_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		}
 #endif
 
-		if (eth_data->dev_conf.rxmode.offloads &
-				RTE_ETH_RX_OFFLOAD_VLAN_STRIP) {
-			rte_vlan_strip(bufs[num_rx]);
-		}
-
 			dq_storage++;
 			num_rx++;
 			num_pulled++;
-- 
2.43.0


^ permalink raw reply related

* RE: [PATCH v6 0/9] bpf: JIT related bug fixes
From: Konstantin Ananyev @ 2026-06-30 12:45 UTC (permalink / raw)
  To: Stephen Hemminger, dev@dpdk.org
In-Reply-To: <20260625173231.216074-1-stephen@networkplumber.org>



> While implementing JIT for packet capture ran into several issues:
>   1. x86 JIT had a pre-existing bug which would crash.
>   2. The arm64 JIT was missing the packet-access instructions, found
>      previously [1].
>   3. Shift counts were not masked to the operand width as RFC 9669
>      requires: undefined behavior in the interpreter and an encoding
>      failure in the arm64 JIT.
>   4. Tests related to JIT were not being run or were missing coverage.
> 
> Fixed all of these. Patches are ordered with the most urgent fix (the
> x86 crash) first, each fix followed by the test that exercises it. The
> arm64 packet-load support is kept ahead of the "check JIT was generated"
> patch so the series bisects cleanly on arm64.
> 
> The arm64 epilogue branch fix (patch 6) was originally posted by
> Christophe Fontaine [1]; that series stalled, so it is carried here with
> his authorship.
> 
> [1] https://inbox.dpdk.org/dev/20260319114500.9757-2-cfontain@redhat.com/
> 
> v6:
>  - address Marat's review ARM64 JIT of LD IND instructions
>    need to handle offsets outside of 32 bit range.
> 
> 
> Christophe Fontaine (1):
>   bpf/arm64: fix offset type to allow a negative jump
> 
> Stephen Hemminger (8):
>   bpf/x86: fix JIT encoding of fixed-width immediates
>   test/bpf: add JSET test with small immediate
>   bpf: mask shift count in interpreter per RFC 9669
>   bpf/arm64: mask shift count per RFC 9669
>   test/bpf: add test for large shift
>   bpf/arm64: add BPF_ABS/BPF_IND packet load support
>   test/bpf: check that JIT was generated
>   test/bpf: check that bpf_convert can be JIT'd
> 
>  app/test/test_bpf.c     | 320 +++++++++++++++++++++++++++++++---------
>  lib/bpf/bpf_exec.c      |  31 ++--
>  lib/bpf/bpf_jit_arm64.c | 185 ++++++++++++++++++++++-
>  lib/bpf/bpf_jit_x86.c   |   6 +-
>  lib/bpf/meson.build     |   2 +
>  5 files changed, 456 insertions(+), 88 deletions(-)
> 
> --

Series-Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>

> 2.53.0


^ permalink raw reply

* [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic
From: Maxime Leroy @ 2026-06-30 12:38 UTC (permalink / raw)
  To: dev; +Cc: hemant.agrawal, sachin.saxena, Maxime Leroy

When RTE_ETH_RSS_LEVEL_INNERMOST is requested, the IP key extracts use
the innermost header index (HDR_INDEX_LAST). The hardware only resolves
that index when several IP headers are stacked: for a non-tunnelled
frame, which carries a single IP header, the extraction returns nothing.
The RSS hash is then constant and all such frames are steered to a
single Rx queue.

Always also extract the outer IP (header index 0), which the hardware
resolves for any frame. Non-tunnelled frames are thus hashed on their
only IP header, while tunnelled frames keep being hashed on their inner
IP.

This is a deliberate tradeoff: the ethdev API defines
RTE_ETH_RSS_LEVEL_INNERMOST as hashing the innermost header only, but the
hardware cannot do that without breaking RSS for plain traffic. As a
consequence, two tunnelled flows with the same inner header but
different outer IPs may hash to different queues. This limitation is
documented in the dpaa2 guide.

Alternatives considered (feedback welcome, hence RFC):

- Hash both outer and inner only under RTE_ETH_RSS_LEVEL_PMD_DEFAULT and
  keep INNERMOST strictly inner-only. The ethdev API leaves the default
  level to the PMD, so this stays API-compliant; it changes the default
  hash for tunnelled traffic.

- Add a generic RTE_ETH_RSS_LEVEL_OUTER_INNER value to the ethdev API so
  applications can request hashing on both encapsulation levels
  explicitly, instead of overloading INNERMOST. This needs an ethdev API
  change and agreement from other PMDs.

Fixes: 32f701671d2f ("net/dpaa2: support inner RSS level for tunnelled traffic")
Signed-off-by: Maxime Leroy <maxime@leroys.fr>
---
 doc/guides/nics/dpaa2.rst              |  6 +++
 drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 64 +++++++++++---------------
 2 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/doc/guides/nics/dpaa2.rst b/doc/guides/nics/dpaa2.rst
index 2d70bd0ab9..b7b68f0cd5 100644
--- a/doc/guides/nics/dpaa2.rst
+++ b/doc/guides/nics/dpaa2.rst
@@ -558,6 +558,12 @@ Other Limitations
 
 - RSS hash key cannot be modified.
 - RSS RETA cannot be configured.
+- Under ``RTE_ETH_RSS_LEVEL_INNERMOST``, the IP hash also covers the
+  outermost IP, not only the innermost one. The hardware extracts no IP
+  at the innermost index for non-tunnelled frames, so the outer IP is
+  added to keep RSS working on plain traffic. As a result, tunnelled
+  flows with the same inner header but different outer IPs may be
+  distributed to different queues.
 
 .. _dptmapi:
 
diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c
index 07f4a3d414..b002dba171 100644
--- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c
+++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c
@@ -398,48 +398,38 @@ dpaa2_distset_to_dpkg_profile_cfg(
 			case RTE_ETH_RSS_IPV6:
 			case RTE_ETH_RSS_FRAG_IPV6:
 			case RTE_ETH_RSS_NONFRAG_IPV6_OTHER:
-			case RTE_ETH_RSS_IPV6_EX:
+			case RTE_ETH_RSS_IPV6_EX: {
+				static const uint32_t ip_fields[] = {
+					NH_FLD_IP_SRC, NH_FLD_IP_DST,
+					NH_FLD_IP_PROTO };
+				static const uint8_t ip_hdr_index[] = {
+					0, DPAA2_DIST_HDR_INDEX_LAST };
+				unsigned int n_hdr, f, h;
 
 				if (l3_configured)
 					break;
 				l3_configured = 1;
 
-				kg_cfg->extracts[i].extract.from_hdr.prot =
-					NET_PROT_IP;
-				kg_cfg->extracts[i].extract.from_hdr.hdr_index =
-					hdr_index;
-				kg_cfg->extracts[i].extract.from_hdr.field =
-					NH_FLD_IP_SRC;
-				kg_cfg->extracts[i].type =
-					DPKG_EXTRACT_FROM_HDR;
-				kg_cfg->extracts[i].extract.from_hdr.type =
-					DPKG_FULL_FIELD;
-				i++;
-
-				kg_cfg->extracts[i].extract.from_hdr.prot =
-					NET_PROT_IP;
-				kg_cfg->extracts[i].extract.from_hdr.hdr_index =
-					hdr_index;
-				kg_cfg->extracts[i].extract.from_hdr.field =
-					NH_FLD_IP_DST;
-				kg_cfg->extracts[i].type =
-					DPKG_EXTRACT_FROM_HDR;
-				kg_cfg->extracts[i].extract.from_hdr.type =
-					DPKG_FULL_FIELD;
-				i++;
-
-				kg_cfg->extracts[i].extract.from_hdr.prot =
-					NET_PROT_IP;
-				kg_cfg->extracts[i].extract.from_hdr.hdr_index =
-					hdr_index;
-				kg_cfg->extracts[i].extract.from_hdr.field =
-					NH_FLD_IP_PROTO;
-				kg_cfg->extracts[i].type =
-					DPKG_EXTRACT_FROM_HDR;
-				kg_cfg->extracts[i].extract.from_hdr.type =
-					DPKG_FULL_FIELD;
-				i++;
-			break;
+				/* outer IP always; inner IP too for INNERMOST */
+				n_hdr = (hdr_index == DPAA2_DIST_HDR_INDEX_LAST) ?
+					2 : 1;
+
+				for (h = 0; h < n_hdr; h++)
+					for (f = 0; f < RTE_DIM(ip_fields); f++) {
+						kg_cfg->extracts[i].extract.from_hdr.prot =
+							NET_PROT_IP;
+						kg_cfg->extracts[i].extract.from_hdr.hdr_index =
+							ip_hdr_index[h];
+						kg_cfg->extracts[i].extract.from_hdr.field =
+							ip_fields[f];
+						kg_cfg->extracts[i].type =
+							DPKG_EXTRACT_FROM_HDR;
+						kg_cfg->extracts[i].extract.from_hdr.type =
+							DPKG_FULL_FIELD;
+						i++;
+					}
+				break;
+			}
 
 			case RTE_ETH_RSS_NONFRAG_IPV4_TCP:
 			case RTE_ETH_RSS_NONFRAG_IPV6_TCP:
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 6/6] app/testpmd: add pinned external-buffer Rx pool command
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260630120657.1046588-1-dawid.wesierski@intel.com>

Add the 'create pinned-rxpool <seg-idx> <count> <elt-size>' testpmd
command to demonstrate zero-copy header/payload split receive using
pinned external-buffer mempools (RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF).

Motivation: the DPDK buffer-split offload (RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT)
with two Rx segments allows an application to direct the NIC to place
the protocol header and the payload into separate mbufs. Combining it
with a pinned external-buffer pool for the payload segment lets the NIC
DMA the payload directly into application-owned hugepage memory without
any extra copy or new ethdev API.

This is the mechanism needed by streaming applications such as the
Media Transport Library (MTL) for SMPTE ST 2110-21 video reception,
where 1260-byte RTP payload chunks must land zero-copy in pre-allocated
per-frame video buffers. The existing rte_pktmbuf_pool_create_extbuf()
API covers this use case; no new callback or out-of-tree PMD hook is
required.

The command allocates a hugepage region via rte_zmalloc_socket(),
creates a pinned pool over it with rte_pktmbuf_pool_create_extbuf(),
and registers the pool with testpmd's pool index so that
rx_queue_setup() automatically selects it for the configured split
segment. The complete workflow and a worked video-streaming example are
documented in doc/guides/testpmd_app_ug/testpmd_funcs.rst.

Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
Signed-off-by: Marek Kasiewicz <marek.kasiewicz@intel.com>
---
 app/test-pmd/cmdline.c                      | 123 ++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  82 +++++++++++++
 2 files changed, 205 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 3c39e27aa8..83ea6d2cd2 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -371,6 +371,11 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"inner-ipv6-tcp|inner-ipv4-udp|inner-ipv6-udp|"
 			"inner-ipv4-sctp|inner-ipv6-sctp\n\n"
 
+			"create pinned-rxpool (seg-idx) (count) (elt-size)\n"
+			"    Create a pinned external-buffer Rx mempool for"
+			" buffer-split segment <seg-idx>. Payloads DMA directly"
+			" into application-owned hugepage memory without copy.\n\n"
+
 			"set txpkts (x[,y]*)\n"
 			"    Set the length of each segment of TXONLY"
 			" and optionally CSUM packets.\n\n"
@@ -4483,6 +4488,123 @@ static cmdline_parse_inst_t cmd_set_rxhdrs = {
 	},
 };
 
+/* *** CREATE PINNED EXTERNAL BUFFER POOL FOR RX SPLIT SEGMENT *** */
+struct cmd_create_pinned_rxpool_result {
+	cmdline_fixed_string_t create;
+	cmdline_fixed_string_t pinned_rxpool;
+	uint16_t seg_idx;
+	uint32_t count;
+	uint16_t elt_size;
+};
+
+static void
+cmd_create_pinned_rxpool_parsed(void *parsed_result,
+				__rte_unused struct cmdline *cl,
+				__rte_unused void *data)
+{
+	struct cmd_create_pinned_rxpool_result *res = parsed_result;
+	char pool_name[RTE_MEMPOOL_NAMESIZE];
+	struct rte_pktmbuf_extmem ext_mem;
+	struct rte_mempool *mp;
+	unsigned int socket_id;
+	size_t mem_size;
+	void *frames;
+
+	if (res->seg_idx >= MAX_SEGS_BUFFER_SPLIT) {
+		fprintf(stderr, "seg-idx must be less than %u\n",
+			MAX_SEGS_BUFFER_SPLIT);
+		return;
+	}
+
+	socket_id = (num_sockets > 0) ? (unsigned int)socket_ids[0] : 0;
+	mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name),
+			    res->seg_idx);
+
+	if (mbuf_pool_find(socket_id, res->seg_idx) != NULL) {
+		fprintf(stderr,
+			"Pool '%s' already exists; stop/close port before recreating\n",
+			pool_name);
+		return;
+	}
+
+	mem_size = (size_t)res->count * res->elt_size;
+	frames = rte_zmalloc_socket("pinned_rxpool_mem", mem_size,
+				    RTE_CACHE_LINE_SIZE, socket_id);
+	if (frames == NULL) {
+		fprintf(stderr,
+			"Failed to allocate %zu bytes for pinned pool\n",
+			mem_size);
+		return;
+	}
+
+	ext_mem.buf_ptr  = frames;
+	ext_mem.buf_iova = rte_malloc_virt2iova(frames);
+	if (ext_mem.buf_iova == RTE_BAD_IOVA) {
+		fprintf(stderr,
+			"No IOVA mapping for pinned pool (VFIO/IOMMU required)\n");
+		rte_free(frames);
+		return;
+	}
+	ext_mem.buf_len  = mem_size;
+	ext_mem.elt_size = res->elt_size;
+
+	mp = rte_pktmbuf_pool_create_extbuf(pool_name, res->count,
+					    0, 0, res->elt_size,
+					    socket_id, &ext_mem, 1);
+	if (mp == NULL) {
+		fprintf(stderr, "Failed to create pinned pool '%s': %s\n",
+			pool_name, rte_strerror(rte_errno));
+		rte_free(frames);
+		return;
+	}
+
+	/* Register with testpmd so rx_queue_setup() uses this pool for
+	 * segment <seg_idx> when buffer-split is configured.
+	 */
+	mbuf_data_size[res->seg_idx] = res->elt_size;
+	if ((uint32_t)(res->seg_idx + 1) > mbuf_data_size_n)
+		mbuf_data_size_n = res->seg_idx + 1;
+
+	printf("Created pinned ext-buf pool '%s':\n"
+	       "  socket=%u seg-idx=%u count=%u elt-size=%u "
+	       "mem=%p iova=0x%" PRIx64 "\n",
+	       pool_name, socket_id, res->seg_idx, res->count,
+	       res->elt_size, frames, ext_mem.buf_iova);
+}
+
+static cmdline_parse_token_string_t cmd_create_pinned_rxpool_create =
+	TOKEN_STRING_INITIALIZER(struct cmd_create_pinned_rxpool_result,
+				 create, "create");
+static cmdline_parse_token_string_t cmd_create_pinned_rxpool_kw =
+	TOKEN_STRING_INITIALIZER(struct cmd_create_pinned_rxpool_result,
+				 pinned_rxpool, "pinned-rxpool");
+static cmdline_parse_token_num_t cmd_create_pinned_rxpool_seg_idx =
+	TOKEN_NUM_INITIALIZER(struct cmd_create_pinned_rxpool_result,
+			      seg_idx, RTE_UINT16);
+static cmdline_parse_token_num_t cmd_create_pinned_rxpool_count =
+	TOKEN_NUM_INITIALIZER(struct cmd_create_pinned_rxpool_result,
+			      count, RTE_UINT32);
+static cmdline_parse_token_num_t cmd_create_pinned_rxpool_elt_size =
+	TOKEN_NUM_INITIALIZER(struct cmd_create_pinned_rxpool_result,
+			      elt_size, RTE_UINT16);
+
+static cmdline_parse_inst_t cmd_create_pinned_rxpool = {
+	.f = cmd_create_pinned_rxpool_parsed,
+	.data = NULL,
+	.help_str = "create pinned-rxpool <seg-idx> <count> <elt-size>: "
+		    "create a pinned external-buffer Rx mempool for split "
+		    "segment <seg-idx>; payloads DMA directly into hugepage "
+		    "memory owned by the application without an extra copy",
+	.tokens = {
+		(void *)&cmd_create_pinned_rxpool_create,
+		(void *)&cmd_create_pinned_rxpool_kw,
+		(void *)&cmd_create_pinned_rxpool_seg_idx,
+		(void *)&cmd_create_pinned_rxpool_count,
+		(void *)&cmd_create_pinned_rxpool_elt_size,
+		NULL,
+	},
+};
+
 /* *** SET SEGMENT LENGTHS OF TXONLY PACKETS *** */
 
 struct cmd_set_txpkts_result {
@@ -14238,6 +14360,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
 	&cmd_set_rxoffs,
 	&cmd_set_rxpkts,
 	&cmd_set_rxhdrs,
+	&cmd_create_pinned_rxpool,
 	&cmd_set_txflows,
 	&cmd_set_txpkts,
 	&cmd_set_txsplit,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index f0f2b0758b..0ca263cc4e 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -867,6 +867,88 @@ Where eth[,ipv4]* represents a CSV list of values, without white space.
 If the list of offsets is shorter than the list of segments,
 zero offsets will be used for the remaining segments.
 
+create pinned-rxpool
+~~~~~~~~~~~~~~~~~~~~
+
+Create a pinned external-buffer Rx mempool for a buffer-split payload
+segment. Each mbuf in the pool is permanently bound to a fixed slot in
+a contiguous hugepage region allocated by testpmd. When the NIC
+performs a buffer-split receive, the payload DMA-writes directly into
+that hugepage memory without any extra copy from a normal mbuf.
+
+.. code-block:: none
+
+   testpmd> create pinned-rxpool (seg-idx) (count) (elt-size)
+
+Where:
+
+seg-idx
+   Index of the Rx split segment that will use the pinned pool.
+   0 is the header segment (usually left as the default pool);
+   1 is the first payload segment and is the typical target.
+
+count
+   Number of mbufs in the pool. Should be at least as large as the
+   number of Rx descriptors on all queues using this pool, plus a
+   safety margin (e.g. ``nb_rxd * nb_rxq * 2``).
+
+elt-size
+   Size of each pool element in bytes. This is the total slot stride,
+   including ``RTE_PKTMBUF_HEADROOM`` (default 128 B). For example,
+   to hold 1260-byte video payloads (SMPTE ST 2110-21 BPM size) with
+   a standard headroom, set ``elt-size`` to 1388 (= 128 + 1260).
+
+The pool is named according to testpmd's internal convention so that
+``rx_queue_setup()`` automatically selects it for segment ``seg-idx``
+when ``RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT`` is enabled.
+
+.. note::
+
+   VFIO or another IOMMU driver is required so that hugepage memory
+   has a valid IOVA. The backing hugepage allocation is not freed when
+   the port is stopped or the pool is re-created; restart testpmd to
+   reclaim it.
+
+**Example — zero-copy header/payload split for video streaming**
+
+This example mirrors the use case in the Media Transport Library (MTL)
+for SMPTE ST 2110-21 video reception. Headers land in the default
+pool; 1260-byte video payloads DMA directly into a pinned hugepage
+region without any copy. The pool holds enough slots for 4 K
+descriptors on 4 queues with headroom:
+
+.. code-block:: console
+
+   # Start testpmd with a default header pool (segment 0)
+   dpdk-testpmd -a 0000:31:00.0,enable-rx-timestamp=0 \
+     --mbuf-size=256 -- -i --rxq=4 --txq=4 --rxd=4096
+
+   # Inside testpmd:
+
+   # 1. Create the pinned payload pool for segment 1 (4*4096 mbufs,
+   #    1388 bytes each: 128 B headroom + 1260 B payload)
+   testpmd> create pinned-rxpool 1 32768 1388
+
+   # 2. Configure buffer split: segment 0 = UDP+lower headers,
+   #    segment 1 = payload (length 0 means "rest of packet")
+   testpmd> set rxhdrs ipv4-udp
+   testpmd> set rxpkts 0,0
+
+   # 3. Enable buffer split on the port
+   testpmd> port config 0 rx_offload buffer_split on
+
+   # 4. Restart the queues so the new configuration takes effect
+   testpmd> stop
+   testpmd> port stop 0
+   testpmd> port start 0
+   testpmd> start
+
+After this sequence, each received UDP packet is split by the NIC:
+the header mbuf (chain head) comes from the default pool, and the
+payload mbuf (chain next) has its ``buf_addr`` pointing into the
+pinned hugepage region owned by the application — no copy, no
+callback, no new ethdev API.
+
 set txpkts
 ~~~~~~~~~~
 
-- 
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 v3 5/6] net/iavf: disable runtime queue setup capability
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260630120657.1046588-1-dawid.wesierski@intel.com>

From: Marek Kasiewicz <marek.kasiewicz@intel.com>

Remove the advertisement of RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP
and RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP capabilities from the
iavf VF driver.

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.

By not advertising these capabilities, all queues are configured at
port start and remain stable throughout the port lifecycle.

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

diff --git a/doc/guides/nics/intel_vf.rst b/doc/guides/nics/intel_vf.rst
index e010f852cf..86878330f2 100644
--- a/doc/guides/nics/intel_vf.rst
+++ b/doc/guides/nics/intel_vf.rst
@@ -131,6 +131,15 @@ IAVF PMD parameters
     * ``segment``: Check number of mbuf segments does not exceed HW limits.
     * ``offload``: Check for use of an unsupported offload flag.
 
+``no_runtime_queue_setup``
+    Runtime (post-start) Rx/Tx queue setup can race with the hardware Tx rate
+    limiter on E810 VFs and corrupt queue state.
+    It is advertised by default.
+    Applications that pace queues through the traffic manager can opt out
+    of advertising the runtime queue setup capability
+    by setting ``no_runtime_queue_setup`` to 1,
+    for example, ``-a 18:01.0,no_runtime_queue_setup=1``.
+
 
 HW-Specific Notes For IAVF
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index db8c4d5b16..d3e9dc6cf4 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -135,6 +135,8 @@ New Features
 
   * Added support for transmitting LLDP packets based on mbuf packet type.
   * Implemented AVX2 context descriptor transmit paths.
+  * Added ``no_runtime_queue_setup`` devarg to disable runtime queue setup
+    on devices that pace queues through the traffic manager.
 
 * **Updated Intel ice driver.**
 
diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
index 4444602a30..146f02ea13 100644
--- a/drivers/net/intel/iavf/iavf.h
+++ b/drivers/net/intel/iavf/iavf.h
@@ -326,6 +326,7 @@ struct iavf_devargs {
 	int no_poll_on_link_down;
 	uint64_t mbuf_check;
 	int enable_ptype_lldp;
+	int no_runtime_queue_setup;
 };
 
 struct iavf_security_ctx;
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index ec1ad02826..be733f9edf 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -46,6 +46,7 @@
 #define IAVF_NO_POLL_ON_LINK_DOWN_ARG "no-poll-on-link-down"
 #define IAVF_MBUF_CHECK_ARG       "mbuf_check"
 #define IAVF_ENABLE_PTYPE_LLDP_ARG "enable_ptype_lldp"
+#define IAVF_NO_RUNTIME_QUEUE_SETUP_ARG "no_runtime_queue_setup"
 uint64_t iavf_timestamp_dynflag;
 int iavf_timestamp_dynfield_offset = -1;
 int rte_pmd_iavf_tx_lldp_dynfield_offset = -1;
@@ -59,6 +60,7 @@ static const char * const iavf_valid_args[] = {
 	IAVF_NO_POLL_ON_LINK_DOWN_ARG,
 	IAVF_MBUF_CHECK_ARG,
 	IAVF_ENABLE_PTYPE_LLDP_ARG,
+	IAVF_NO_RUNTIME_QUEUE_SETUP_ARG,
 	NULL
 };
 
@@ -1160,9 +1162,15 @@ 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. Applications that pace queues via
+	 * the traffic manager can opt out with no_runtime_queue_setup=1.
+	 */
+	if (!adapter->devargs.no_runtime_queue_setup)
+		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 |
@@ -2533,6 +2541,11 @@ static int iavf_parse_devargs(struct rte_eth_dev *dev)
 	if (ret)
 		goto bail;
 
+	ret = rte_kvargs_process(kvlist, IAVF_NO_RUNTIME_QUEUE_SETUP_ARG,
+				 &parse_bool, &ad->devargs.no_runtime_queue_setup);
+	if (ret)
+		goto bail;
+
 bail:
 	rte_kvargs_free(kvlist);
 	return ret;
@@ -3619,7 +3632,8 @@ bool is_iavf_supported(struct rte_eth_dev *dev)
 RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
-RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf"
+			      IAVF_NO_RUNTIME_QUEUE_SETUP_ARG "=<0|1>");
 RTE_LOG_REGISTER_SUFFIX(iavf_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(iavf_logtype_driver, driver, NOTICE);
 #ifdef RTE_ETHDEV_DEBUG_RX
-- 
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 v3 4/6] net/ice: timestamp all received packets when PTP is enabled
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260630120657.1046588-1-dawid.wesierski@intel.com>

From: Marek Kasiewicz <marek.kasiewicz@intel.com>

When PTP is enabled on the ICE PMD, hardware RX timestamps are only
applied to packets classified as IEEE 1588 (Ethertype 0x88F7). This
prevents applications from obtaining hardware timestamps on regular
UDP/IP traffic.

Remove the TIMESYNC packet type filter so that all received packets
get hardware timestamps when PTP is enabled. This is required for
time-sensitive networking applications that need per-packet arrival
timing on media traffic, such as ST 2110-21 receiver compliance
monitoring.

The change affects all three RX paths: scan, scattered, and single
packet receive functions.

Signed-off-by: Marek Kasiewicz <marek.kasiewicz@intel.com>
Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
---
 drivers/net/intel/ice/ice_rxtx.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/net/intel/ice/ice_rxtx.c b/drivers/net/intel/ice/ice_rxtx.c
index c4b5454c53..8d709125f7 100644
--- a/drivers/net/intel/ice/ice_rxtx.c
+++ b/drivers/net/intel/ice/ice_rxtx.c
@@ -2023,8 +2023,7 @@ ice_rx_scan_hw_ring(struct ci_rx_queue *rxq)
 				pkt_flags |= rxq->ts_flag;
 			}
 
-			if (ad->ptp_ena && ((mb->packet_type &
-			    RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC)) {
+			if (ad->ptp_ena) {
 				rxq->time_high =
 				   rte_le_to_cpu_32(rxdp[j].wb.flex_ts.ts_high);
 				mb->timesync = rxq->queue_id;
@@ -2390,8 +2389,7 @@ ice_recv_scattered_pkts(void *rx_queue,
 			pkt_flags |= rxq->ts_flag;
 		}
 
-		if (ad->ptp_ena && ((first_seg->packet_type & RTE_PTYPE_L2_MASK)
-		    == RTE_PTYPE_L2_ETHER_TIMESYNC)) {
+		if (ad->ptp_ena) {
 			rxq->time_high =
 			   rte_le_to_cpu_32(rxd.wb.flex_ts.ts_high);
 			first_seg->timesync = rxq->queue_id;
@@ -2881,8 +2879,7 @@ ice_recv_pkts(void *rx_queue,
 			pkt_flags |= rxq->ts_flag;
 		}
 
-		if (ad->ptp_ena && ((rxm->packet_type & RTE_PTYPE_L2_MASK) ==
-		    RTE_PTYPE_L2_ETHER_TIMESYNC)) {
+		if (ad->ptp_ena) {
 			rxq->time_high =
 			   rte_le_to_cpu_32(rxd.wb.flex_ts.ts_high);
 			rxm->timesync = rxq->queue_id;
-- 
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 v3 3/6] net/ice: add scheduler rate-limiter burst size devarg
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260630120657.1046588-1-dawid.wesierski@intel.com>

From: Marek Kasiewicz <marek.kasiewicz@intel.com>

The E810 Tx scheduler uses a token bucket algorithm where the burst
size controls the maximum bytes sent in a single burst before the
rate limiter throttles. The hardware default of 15 KB allows
micro-bursts of ~10 max-size frames, which violates tight
inter-packet spacing requirements in time-sensitive networking
applications such as SMPTE ST 2110-21 narrow-sender compliance.

Add a "rl_burst_size" device argument that lets the application lower
the scheduler rate-limiter burst size (for example to 2 KB) to force
near-constant-rate output matching the configured shaper profile.
The burst size is a global scheduler resource, so the override is
applied once at probe time and only when the user explicitly requests
it; the hardware default is left unchanged otherwise.

Signed-off-by: Marek Kasiewicz <marek.kasiewicz@intel.com>
Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
---
 doc/guides/nics/ice.rst                | 12 +++++++
 doc/guides/rel_notes/release_26_07.rst |  5 +++
 drivers/net/intel/ice/ice_ethdev.c     | 46 ++++++++++++++++++++++++++
 drivers/net/intel/ice/ice_ethdev.h     |  1 +
 4 files changed, 64 insertions(+)

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8251416918..187c7e821f 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -158,6 +158,18 @@ Runtime Configuration
 
     -a 80:00.0,source-prune=1
 
+- ``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 value is clamped to the hardware-allowed
+  range. A value of ``0`` (the default) keeps the hardware default.
+
+  For example::
+
+    -a 80:00.0,rl_burst_size=2048
+
 - ``Protocol extraction for per queue``
 
   Configure the RX queues to do protocol extraction into mbuf for protocol
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 5d7aa8d1bf..db8c4d5b16 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -136,6 +136,11 @@ New Features
   * Added support for transmitting LLDP packets based on mbuf packet type.
   * Implemented AVX2 context descriptor transmit paths.
 
+* **Updated Intel ice driver.**
+
+  * Added ``rl_burst_size`` devarg to configure the scheduler rate-limiter
+    burst size, reducing Tx latency jitter for time-sensitive traffic.
+
 * **Updated NVIDIA mlx5 ethernet driver.**
 
   * Added support for selective Rx in scalar SPRQ Rx path.
diff --git a/drivers/net/intel/ice/ice_ethdev.c b/drivers/net/intel/ice/ice_ethdev.c
index ad9c49b339..465cf07383 100644
--- a/drivers/net/intel/ice/ice_ethdev.c
+++ b/drivers/net/intel/ice/ice_ethdev.c
@@ -41,6 +41,7 @@
 #define ICE_DDP_FILENAME_ARG      "ddp_pkg_file"
 #define ICE_DDP_LOAD_SCHED_ARG    "ddp_load_sched_topo"
 #define ICE_TM_LEVELS_ARG         "tm_sched_levels"
+#define ICE_RL_BURST_SIZE_ARG     "rl_burst_size"
 #define ICE_SOURCE_PRUNE_ARG      "source-prune"
 #define ICE_LINK_STATE_ON_CLOSE   "link_state_on_close"
 
@@ -59,6 +60,7 @@ static const char * const ice_valid_args[] = {
 	ICE_DDP_FILENAME_ARG,
 	ICE_DDP_LOAD_SCHED_ARG,
 	ICE_TM_LEVELS_ARG,
+	ICE_RL_BURST_SIZE_ARG,
 	ICE_SOURCE_PRUNE_ARG,
 	ICE_LINK_STATE_ON_CLOSE,
 	NULL
@@ -2147,6 +2149,29 @@ parse_u64(const char *key, const char *value, void *args)
 	return 0;
 }
 
+static int
+parse_u32(const char *key, const char *value, void *args)
+{
+	uint32_t *num = args;
+	unsigned long tmp;
+	char *endptr;
+
+	errno = 0;
+	tmp = strtoul(value, &endptr, 0);
+	if (errno != 0 || endptr == value || *endptr != '\0') {
+		PMD_DRV_LOG(WARNING, "%s: \"%s\" is not a valid u32", key, value);
+		return -1;
+	}
+	if (tmp > UINT32_MAX) {
+		PMD_DRV_LOG(WARNING, "%s: value \"%s\" is out of range", key, value);
+		return -1;
+	}
+
+	*num = (uint32_t)tmp;
+
+	return 0;
+}
+
 static int
 parse_tx_sched_levels(const char *key, const char *value, void *args)
 {
@@ -2448,6 +2473,11 @@ static int ice_parse_devargs(struct rte_eth_dev *dev)
 	if (ret)
 		goto bail;
 
+	ret = rte_kvargs_process(kvlist, ICE_RL_BURST_SIZE_ARG,
+				 &parse_u32, &ad->devargs.rl_burst_size);
+	if (ret)
+		goto bail;
+
 	ret = rte_kvargs_process(kvlist, ICE_SOURCE_PRUNE_ARG,
 				 &parse_bool, &ad->devargs.source_prune);
 	if (ret)
@@ -2662,6 +2692,21 @@ ice_dev_init(struct rte_eth_dev *dev)
 		return -EINVAL;
 	}
 
+	/*
+	 * Override the hardware default scheduler rate-limiter burst size only
+	 * when the user explicitly requests it. A smaller burst reduces Tx
+	 * latency jitter for time-sensitive traffic at the cost of throughput,
+	 * so it must not change for every port. ice_cfg_rl_burst_size()
+	 * validates the value against the hardware-allowed range.
+	 */
+	if (ad->devargs.rl_burst_size != 0 &&
+	    ice_cfg_rl_burst_size(hw, ad->devargs.rl_burst_size) != 0) {
+		PMD_INIT_LOG(ERR, "Invalid rl_burst_size %u bytes",
+			     ad->devargs.rl_burst_size);
+		ice_deinit_hw(hw);
+		return -EINVAL;
+	}
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	use_dsn = false;
 	dsn = 0;
@@ -7713,6 +7758,7 @@ RTE_PMD_REGISTER_PARAM_STRING(net_ice,
 			      ICE_DDP_FILENAME_ARG "=</path/to/file>"
 			      ICE_DDP_LOAD_SCHED_ARG "=<0|1>"
 			      ICE_TM_LEVELS_ARG "=<N>"
+			      ICE_RL_BURST_SIZE_ARG "=<N>"
 			      ICE_SOURCE_PRUNE_ARG "=<0|1>"
 			      ICE_RX_LOW_LATENCY_ARG "=<0|1>"
 			      ICE_LINK_STATE_ON_CLOSE "=<down|up|initial>");
diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
index 20e8a13fe9..0a9d75b9cd 100644
--- a/drivers/net/intel/ice/ice_ethdev.h
+++ b/drivers/net/intel/ice/ice_ethdev.h
@@ -631,6 +631,7 @@ struct ice_devargs {
 	uint8_t ddp_load_sched;
 	uint8_t tm_exposed_levels;
 	uint8_t source_prune;
+	uint32_t rl_burst_size;
 	int link_state_on_close;
 	int xtr_field_offs;
 	uint8_t xtr_flag_offs[PROTO_XTR_MAX];
-- 
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 v3 2/6] net/iavf: allow runtime queue rate limit configuration
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260630120657.1046588-1-dawid.wesierski@intel.com>

From: Marek Kasiewicz <marek.kasiewicz@intel.com>

Allow per-queue bandwidth rate limiting to be configured without
stopping the port when only a single TC node and single QoS element
are involved. This enables dynamic session management where individual
queue pacing rates can be changed while other queues continue
transmitting.

Also fix the queue ID assignment in the bandwidth configuration to
use the actual TM node ID rather than a sequential counter index, and
only mark the TM hierarchy as committed when the port is stopped to
permit subsequent reconfiguration.

Signed-off-by: Marek Kasiewicz <marek.kasiewicz@intel.com>
Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
---
 drivers/net/intel/iavf/iavf_tm.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/net/intel/iavf/iavf_tm.c b/drivers/net/intel/iavf/iavf_tm.c
index 1cf7bfb106..e3492ec491 100644
--- a/drivers/net/intel/iavf/iavf_tm.c
+++ b/drivers/net/intel/iavf/iavf_tm.c
@@ -804,19 +804,25 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,
 	int index = 0, node_committed = 0;
 	int i, ret_val = IAVF_SUCCESS;
 
-	/* check if port is stopped */
-	if (adapter->stopped != 1) {
-		PMD_DRV_LOG(ERR, "Please stop port first");
-		ret_val = IAVF_ERR_NOT_READY;
-		goto err;
-	}
-
 	if (!(vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_QOS)) {
 		PMD_DRV_LOG(ERR, "VF queue tc mapping is not supported");
 		ret_val = IAVF_NOT_SUPPORTED;
 		goto fail_clear;
 	}
 
+	/*
+	 * Allow reconfiguration on a running port only when a single queue is
+	 * involved (single TC node and single QoS element); otherwise the port
+	 * must be stopped first. qos_cap is valid here because the
+	 * VIRTCHNL_VF_OFFLOAD_QOS capability was checked above.
+	 */
+	if ((vf->tm_conf.nb_tc_node != 1 || vf->qos_cap->num_elem != 1) &&
+	    adapter->stopped != 1) {
+		PMD_DRV_LOG(ERR, "Please stop port first");
+		ret_val = IAVF_ERR_NOT_READY;
+		goto err;
+	}
+
 	/* check if all TC nodes are set with VF vsi */
 	if (vf->tm_conf.nb_tc_node != vf->qos_cap->num_elem) {
 		PMD_DRV_LOG(ERR, "Does not set VF vsi nodes to all TCs");
@@ -856,7 +862,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,
 		q_tc_mapping->tc[tm_node->tc].req.queue_count++;
 
 		if (tm_node->shaper_profile) {
-			q_bw->cfg[node_committed].queue_id = node_committed;
+			q_bw->cfg[node_committed].queue_id = tm_node->id;
 			q_bw->cfg[node_committed].shaper.peak =
 			tm_node->shaper_profile->profile.peak.rate /
 			1000 * IAVF_BITS_PER_BYTE;
@@ -900,7 +906,8 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,
 		goto fail_clear;
 
 	vf->qtc_map = qtc_map;
-	vf->tm_conf.committed = true;
+	if (adapter->stopped == 1)
+		vf->tm_conf.committed = true;
 	return ret_val;
 
 fail_clear:
-- 
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 v3 1/6] net/iavf: increase max ring descriptors to hardware limit
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260630120657.1046588-1-dawid.wesierski@intel.com>

From: Marek Kasiewicz <marek.kasiewicz@intel.com>

The Intel E810 hardware supports up to 8160 (8K - 32) descriptors per
TX/RX ring, but IAVF_MAX_RING_DESC caps it at 4096. Applications that
need deep descriptor rings for hardware rate-limited pacing (e.g.,
ST2110 video with thousands of packets per frame) cannot queue enough
packets before the pacing epoch begins.

Increase IAVF_MAX_RING_DESC to the hardware maximum of 8160 to allow
full utilization of the ring depth on E810 VFs.

Signed-off-by: Marek Kasiewicz <marek.kasiewicz@intel.com>
Signed-off-by: Dawid Wesierski <dawid.wesierski@intel.com>
---
 .mailmap                           | 2 ++
 drivers/net/intel/iavf/iavf_rxtx.h | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/.mailmap b/.mailmap
index 4001e5fb0e..d7b175de2a 100644
--- a/.mailmap
+++ b/.mailmap
@@ -366,6 +366,7 @@ David Zeng <zengxhsh@cn.ibm.com>
 Davide Caratti <dcaratti@redhat.com>
 Dawid Gorecki <dgr@semihalf.com>
 Dawid Jurczak <dawid_jurek@vp.pl>
+Dawid Wesierski <dawid.wesierski@intel.com>
 Dawid Zielinski <dawid.zielinski@intel.com>
 Dawid Łukwiński <dawid.lukwinski@intel.com>
 Daxue Gao <daxuex.gao@intel.com>
@@ -1014,6 +1015,7 @@ Marcin Wilk <marcin.wilk@caviumnetworks.com>
 Marcin Wojtas <mw@semihalf.com>
 Marcin Zapolski <marcinx.a.zapolski@intel.com>
 Marco Varlese <mvarlese@suse.de>
+Marek Kasiewicz <marek.kasiewicz@intel.com>
 Marek Mical <marekx.mical@intel.com>
 Marek Zalfresso-jundzillo <marekx.zalfresso-jundzillo@intel.com>
 Maria Lingemark <maria.lingemark@ericsson.com>
diff --git a/drivers/net/intel/iavf/iavf_rxtx.h b/drivers/net/intel/iavf/iavf_rxtx.h
index 8449236d4d..22ea415f44 100644
--- a/drivers/net/intel/iavf/iavf_rxtx.h
+++ b/drivers/net/intel/iavf/iavf_rxtx.h
@@ -16,7 +16,7 @@
 /* In QLEN must be whole number of 32 descriptors. */
 #define IAVF_ALIGN_RING_DESC      32
 #define IAVF_MIN_RING_DESC        64
-#define IAVF_MAX_RING_DESC        4096
+#define IAVF_MAX_RING_DESC        (8192 - 32)
 #define IAVF_DMA_MEM_ALIGN        4096
 /* Base address of the HW descriptor ring should be 128B aligned. */
 #define IAVF_RING_BASE_ALIGN      128
-- 
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 v3 0/6] Intel network drivers enhancements
From: Dawid Wesierski @ 2026-06-30 12:06 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, marek.kasiewicz, Dawid Wesierski
In-Reply-To: <20260618144442.312844-8-dawid.wesierski@intel.com>

This series collects Intel E810 iavf and ice driver enhancements developed
for the Media Transport Library (MTL) to support high-performance SMPTE
ST 2110 media streaming workflows.

The "new code" in this series (specifically the testpmd enhancement in
patch 6) demonstrates how the standard DPDK buffer-split offload can be
orchestrated with pinned external-buffer mempools
(RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF) to achieve this. By pinning mbufs to
contiguous hugepages, the NIC DMAs RTP payloads directly into application-
owned memory. This eliminates the need for the header-split.

Documentation and a concrete configuration example for this workflow are
included in the testpmd user guide (patch 6/6). The new 'create pinned-rxpool'
command serves as both a test vehicle and a reference implementation for
integrators.

In this series:
- iavf maximum ring descriptor count to raised 4096 (HW limit).
- iavf queue rate limit enabled reconfiguration at runtime.
- Added opt-in "rl_burst_size" ice devarg for tighter packet spacing (jitter reduction).
- Enabled PTP timestamping for all packets on ice.
- Added opt-in "no_runtime_queue_setup" iavf devarg to restore strict
  initialization semantics when required.

- Dropped the ethdev and net/intel "header-split mbuf callback" API
- Replaced the out-of-tree approach with a testpmd demonstration (patch 6)
  of the standard, upstream-preferred pinned-external-buffer workflow.
- Fixed iavf error propagation and committed-state logic (Stephen Hemminger).
- Converted the ice scheduler burst reduction and iavf runtime-config
  disabling into opt-in devargs to preserve default behavior.
- Updated documentation, commit messages, and .mailmap.

Dawid Wesierski (1):
  app/testpmd: add pinned external-buffer Rx pool command

Marek Kasiewicz (5):
  net/iavf: increase max ring descriptors to hardware limit
  net/iavf: allow runtime queue rate limit configuration
  net/ice: add scheduler rate-limiter burst size devarg
  net/ice: timestamp all received packets when PTP is enabled
  net/iavf: disable runtime queue setup capability

 .mailmap                                    |   2 +
 app/test-pmd/cmdline.c                      | 123 ++++++++++++++++++++
 doc/guides/nics/ice.rst                     |  12 ++
 doc/guides/nics/intel_vf.rst                |   9 ++
 doc/guides/rel_notes/release_26_07.rst      |   7 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  82 +++++++++++++
 drivers/net/intel/iavf/iavf.h               |   1 +
 drivers/net/intel/iavf/iavf_ethdev.c        |  22 +++-
 drivers/net/intel/iavf/iavf_rxtx.h          |   2 +-
 drivers/net/intel/iavf/iavf_tm.c            |  25 ++--
 drivers/net/intel/ice/ice_ethdev.c          |  46 ++++++++
 drivers/net/intel/ice/ice_ethdev.h          |   1 +
 drivers/net/intel/ice/ice_rxtx.c            |   9 +-
 13 files changed, 321 insertions(+), 20 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

* [PATCH v4 4/4] net/txgbe: add VF support for Amber-Lite 40G NIC
From: Zaiyu Wang @ 2026-06-30 11:16 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260630111608.22196-1-zaiyuwang@trustnetic.com>

VF support for the 40G NIC was previously omitted; only the 25G VF was
added. Now add 40G VF support based on the existing 25G VF implementation,
with no major changes but only device ID adaptation.

Also, drop the redundant mac type check in txgbe_check_mac_link_vf(),
as the function now handles all VF types uniformly.

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/rel_notes/release_26_07.rst | 2 ++
 drivers/net/txgbe/base/txgbe_devids.h  | 2 ++
 drivers/net/txgbe/base/txgbe_hw.c      | 7 +++++++
 drivers/net/txgbe/base/txgbe_regs.h    | 7 +++++--
 drivers/net/txgbe/base/txgbe_type.h    | 1 +
 drivers/net/txgbe/base/txgbe_vf.c      | 6 +++---
 drivers/net/txgbe/txgbe_ethdev.c       | 1 +
 drivers/net/txgbe/txgbe_ethdev_vf.c    | 2 ++
 8 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 46935ba872..95b536a5ef 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -195,6 +195,8 @@ New Features
     down. When the PF comes back, the VF triggers an
     ``RTE_ETH_EVENT_INTR_RESET`` event so the application can reset the VF
     and resume normal packet Rx/Tx.
+  * Added VF support for the Amber-Lite 40G NIC variant, with new device
+    IDs ``0x503f`` and ``0x513f``.
 
 
 Removed Items
diff --git a/drivers/net/txgbe/base/txgbe_devids.h b/drivers/net/txgbe/base/txgbe_devids.h
index b7133c7d54..f5454ffbb1 100644
--- a/drivers/net/txgbe/base/txgbe_devids.h
+++ b/drivers/net/txgbe/base/txgbe_devids.h
@@ -28,6 +28,8 @@
 #define TXGBE_DEV_ID_AML_VF			0x5001
 #define TXGBE_DEV_ID_AML5024_VF			0x5024
 #define TXGBE_DEV_ID_AML5124_VF			0x5124
+#define TXGBE_DEV_ID_AML503F_VF			0x503f
+#define TXGBE_DEV_ID_AML513F_VF			0x513f
 
 /*
  * Subsystem IDs
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 0f3db3a1ad..21465d68ff 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -2543,6 +2543,7 @@ s32 txgbe_init_shared_code(struct txgbe_hw *hw)
 		break;
 	case txgbe_mac_sp_vf:
 	case txgbe_mac_aml_vf:
+	case txgbe_mac_aml40_vf:
 		status = txgbe_init_ops_vf(hw);
 		break;
 	default:
@@ -2573,6 +2574,7 @@ bool txgbe_is_vf(struct txgbe_hw *hw)
 	switch (hw->mac.type) {
 	case txgbe_mac_sp_vf:
 	case txgbe_mac_aml_vf:
+	case txgbe_mac_aml40_vf:
 		return true;
 	default:
 		return false;
@@ -2620,6 +2622,11 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw)
 		hw->phy.media_type = txgbe_media_type_virtual;
 		hw->mac.type = txgbe_mac_aml_vf;
 		break;
+	case TXGBE_DEV_ID_AML503F_VF:
+	case TXGBE_DEV_ID_AML513F_VF:
+		hw->phy.media_type = txgbe_media_type_virtual;
+		hw->mac.type = txgbe_mac_aml40_vf;
+		break;
 	default:
 		err = TXGBE_ERR_DEVICE_NOT_SUPPORTED;
 		DEBUGOUT("Unsupported device id: %x", hw->device_id);
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 95c585a025..5eb92c54b6 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1824,12 +1824,14 @@ txgbe_map_reg(struct txgbe_hw *hw, u32 reg)
 	switch (reg) {
 	case TXGBE_REG_RSSTBL:
 		if (hw->mac.type == txgbe_mac_sp_vf ||
-		    hw->mac.type == txgbe_mac_aml_vf)
+		    hw->mac.type == txgbe_mac_aml_vf ||
+		    hw->mac.type == txgbe_mac_aml40_vf)
 			reg = TXGBE_VFRSSTBL(0);
 		break;
 	case TXGBE_REG_RSSKEY:
 		if (hw->mac.type == txgbe_mac_sp_vf ||
-		    hw->mac.type == txgbe_mac_aml_vf)
+		    hw->mac.type == txgbe_mac_aml_vf ||
+		    hw->mac.type == txgbe_mac_aml40_vf)
 			reg = TXGBE_VFRSSKEY(0);
 		break;
 	default:
@@ -2012,6 +2014,7 @@ static inline void txgbe_flush(struct txgbe_hw *hw)
 		break;
 	case txgbe_mac_sp_vf:
 	case txgbe_mac_aml_vf:
+	case txgbe_mac_aml40_vf:
 		rd32(hw, TXGBE_VFSTATUS);
 		break;
 	default:
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index c73a9ebcb4..3ac4c28fd3 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -171,6 +171,7 @@ enum txgbe_mac_type {
 	txgbe_mac_aml40,
 	txgbe_mac_sp_vf,
 	txgbe_mac_aml_vf,
+	txgbe_mac_aml40_vf,
 	txgbe_num_macs
 };
 
diff --git a/drivers/net/txgbe/base/txgbe_vf.c b/drivers/net/txgbe/base/txgbe_vf.c
index 1a8a20f104..47d9bd16ee 100644
--- a/drivers/net/txgbe/base/txgbe_vf.c
+++ b/drivers/net/txgbe/base/txgbe_vf.c
@@ -134,7 +134,8 @@ s32 txgbe_reset_hw_vf(struct txgbe_hw *hw)
 	}
 
 	/* amlite: bme */
-	if (hw->mac.type == txgbe_mac_aml_vf)
+	if (hw->mac.type == txgbe_mac_aml_vf ||
+	    hw->mac.type == txgbe_mac_aml40_vf)
 		wr32(hw, TXGBE_BME_AML, 0x1);
 
 	if (!timeout)
@@ -493,8 +494,7 @@ s32 txgbe_check_mac_link_vf(struct txgbe_hw *hw, u32 *speed,
 	/* for SFP+ modules and DA cables it can take up to 500usecs
 	 * before the link status is correct
 	 */
-	if ((mac->type == txgbe_mac_sp_vf ||
-	     mac->type == txgbe_mac_aml_vf) && wait_to_complete) {
+	if (wait_to_complete) {
 		if (po32m(hw, TXGBE_VFSTATUS, TXGBE_VFSTATUS_UP,
 			0, NULL, 5, 100))
 			goto out;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index c99734cced..7c39e9f2e8 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -5229,6 +5229,7 @@ txgbe_rss_update(enum txgbe_mac_type mac_type)
 	case txgbe_mac_aml:
 	case txgbe_mac_aml40:
 	case txgbe_mac_aml_vf:
+	case txgbe_mac_aml40_vf:
 		return 1;
 	default:
 		return 0;
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index c57ac57141..341f62bc75 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -77,6 +77,8 @@ static const struct rte_pci_id pci_id_txgbevf_map[] = {
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML_VF) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML5024_VF) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML5124_VF) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML503F_VF) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML513F_VF) },
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
-- 
2.21.0.windows.1


^ permalink raw reply related

* [PATCH v4 2/4] net/txgbe: implement USO support
From: Zaiyu Wang @ 2026-06-30 11:16 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260630111608.22196-1-zaiyuwang@trustnetic.com>

USO (UDP Segmentation Offload), also known as UFO (UDP Fragmentation
Offload), is a hardware offload rarely seen in DPDK. Its implementation
is similar to TSO (TCP Segmentation Offload), so the driver enables
USO based on existing TSO support.

The driver has advertised RTE_ETH_TX_OFFLOAD_UDP_TSO in tx_offload_capa
since its initial integration, but the data path never implemented the
actual segmentation support. This commit fills that gap by enabling USO
in the transmit path, making the advertised capability fully functional.

Note:
USO segments UDP packets, requiring hardware to recalculate both IP
and UDP checksums due to length change. Thus, USO implicitly requires
IP and UDP checksum offloads, same as TSO.

Fixes: 86d8adc7702c ("net/txgbe: support getting device info")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/rel_notes/release_26_07.rst |  7 +++++++
 drivers/net/txgbe/txgbe_rxtx.c         | 13 ++++++++-----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index c5a168fdc9..06cd52b777 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -184,6 +184,13 @@ New Features
     driver's initial integration but the data path was missing; it is now
     functional.
 
+* **Updated Wangxun txgbe driver.**
+
+  * Implemented UDP Segmentation Offload (USO) in the transmit path.
+    The ``RTE_ETH_TX_OFFLOAD_UDP_TSO`` capability was advertised since the
+    driver's initial integration but the data path was missing; it is now
+    functional.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index e2cd9b8841..c4cbdbc2b4 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -58,6 +58,7 @@ static const u64 TXGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
 		RTE_MBUF_F_TX_VLAN |
 		RTE_MBUF_F_TX_L4_MASK |
 		RTE_MBUF_F_TX_TCP_SEG |
+		RTE_MBUF_F_TX_UDP_SEG |
 		RTE_MBUF_F_TX_TUNNEL_MASK |
 		RTE_MBUF_F_TX_OUTER_IP_CKSUM |
 		RTE_MBUF_F_TX_OUTER_UDP_CKSUM |
@@ -367,7 +368,7 @@ txgbe_set_xmit_ctx(struct txgbe_tx_queue *txq,
 	type_tucmd_mlhl |= TXGBE_TXD_PTID(tx_offload.ptid);
 
 	/* check if TCP segmentation required for this packet */
-	if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
 		tx_offload_mask.l2_len |= ~0;
 		tx_offload_mask.l3_len |= ~0;
 		tx_offload_mask.l4_len |= ~0;
@@ -517,7 +518,7 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
 		tmp |= TXGBE_TXD_CC;
 		tmp |= TXGBE_TXD_EIPCS;
 	}
-	if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
 		tmp |= TXGBE_TXD_CC;
 		/* implies IPv4 cksum */
 		if (ol_flags & RTE_MBUF_F_TX_IPV4)
@@ -537,7 +538,7 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
 
 	if (ol_flags & RTE_MBUF_F_TX_VLAN)
 		cmdtype |= TXGBE_TXD_VLE;
-	if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
+	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
 		cmdtype |= TXGBE_TXD_TSE;
 	if (ol_flags & RTE_MBUF_F_TX_MACSEC)
 		cmdtype |= TXGBE_TXD_LINKSEC;
@@ -587,6 +588,8 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
 
 	if (oflags & RTE_MBUF_F_TX_TCP_SEG)
 		ptype |= (tun ? RTE_PTYPE_INNER_L4_TCP : RTE_PTYPE_L4_TCP);
+	else if (oflags & RTE_MBUF_F_TX_UDP_SEG)
+		ptype |= (tun ? RTE_PTYPE_INNER_L4_UDP : RTE_PTYPE_L4_UDP);
 
 	/* Tunnel */
 	switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) {
@@ -1071,7 +1074,7 @@ txgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
 		olinfo_status = 0;
 		if (tx_ol_req) {
-			if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+			if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
 				/* when TSO is on, paylen in descriptor is the
 				 * not the packet len but the tcp payload len
 				 */
@@ -2389,7 +2392,7 @@ txgbe_get_tx_port_offloads(struct rte_eth_dev *dev)
 		RTE_ETH_TX_OFFLOAD_TCP_CKSUM   |
 		RTE_ETH_TX_OFFLOAD_SCTP_CKSUM  |
 		RTE_ETH_TX_OFFLOAD_TCP_TSO     |
-		RTE_ETH_TX_OFFLOAD_UDP_TSO	   |
+		RTE_ETH_TX_OFFLOAD_UDP_TSO     |
 		RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO	|
 		RTE_ETH_TX_OFFLOAD_IP_TNL_TSO	|
 		RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO	|
-- 
2.21.0.windows.1


^ permalink raw reply related

* [PATCH v4 3/4] net/txgbe: add support for VF sensing PF down
From: Zaiyu Wang @ 2026-06-30 11:16 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260630111608.22196-1-zaiyuwang@trustnetic.com>

VFs should continue normal packet Rx/Tx after PF ifconfig down/up.

When mailbox messages lack the TXGBE_VT_MSGTYPE_CTS flag, the PF is
considered down. In this state, the VF reports link down and stops
transmitting. Upon detecting the loss of CTS, the VF sends a reset
request to the PF. If the request succeeds (indicating PF recovery),
the VF triggers an RTE_ETH_EVENT_INTR_RESET event to notify the
application or users to reset the VF.

The write_posted() based VF_RESET request is the only recovery path:
the PF only marks this VF as ready (and starts sending CTS) after it
processes VF_RESET, so this request is required for the VF to recover.
write_posted() may busy-wait for the ACK in the interrupt thread, but
the PF does not send further mailbox messages once it is down, so this
blocking is not continuously triggered.

Additionally, hw->rx_loaded and hw->offset_loaded must be reset when
PF ifconfig down; otherwise, because hardware counter registers are
cleared during PF reset, the VF's software counters will overflow to
0xFFFFFFFF.

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/rel_notes/release_26_07.rst |  5 ++
 drivers/net/txgbe/base/txgbe_type.h    |  1 +
 drivers/net/txgbe/txgbe_ethdev.c       |  4 +-
 drivers/net/txgbe/txgbe_ethdev_vf.c    | 86 ++++++++++++++++++++++----
 4 files changed, 83 insertions(+), 13 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 06cd52b777..46935ba872 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -190,6 +190,11 @@ New Features
     The ``RTE_ETH_TX_OFFLOAD_UDP_TSO`` capability was advertised since the
     driver's initial integration but the data path was missing; it is now
     functional.
+  * Added support for VF sensing PF down. VFs now detect when the PF goes
+    down (via the mailbox ``TXGBE_VT_MSGTYPE_CTS`` flag) and report link
+    down. When the PF comes back, the VF triggers an
+    ``RTE_ETH_EVENT_INTR_RESET`` event so the application can reset the VF
+    and resume normal packet Rx/Tx.
 
 
 Removed Items
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index ede780321f..c73a9ebcb4 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -883,6 +883,7 @@ struct txgbe_hw {
 	rte_atomic32_t swfw_busy;
 	u32 fec_mode;
 	u32 cur_fec_link;
+	RTE_ATOMIC(bool) pf_running;
 };
 
 struct txgbe_backplane_ability {
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0f484dfe91..c99734cced 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3150,7 +3150,9 @@ txgbe_dev_link_update_share(struct rte_eth_dev *dev,
 
 	hw->mac.get_link_status = true;
 
-	if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG)
+	if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG ||
+	    (txgbe_is_vf(hw) && !rte_atomic_load_explicit(&hw->pf_running,
+						rte_memory_order_acquire)))
 		return rte_eth_linkstatus_set(dev, &link);
 
 	/* check if it needs to wait to complete, if lsc interrupt is enabled */
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 7a50c7a855..c57ac57141 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -281,6 +281,8 @@ eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
 	hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
 	hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
 	hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
+	rte_atomic_store_explicit(&hw->pf_running, true,
+				  rte_memory_order_release);
 
 	/* initialize the vfta */
 	memset(shadow_vfta, 0, sizeof(*shadow_vfta));
@@ -1405,10 +1407,21 @@ static s32 txgbevf_get_pf_link_status(struct rte_eth_dev *dev)
 	if (retval)
 		return 0;
 
+	if (!(msgbuf[0] & TXGBE_NOFITY_VF_LINK_STATUS))
+		return 0;
+
 	rte_eth_linkstatus_get(dev, &link);
 
+	if (!rte_atomic_load_explicit(&hw->pf_running,
+				      rte_memory_order_acquire)) {
+		link.link_status =  RTE_ETH_LINK_DOWN;
+		link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+		link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+		return rte_eth_linkstatus_set(dev, &link);
+	}
+
 	link_up = msgbuf[1] & TXGBE_VFSTATUS_UP;
-	link_speed = (msgbuf[1] & 0xFFF0) >> 1;
+	link_speed = (msgbuf[1] & 0x1FFFFE) >> 1;
 
 	if (link_up == link.link_status && link_speed == link.link_speed)
 		return 0;
@@ -1434,10 +1447,23 @@ static s32 txgbevf_get_pf_link_status(struct rte_eth_dev *dev)
 static void txgbevf_check_link_for_intr(struct rte_eth_dev *dev)
 {
 	struct rte_eth_link orig_link, new_link;
+	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
 
 	rte_eth_linkstatus_get(dev, &orig_link);
-	txgbevf_dev_link_update(dev, 0);
-	rte_eth_linkstatus_get(dev, &new_link);
+
+	if (rte_atomic_load_explicit(&hw->pf_running,
+				     rte_memory_order_acquire)) {
+		txgbevf_dev_link_update(dev, 0);
+		rte_eth_linkstatus_get(dev, &new_link);
+	} else {
+		DEBUGOUT("PF ifconfig down, so VF link down");
+		new_link.link_status = RTE_ETH_LINK_DOWN;
+		new_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+		new_link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+		new_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+					  RTE_ETH_LINK_SPEED_FIXED);
+		rte_eth_linkstatus_set(dev, &new_link);
+	}
 
 	PMD_DRV_LOG(INFO, "orig_link: %d, new_link: %d",
 		    orig_link.link_status, new_link.link_status);
@@ -1450,22 +1476,58 @@ static void txgbevf_check_link_for_intr(struct rte_eth_dev *dev)
 static void txgbevf_mbx_process(struct rte_eth_dev *dev)
 {
 	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	u32 msgbuf = 0;
 	u32 in_msg = 0;
 
-	/* peek the message first */
+	/* Peek the message first */
 	in_msg = rd32(hw, TXGBE_VFMBX);
 
-	/* PF reset VF event */
-	if (in_msg & TXGBE_PF_CONTROL_MSG) {
-		if (in_msg & TXGBE_NOFITY_VF_LINK_STATUS) {
-			txgbevf_get_pf_link_status(dev);
-		} else {
-			/* dummy mbx read to ack pf */
-			txgbe_read_mbx(hw, &in_msg, 1, 0);
-			/* check link status if pf ping vf */
+	/* PF control message */
+	if (!(in_msg & TXGBE_PF_CONTROL_MSG))
+		return;
+
+	txgbevf_get_pf_link_status(dev);
+
+	if (!(in_msg & TXGBE_VT_MSGTYPE_CTS)) {
+		/*
+		 * PF is not ready for this VF (e.g. PF ifconfig down).
+		 *
+		 * Send VF_RESET to ask the PF to reconfigure us. The PF only
+		 * marks this VF as ready (and starts sending CTS) after it
+		 * processes VF_RESET, so this request is the only way to
+		 * recover. If write_posted() succeeds the PF is back up and
+		 * we notify the application to reset the VF; otherwise the PF
+		 * is still down, so we mark it down and reset the stats
+		 * baselines (hardware counters are cleared during PF reset).
+		 *
+		 * write_posted() may busy-wait for the ACK in the interrupt
+		 * thread, but the PF does not send further mailbox messages
+		 * once it is down, so this blocking is not continuously
+		 * triggered.
+		 */
+		int err;
+
+		msgbuf = TXGBE_VF_RESET;
+		err = mbx->write_posted(hw, &msgbuf, 1, 0);
+		if (err) {
+			rte_atomic_store_explicit(&hw->pf_running, false,
+						  rte_memory_order_release);
 			txgbevf_check_link_for_intr(dev);
+			hw->rx_loaded = true;
+			hw->offset_loaded = true;
+		} else {
+			rte_atomic_store_explicit(&hw->pf_running, true,
+						  rte_memory_order_release);
+			rte_eth_dev_callback_process(dev,
+					RTE_ETH_EVENT_INTR_RESET, NULL);
 		}
+		return;
 	}
+
+	/* Check link status if pf only ping vf */
+	if (!(in_msg & TXGBE_NOFITY_VF_LINK_STATUS))
+		txgbevf_check_link_for_intr(dev);
 }
 
 static int
-- 
2.21.0.windows.1


^ permalink raw reply related

* [PATCH v4 1/4] net/ngbe: implement USO support
From: Zaiyu Wang @ 2026-06-30 11:16 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260630111608.22196-1-zaiyuwang@trustnetic.com>

USO (UDP Segmentation Offload), also known as UFO (UDP Fragmentation
Offload), is a hardware offload rarely seen in DPDK. Its implementation
is similar to TSO (TCP Segmentation Offload), so the driver enables
USO based on existing TSO support.

The driver has advertised RTE_ETH_TX_OFFLOAD_UDP_TSO in tx_offload_capa
since its initial integration, but the data path never implemented the
actual segmentation support. This commit fills that gap by enabling USO
in the transmit path, making the advertised capability fully functional.

Note:
USO segments UDP packets, requiring hardware to recalculate both IP
and UDP checksums due to length change. Thus, USO implicitly requires
IP and UDP checksum offloads, same as TSO.

Fixes: 9f3206140274 ("net/ngbe: support TSO")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/rel_notes/release_26_07.rst |  7 +++++++
 drivers/net/ngbe/ngbe_rxtx.c           | 13 ++++++++-----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 4ca0a9ac77..c5a168fdc9 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -177,6 +177,13 @@ New Features
   Added AGENTS.md file for AI review
   and supporting scripts to review patches and documentation.
 
+* **Updated Wangxun ngbe driver.**
+
+  * Implemented UDP Segmentation Offload (USO) in the transmit path.
+    The ``RTE_ETH_TX_OFFLOAD_UDP_TSO`` capability was advertised since the
+    driver's initial integration but the data path was missing; it is now
+    functional.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/ngbe/ngbe_rxtx.c b/drivers/net/ngbe/ngbe_rxtx.c
index 91e215694c..a1389de9c0 100644
--- a/drivers/net/ngbe/ngbe_rxtx.c
+++ b/drivers/net/ngbe/ngbe_rxtx.c
@@ -30,6 +30,7 @@ static const u64 NGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
 		RTE_MBUF_F_TX_VLAN |
 		RTE_MBUF_F_TX_L4_MASK |
 		RTE_MBUF_F_TX_TCP_SEG |
+		RTE_MBUF_F_TX_UDP_SEG |
 		NGBE_TX_IEEE1588_TMST);
 
 #define NGBE_TX_OFFLOAD_NOTSUP_MASK \
@@ -317,7 +318,7 @@ ngbe_set_xmit_ctx(struct ngbe_tx_queue *txq,
 	type_tucmd_mlhl |= NGBE_TXD_PTID(tx_offload.ptid);
 
 	/* check if TCP segmentation required for this packet */
-	if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
 		tx_offload_mask.l2_len |= ~0;
 		tx_offload_mask.l3_len |= ~0;
 		tx_offload_mask.l4_len |= ~0;
@@ -427,7 +428,7 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
 		tmp |= NGBE_TXD_CC;
 		tmp |= NGBE_TXD_EIPCS;
 	}
-	if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
 		tmp |= NGBE_TXD_CC;
 		/* implies IPv4 cksum */
 		if (ol_flags & RTE_MBUF_F_TX_IPV4)
@@ -447,7 +448,7 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
 
 	if (ol_flags & RTE_MBUF_F_TX_VLAN)
 		cmdtype |= NGBE_TXD_VLE;
-	if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
+	if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
 		cmdtype |= NGBE_TXD_TSE;
 	return cmdtype;
 }
@@ -483,6 +484,8 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
 
 	if (oflags & RTE_MBUF_F_TX_TCP_SEG)
 		ptype |= RTE_PTYPE_L4_TCP;
+	else if (oflags & RTE_MBUF_F_TX_UDP_SEG)
+		ptype |= RTE_PTYPE_L4_UDP;
 
 	return ptype;
 }
@@ -764,7 +767,7 @@ ngbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
 		olinfo_status = 0;
 		if (tx_ol_req) {
-			if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+			if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
 				/* when TSO is on, paylen in descriptor is the
 				 * not the packet len but the tcp payload len
 				 */
@@ -1991,7 +1994,7 @@ ngbe_get_tx_port_offloads(struct rte_eth_dev *dev)
 		RTE_ETH_TX_OFFLOAD_TCP_CKSUM   |
 		RTE_ETH_TX_OFFLOAD_SCTP_CKSUM  |
 		RTE_ETH_TX_OFFLOAD_TCP_TSO     |
-		RTE_ETH_TX_OFFLOAD_UDP_TSO	   |
+		RTE_ETH_TX_OFFLOAD_UDP_TSO     |
 		RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
 
 	if (hw->is_pf)
-- 
2.21.0.windows.1


^ permalink raw reply related

* [PATCH v4 0/4] Wangxun fixes and new features
From: Zaiyu Wang @ 2026-06-30 11:16 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang
In-Reply-To: <20260617105959.10764-1-zaiyuwang@trustnetic.om>

This patchset introduces three new features and critical fixes for our
recent release cycle.

Patches 1-2 add support for UDP Segmentation Offload (USO) to improve
large-packet transmission performance for UDP workloads.

Patch 3 enables VFs to sense PF ifconfig down/up events, allowing
better fault tolerance and fast recovery in virtualized environments.

Patch 4 adds the missing VF support for the Amber-Lite 40G NICs, which
was previously omitted in the initial integration.
---
v4:
- Patches 1-4: add release notes
- Patch 3: consume the mailbox message before checking the CTS flag;
           separate CTS validation from link status processing by
	   returning early after handling a CTS-less control message;
	   make pf_running atomic.
---
v3:
- Patches 1-2: change from new feature to bug fix.
- Patch 3: fix link status update in txgbevf_get_pf_link_status();
           extend speed mask from 0xFFF0 to 0x1FFFFE for 40G speed;
           reduce msgbuf array to a single u32 variable;
           correct commit message.
- Patch 4: add a cleanup note in commit message for dropping the
           redundant mac type check in txgbevf_check_mac_link_vf();
	   remove a redundant blank line in txgbe_reset_hw_vf().
---
v2:
- Rebased on top of commit 72fdcb7bd19d to resolve conflict in
  drivers/net/txgbe/base/txgbe_type.h.
- No code changes compared to v1.
---

Zaiyu Wang (4):
  net/ngbe: implement USO support
  net/txgbe: implement USO support
  net/txgbe: add support for VF sensing PF down
  net/txgbe: add VF support for Amber-Lite 40G NIC

 doc/guides/rel_notes/release_26_07.rst | 21 ++++++
 drivers/net/ngbe/ngbe_rxtx.c           | 13 ++--
 drivers/net/txgbe/base/txgbe_devids.h  |  2 +
 drivers/net/txgbe/base/txgbe_hw.c      |  7 ++
 drivers/net/txgbe/base/txgbe_regs.h    |  7 +-
 drivers/net/txgbe/base/txgbe_type.h    |  2 +
 drivers/net/txgbe/base/txgbe_vf.c      |  6 +-
 drivers/net/txgbe/txgbe_ethdev.c       |  5 +-
 drivers/net/txgbe/txgbe_ethdev_vf.c    | 88 ++++++++++++++++++++++----
 drivers/net/txgbe/txgbe_rxtx.c         | 13 ++--
 10 files changed, 136 insertions(+), 28 deletions(-)

-- 
2.21.0.windows.1


^ permalink raw reply

* [PATCH v2] net/mlx5: fallback to verbs for Tx memory allocation if devx unsupported
From: banoth.saikumar @ 2026-06-30 10:23 UTC (permalink / raw)
  To: dsosnowski, viacheslavo, bingz; +Cc: dev, stable, Banoth Saikumar
In-Reply-To: <'20260323113403.1984-1-banoth.saikumar@oracle.com'>

From: Banoth Saikumar <banoth.saikumar@oracle.com>

Previously, the mlx5 PMD attempted to allocate consecutive Tx memory
using DevX without checking whether the NIC actually supported DevX.
This led to allocation failures on legacy or unsupported NICs.

This patch adds a fallback mechanism: if DevX is not available, the PMD
skips DevX-based allocation and allows the verbs path to handle memory
allocation and registration. This improves compatibility with older
NICs and ensures Tx queue setup proceeds correctly.

Fixes: bbfab2eb2528 ("net/mlx5: allocate and release unique
resources for Tx queues")
Cc: stable@dpdk.org

Signed-off-by: Banoth Saikumar <banoth.saikumar@oracle.com>
---
v2:
- Use mlx5_devx_obj_ops_en() instead of checking config.devx directly.

 drivers/net/mlx5/mlx5_trigger.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index 6c6f228afd..721fa5e2c8 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -1161,7 +1161,7 @@ static int mlx5_dev_allocate_consec_tx_mem(struct rte_eth_dev *dev)
 	void *umem_buf = NULL;
 
 	/* Legacy per queue allocation, do nothing here. */
-	if (priv->sh->config.txq_mem_algn == 0)
+	if (priv->sh->config.txq_mem_algn == 0 || !mlx5_devx_obj_ops_en(priv->sh))
 		return 0;
 	alignment = (size_t)1 << priv->sh->config.txq_mem_algn;
 	total_size = priv->consec_tx_mem.sq_total_size + priv->consec_tx_mem.cq_total_size;
-- 
2.47.3


^ permalink raw reply related

* [v1] crypto/qat: fix IPsec MB header include for ARM
From: Emma Finn @ 2026-06-30 10:01 UTC (permalink / raw)
  To: Kai Ji, Emma Finn; +Cc: dev, Thomas Monjalon

Update the header file to always include the platform-specific
IPsec MB header.

Fixes: 03c475d609eb ("crypto/qat: require IPsec MB for HMAC precomputes")

Reported-by: Thomas Monjalon <thomas@monjalon.net>
Signed-off-by: Emma Finn <emma.finn@intel.com>
---
 drivers/crypto/qat/qat_sym_session.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/qat/qat_sym_session.h b/drivers/crypto/qat/qat_sym_session.h
index 0c7b9cc6cf..b18673a1f7 100644
--- a/drivers/crypto/qat/qat_sym_session.h
+++ b/drivers/crypto/qat/qat_sym_session.h
@@ -14,11 +14,11 @@
 #include "icp_qat_fw.h"
 #include "icp_qat_fw_la.h"
 
-#ifndef RTE_QAT_OPENSSL
-#ifndef RTE_ARCH_ARM
+#ifdef RTE_ARCH_ARM
+#include <ipsec-mb.h>
+#else
 #include <intel-ipsec-mb.h>
 #endif
-#endif
 
 /*
  * Key Modifier (KM) value used in KASUMI algorithm in F9 mode to XOR
-- 
2.43.0


^ permalink raw reply related


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