DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Pravin Pathak <pravinpathakdev@gmail.com>
To: dev@dpdk.org
Cc: jerinj@marvell.com, mike.ximing.chen@intel.com,
	bruce.richardson@intel.com, thomas@monjalon.net,
	david.marchand@redhat.com, nipun.gupta@amd.com,
	chenbox@nvidia.com, tirthendu.sarkar@intel.com,
	Pravin Pathak <pravin.pathak.dev@gmail.com>
Subject: [PATCH v1 6/8] event/slb: add self-test and documentation
Date: Fri,  6 Nov 2026 20:30:08 -0500	[thread overview]
Message-ID: <20261107013011.2443138-7-pravinpathakdev@gmail.com> (raw)
In-Reply-To: <20261107013011.2443138-1-pravinpathakdev@gmail.com>

From: Pravin Pathak <pravin.pathak.dev@gmail.com>

Add driver self-test coverage and documentation for the Software
Load Balancer PMD.

The self-test verifies parallel queues, atomic queue flow ordering,
ordered queues with forward sequence restoration, single-link queues,
and device stop/restart event draining. Register the self-test in
app/test as a fast test.

Add PMD user guide, feature matrix table, release notes entry for
DPDK 26.11, and update MAINTAINERS.

Signed-off-by: Pravin Pathak <pravin.pathak.dev@gmail.com>
---
 MAINTAINERS                           |   2 +
 app/test/test_eventdev.c              |   7 +
 doc/guides/eventdevs/features/slb.ini |  26 ++
 doc/guides/eventdevs/index.rst        |   1 +
 doc/guides/eventdevs/slb.rst          |  68 ++++
 drivers/event/slb/meson.build         |   1 +
 drivers/event/slb/slb_evdev.c         |   1 +
 drivers/event/slb/slb_evdev.h         |   4 +
 drivers/event/slb/slb_selftest.c      | 522 ++++++++++++++++++++++++++
 9 files changed, 632 insertions(+)
 create mode 100644 doc/guides/eventdevs/features/slb.ini
 create mode 100644 doc/guides/eventdevs/slb.rst
 create mode 100644 drivers/event/slb/slb_selftest.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 89ea53695a..bc46e3e8b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1536,6 +1536,8 @@ F: doc/guides/eventdevs/dsw.rst
 Software Load Balancer (SLB) Eventdev PMD
 M: Pravin Pathak <pravin.pathak.dev@gmail.com>
 F: drivers/event/slb/
+F: doc/guides/eventdevs/slb.rst
+F: doc/guides/eventdevs/features/slb.ini
 
 Software OPDL Eventdev PMD
 M: Liang Ma <liangma@liangbit.com>
diff --git a/app/test/test_eventdev.c b/app/test/test_eventdev.c
index 1241da38cb..58ec440674 100644
--- a/app/test/test_eventdev.c
+++ b/app/test/test_eventdev.c
@@ -1527,12 +1527,19 @@ test_eventdev_selftest_cn20k(void)
 	return test_eventdev_selftest_impl("event_cn20k", "");
 }
 
+static int
+test_eventdev_selftest_slb(void)
+{
+	return test_eventdev_selftest_impl("event_slb", "");
+}
+
 #endif /* !RTE_EXEC_ENV_WINDOWS */
 
 REGISTER_FAST_TEST(eventdev_common_autotest, NOHUGE_OK, ASAN_OK, test_eventdev_common);
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 REGISTER_FAST_TEST(eventdev_selftest_sw, NOHUGE_OK, ASAN_OK, test_eventdev_selftest_sw);
+REGISTER_FAST_TEST(eventdev_selftest_slb, NOHUGE_OK, ASAN_OK, test_eventdev_selftest_slb);
 REGISTER_DRIVER_TEST(eventdev_selftest_octeontx, test_eventdev_selftest_octeontx);
 REGISTER_DRIVER_TEST(eventdev_selftest_dpaa2, test_eventdev_selftest_dpaa2);
 REGISTER_DRIVER_TEST(eventdev_selftest_dlb2, test_eventdev_selftest_dlb2);
diff --git a/doc/guides/eventdevs/features/slb.ini b/doc/guides/eventdevs/features/slb.ini
new file mode 100644
index 0000000000..0364840bc9
--- /dev/null
+++ b/doc/guides/eventdevs/features/slb.ini
@@ -0,0 +1,26 @@
+;
+; Supported features of the 'software load balancer' (event_slb) eventdev driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Scheduling Features]
+atomic_scheduling          = Y
+ordered_scheduling         = Y
+parallel_scheduling        = Y
+distributed_sched          = Y
+burst_mode                 = Y
+implicit_release_disable   = Y
+nonseq_mode                = Y
+runtime_port_link          = Y
+multiple_queue_port        = Y
+carry_flow_id              = Y
+maintenance_free           = Y
+independent_enq            = Y
+
+[Eth Rx adapter Features]
+
+[Eth Tx adapter Features]
+
+[Crypto adapter Features]
+
+[Timer adapter Features]
diff --git a/doc/guides/eventdevs/index.rst b/doc/guides/eventdevs/index.rst
index 69a5ebf812..fdaf846503 100644
--- a/doc/guides/eventdevs/index.rst
+++ b/doc/guides/eventdevs/index.rst
@@ -20,3 +20,4 @@ application through the eventdev API.
     sw
     octeontx
     opdl
+    slb
diff --git a/doc/guides/eventdevs/slb.rst b/doc/guides/eventdevs/slb.rst
new file mode 100644
index 0000000000..d319b94920
--- /dev/null
+++ b/doc/guides/eventdevs/slb.rst
@@ -0,0 +1,68 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2026 Pravin Pathak <pravin.pathak.dev@gmail.com>
+
+Software Load Balancer (SLB) Eventdev Driver
+============================================
+
+The Software Load Balancer (SLB) event device is a poll-mode eventdev driver
+which distributes events among multiple worker ports and cores without requiring
+dedicated scheduling service cores or hardware coprocessors.
+
+Features
+--------
+
+Queues
+~~~~~~
+
+* **Parallel**: Lock-free multi-producer, multi-consumer ring-based queue allowing
+  concurrent dequeues across all serving worker ports.
+* **Atomic**: Flow-pinned scheduling guaranteeing strict per-flow packet ordering.
+  Includes dynamic load tracking and automatic flow migration to rebalance overloaded
+  ports while preserving in-flight sequence integrity.
+* **Ordered**: Ticket-based sequence tracking and reorder buffer providing end-to-end
+  packet order restoration across parallel processing workers.
+* **Single-Link**: Dedicated direct queue mapping from a producer port to a single
+  consumer port using optimized single-consumer rings.
+
+Ports & Scheduling Capabilities
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* **Distributed Scheduling**: No dedicated service core required; scheduling work is
+  performed inline during enqueue and dequeue operations.
+* **Prefix Sum Burst Enqueue**: Interleaved multi-queue bursts are grouped and scattered
+  via prefix-sum offsets, dispatching single batched bursts to queue rings to eliminate
+  atomic Compare-And-Swap contention on multi-producer rings.
+* **Dynamic Flow Migration**: Atomic queues monitor port dequeue loads and migrate
+  eligible victim flows from overloaded ports to underloaded ports with cooling cycles.
+* **Credit Pool Management**: Centralized event credit pool with per-port credit caching
+  to enforce device-wide in-flight event limits (``max_num_events``).
+* **Runtime Port Linking**: Supports dynamic linking and unlinking of ports and queues
+  both when stopped and at runtime.
+* **Maintenance Free**: Operates without requiring periodic maintenance calls
+  (``RTE_EVENT_DEV_CAP_MAINTENANCE_FREE``).
+
+Configuration and Options
+-------------------------
+
+The SLB event device is a virtual device (vdev) and can be initialized from the
+application code or from the EAL command line:
+
+* From application code:
+
+  .. code-block:: c
+
+      rte_vdev_init("event_slb0", NULL);
+
+* From EAL command-line options:
+
+  .. code-block:: console
+
+      ./your_dpdk_application --vdev="event_slb0"
+
+Limitations
+-----------
+
+* **Flow Hash Table Size**: Atomic queues use an internal flow mapping table
+  dimensioned to 2048 concurrent active flows per queue (``SLB_ATOMIC_FLOWS``).
+* **Maximum Ports and Queues**: Configured for up to 64 ports (``SLB_MAX_PORTS``)
+  and 64 queues (``SLB_MAX_QUEUES``).
diff --git a/drivers/event/slb/meson.build b/drivers/event/slb/meson.build
index d698a58f16..6caf48720f 100644
--- a/drivers/event/slb/meson.build
+++ b/drivers/event/slb/meson.build
@@ -11,6 +11,7 @@ sources = files(
         'slb_evdev.c',
         'slb_event.c',
         'slb_xstats.c',
+        'slb_selftest.c',
 )
 
 deps += ['bus_vdev', 'ring']
diff --git a/drivers/event/slb/slb_evdev.c b/drivers/event/slb/slb_evdev.c
index 04a2aba165..c86b934b03 100644
--- a/drivers/event/slb/slb_evdev.c
+++ b/drivers/event/slb/slb_evdev.c
@@ -758,6 +758,7 @@ static struct eventdev_ops slb_evdev_ops = {
 	.xstats_get = slb_xstats_get,
 	.xstats_get_names = slb_xstats_get_names,
 	.xstats_get_by_name = slb_xstats_get_by_name,
+	.dev_selftest = test_slb_eventdev,
 };
 
 static int
diff --git a/drivers/event/slb/slb_evdev.h b/drivers/event/slb/slb_evdev.h
index 17f3154efa..f727a1b83c 100644
--- a/drivers/event/slb/slb_evdev.h
+++ b/drivers/event/slb/slb_evdev.h
@@ -242,6 +242,8 @@ int slb_xstats_get(const struct rte_eventdev *dev,
 uint64_t slb_xstats_get_by_name(const struct rte_eventdev *dev,
 				const char *name, uint64_t *id);
 
+int test_slb_eventdev(void);
+
 static inline struct slb_evdev *
 slb_pmd_priv(const struct rte_eventdev *eventdev)
 {
@@ -250,6 +252,8 @@ slb_pmd_priv(const struct rte_eventdev *eventdev)
 
 extern int event_slb_logtype;
 #define RTE_LOGTYPE_EVENT_SLB event_slb_logtype
+#define SLB_LOG_LINE(level, ...) \
+	RTE_LOG_LINE(level, EVENT_SLB, __VA_ARGS__)
 #define SLB_LOG_DP_LINE(level, fmt, ...)				\
 	RTE_LOG_DP_LINE(level, EVENT_SLB, "%s() line %u: " fmt,		\
 		   __func__, __LINE__, ## __VA_ARGS__)
diff --git a/drivers/event/slb/slb_selftest.c b/drivers/event/slb/slb_selftest.c
new file mode 100644
index 0000000000..4a072b811b
--- /dev/null
+++ b/drivers/event/slb/slb_selftest.c
@@ -0,0 +1,522 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Pravin Pathak <pravin.pathak.dev@gmail.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include <rte_bus_vdev.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_eventdev.h>
+
+#include "slb_evdev.h"
+
+#define NUM_PORTS 4
+#define NUM_QUEUES 4
+#define PORT_PROD 0
+#define PORT_W1   1
+#define PORT_W2   2
+#define PORT_CONS 3
+
+#define Q_PARALLEL 0
+#define Q_ATOMIC   1
+#define Q_ORDERED  2
+#define Q_SINGLE   3
+
+#define NUM_FLOWS 4
+#define EVENTS_PER_FLOW 16
+#define TOTAL_ATOMIC_EVENTS (NUM_FLOWS * EVENTS_PER_FLOW)
+
+static int g_dev_id = -1;
+
+static int
+init_selftest_device(void)
+{
+	struct rte_event_dev_config dev_conf = {
+		.dequeue_timeout_ns = 0,
+		.nb_event_queues = NUM_QUEUES,
+		.nb_event_ports = NUM_PORTS,
+		.nb_events_limit = 4096,
+		.nb_event_queue_flows = 1024,
+		.nb_event_port_dequeue_depth = 64,
+		.nb_event_port_enqueue_depth = 64,
+	};
+	struct rte_event_queue_conf q_conf;
+	struct rte_event_port_conf p_conf = {
+		.dequeue_depth = 64,
+		.enqueue_depth = 64,
+		.new_event_threshold = 2048,
+		.event_port_cfg = 0
+	};
+	struct rte_event_dev_info info;
+	uint8_t ldb_queues[] = { Q_PARALLEL, Q_ATOMIC, Q_ORDERED };
+	uint8_t single_q = Q_SINGLE;
+	int ret;
+	int p;
+
+	g_dev_id = rte_event_dev_get_dev_id(SLB_PMD_NAME);
+	if (g_dev_id < 0) {
+		ret = rte_vdev_init("event_slb_selftest", NULL);
+		if (ret < 0) {
+			SLB_LOG_LINE(ERR, "Failed to init vdev event_slb_selftest");
+			return -1;
+		}
+		g_dev_id = rte_event_dev_get_dev_id("event_slb_selftest");
+		if (g_dev_id < 0) {
+			SLB_LOG_LINE(ERR, "Cannot find initialized vdev");
+			return -1;
+		}
+	}
+
+	ret = rte_event_dev_info_get(g_dev_id, &info);
+	if (ret < 0) {
+		SLB_LOG_LINE(ERR, "Failed to get dev info");
+		return -1;
+	}
+
+	ret = rte_event_dev_configure(g_dev_id, &dev_conf);
+	if (ret < 0) {
+		SLB_LOG_LINE(ERR, "Failed to configure device, ret=%d", ret);
+		return -1;
+	}
+
+	/* Setup Queues */
+	memset(&q_conf, 0, sizeof(q_conf));
+	q_conf.nb_atomic_flows = 1024;
+	q_conf.nb_atomic_order_sequences = 1024;
+	q_conf.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+
+	/* Q0: Parallel */
+	q_conf.schedule_type = RTE_SCHED_TYPE_PARALLEL;
+	q_conf.event_queue_cfg = 0;
+	ret = rte_event_queue_setup(g_dev_id, Q_PARALLEL, &q_conf);
+	if (ret < 0)
+		return -1;
+
+	/* Q1: Atomic */
+	q_conf.schedule_type = RTE_SCHED_TYPE_ATOMIC;
+	q_conf.event_queue_cfg = 0;
+	ret = rte_event_queue_setup(g_dev_id, Q_ATOMIC, &q_conf);
+	if (ret < 0)
+		return -1;
+
+	/* Q2: Ordered */
+	q_conf.schedule_type = RTE_SCHED_TYPE_ORDERED;
+	q_conf.event_queue_cfg = 0;
+	ret = rte_event_queue_setup(g_dev_id, Q_ORDERED, &q_conf);
+	if (ret < 0)
+		return -1;
+
+	/* Q3: Single-link */
+	q_conf.schedule_type = RTE_SCHED_TYPE_PARALLEL;
+	q_conf.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_LINK;
+	ret = rte_event_queue_setup(g_dev_id, Q_SINGLE, &q_conf);
+	if (ret < 0)
+		return -1;
+
+	/* Setup Ports */
+	for (p = 0; p < NUM_PORTS; p++) {
+		if (p == PORT_CONS)
+			p_conf.event_port_cfg = RTE_EVENT_PORT_CFG_SINGLE_LINK;
+		else
+			p_conf.event_port_cfg = 0;
+
+		ret = rte_event_port_setup(g_dev_id, p, &p_conf);
+		if (ret < 0)
+			return -1;
+	}
+
+	/* Link Queues */
+	ret = rte_event_port_link(g_dev_id, PORT_W1, ldb_queues, NULL, 3);
+	if (ret != 3)
+		return -1;
+
+	ret = rte_event_port_link(g_dev_id, PORT_W2, ldb_queues, NULL, 3);
+	if (ret != 3)
+		return -1;
+
+	ret = rte_event_port_link(g_dev_id, PORT_CONS, &single_q, NULL, 1);
+	if (ret != 1)
+		return -1;
+
+	ret = rte_event_dev_start(g_dev_id);
+	if (ret < 0)
+		return -1;
+
+	return 0;
+}
+
+static void
+cleanup_selftest_device(void)
+{
+	if (g_dev_id >= 0) {
+		rte_event_dev_stop(g_dev_id);
+		rte_event_dev_close(g_dev_id);
+		g_dev_id = -1;
+	}
+}
+
+static int
+test_parallel_queue(void)
+{
+	struct rte_event rx_ev[32];
+	struct rte_event ev[32];
+	uint16_t enqd, deqd = 0;
+	uint16_t n = 0;
+	int tries = 0;
+	int i;
+
+	memset(ev, 0, sizeof(ev));
+
+	for (i = 0; i < 32; i++) {
+		ev[i].op = RTE_EVENT_OP_NEW;
+		ev[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+		ev[i].queue_id = Q_PARALLEL;
+		ev[i].u64 = 1000 + i;
+	}
+
+	enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, 32);
+	if (enqd != 32) {
+		SLB_LOG_LINE(ERR, "Parallel enqueue failed, expected 32, got %u", enqd);
+		return -1;
+	}
+
+	while (deqd < 32 && tries++ < 1000) {
+		n = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx_ev + deqd,
+					    32 - deqd, 0);
+		deqd += n;
+		if (deqd < 32) {
+			n = rte_event_dequeue_burst(g_dev_id, PORT_W2,
+						    rx_ev + deqd, 32 - deqd, 0);
+			deqd += n;
+		}
+	}
+
+	if (deqd != 32) {
+		SLB_LOG_LINE(ERR, "Parallel dequeue failed, expected 32, got %u", deqd);
+		return -1;
+	}
+
+	/* Release events */
+	for (i = 0; i < 32; i++)
+		rx_ev[i].op = RTE_EVENT_OP_RELEASE;
+	rte_event_enqueue_burst(g_dev_id, PORT_W1, rx_ev, 32);
+
+	return 0;
+}
+
+static int
+test_atomic_queue(void)
+{
+	struct rte_event rx_ev[64];
+	struct rte_event ev[64];
+	int expected_seq[NUM_FLOWS];
+	uint16_t enqd = 0;
+	uint16_t deqd = 0;
+	int tries = 0;
+	int idx = 0;
+	int e, f;
+	uint16_t i, n;
+
+	memset(ev, 0, sizeof(ev));
+
+	for (e = 0; e < EVENTS_PER_FLOW; e++) {
+		for (f = 0; f < NUM_FLOWS; f++) {
+			ev[idx].op = RTE_EVENT_OP_NEW;
+			ev[idx].sched_type = RTE_SCHED_TYPE_ATOMIC;
+			ev[idx].queue_id = Q_ATOMIC;
+			ev[idx].flow_id = f;
+			ev[idx].u64 = e; /* sequence number */
+			idx++;
+		}
+	}
+
+	while (enqd < TOTAL_ATOMIC_EVENTS) {
+		n = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev + enqd,
+					    TOTAL_ATOMIC_EVENTS - enqd);
+		if (n == 0)
+			break;
+		enqd += n;
+	}
+	if (enqd != TOTAL_ATOMIC_EVENTS) {
+		SLB_LOG_LINE(ERR, "Atomic enqueue failed, expected %d, got %u",
+			     TOTAL_ATOMIC_EVENTS, enqd);
+		return -1;
+	}
+
+	for (f = 0; f < NUM_FLOWS; f++)
+		expected_seq[f] = 0;
+
+	while (deqd < TOTAL_ATOMIC_EVENTS && tries++ < 2000) {
+		n = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx_ev, 16, 0);
+		for (i = 0; i < n; i++) {
+			int fid = rx_ev[i].flow_id;
+
+			if (rx_ev[i].u64 != (uint64_t)expected_seq[fid]) {
+				SLB_LOG_LINE(ERR,
+					     "Flow %d out of order! Expected %d got %" PRIu64,
+					     fid, expected_seq[fid], rx_ev[i].u64);
+				return -1;
+			}
+			expected_seq[fid]++;
+			rx_ev[i].op = RTE_EVENT_OP_RELEASE;
+		}
+		if (n > 0)
+			rte_event_enqueue_burst(g_dev_id, PORT_W1, rx_ev, n);
+		deqd += n;
+
+		n = rte_event_dequeue_burst(g_dev_id, PORT_W2, rx_ev, 16, 0);
+		for (i = 0; i < n; i++) {
+			int fid = rx_ev[i].flow_id;
+
+			if (rx_ev[i].u64 != (uint64_t)expected_seq[fid]) {
+				SLB_LOG_LINE(ERR,
+					     "Flow %d out of order! Expected %d got %" PRIu64,
+					     fid, expected_seq[fid], rx_ev[i].u64);
+				return -1;
+			}
+			expected_seq[fid]++;
+			rx_ev[i].op = RTE_EVENT_OP_RELEASE;
+		}
+		if (n > 0)
+			rte_event_enqueue_burst(g_dev_id, PORT_W2, rx_ev, n);
+		deqd += n;
+	}
+
+	if (deqd != TOTAL_ATOMIC_EVENTS) {
+		SLB_LOG_LINE(ERR, "Atomic dequeue failed, expected %d got %u",
+			     TOTAL_ATOMIC_EVENTS, deqd);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_ordered_forward(void)
+{
+	const int num_events = 32;
+	struct rte_event rx[16];
+	struct rte_event ev[32];
+	uint16_t enqd;
+	uint16_t fwd = 0;
+	uint16_t cons_rx = 0;
+	int tries = 0;
+	int i;
+	uint16_t n;
+
+	memset(ev, 0, sizeof(ev));
+
+	for (i = 0; i < num_events; i++) {
+		ev[i].op = RTE_EVENT_OP_NEW;
+		ev[i].sched_type = RTE_SCHED_TYPE_ORDERED;
+		ev[i].queue_id = Q_ORDERED;
+		ev[i].u64 = i;
+	}
+
+	enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, num_events);
+	if (enqd != num_events)
+		return -1;
+
+	/* Workers dequeue and forward to Q_SINGLE */
+	while (fwd < num_events && tries++ < 2000) {
+		n = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx, 16, 0);
+		for (i = 0; i < n; i++) {
+			rx[i].op = RTE_EVENT_OP_FORWARD;
+			rx[i].queue_id = Q_SINGLE;
+			rx[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+		}
+		if (n > 0)
+			rte_event_enqueue_burst(g_dev_id, PORT_W1, rx, n);
+		fwd += n;
+
+		n = rte_event_dequeue_burst(g_dev_id, PORT_W2, rx, 16, 0);
+		for (i = 0; i < n; i++) {
+			rx[i].op = RTE_EVENT_OP_FORWARD;
+			rx[i].queue_id = Q_SINGLE;
+			rx[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+		}
+		if (n > 0)
+			rte_event_enqueue_burst(g_dev_id, PORT_W2, rx, n);
+		fwd += n;
+	}
+
+	if (fwd != num_events) {
+		SLB_LOG_LINE(ERR, "Ordered workers failed to forward all events (%u/%d)",
+			     fwd, num_events);
+		return -1;
+	}
+
+	/* Consumer on PORT_CONS must receive all events in exact sequence 0..num_events-1 */
+	tries = 0;
+	while (cons_rx < num_events && tries++ < 2000) {
+		n = rte_event_dequeue_burst(g_dev_id, PORT_CONS, rx, 16, 0);
+		for (i = 0; i < n; i++) {
+			if (rx[i].u64 != cons_rx) {
+				SLB_LOG_LINE(ERR,
+					     "Ordered seq violation! Expected %u got %" PRIu64,
+					     cons_rx, rx[i].u64);
+				return -1;
+			}
+			cons_rx++;
+			rx[i].op = RTE_EVENT_OP_RELEASE;
+		}
+		if (n > 0)
+			rte_event_enqueue_burst(g_dev_id, PORT_CONS, rx, n);
+	}
+
+	if (cons_rx != num_events) {
+		SLB_LOG_LINE(ERR, "Consumer received %u/%d ordered events",
+			     cons_rx, num_events);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_single_link(void)
+{
+	struct rte_event rx[16];
+	struct rte_event ev[16];
+	uint16_t enqd;
+	uint16_t deqd = 0;
+	int tries = 0;
+	int i;
+	uint16_t n;
+
+	memset(ev, 0, sizeof(ev));
+
+	for (i = 0; i < 16; i++) {
+		ev[i].op = RTE_EVENT_OP_NEW;
+		ev[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+		ev[i].queue_id = Q_SINGLE;
+		ev[i].u64 = 5000 + i;
+	}
+
+	enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, 16);
+	if (enqd != 16)
+		return -1;
+
+	while (deqd < 16 && tries++ < 1000) {
+		n = rte_event_dequeue_burst(g_dev_id, PORT_CONS,
+					    rx + deqd, 16 - deqd, 0);
+		deqd += n;
+	}
+
+	if (deqd != 16) {
+		SLB_LOG_LINE(ERR, "Single-link dequeue failed (%u/16)", deqd);
+		return -1;
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (rx[i].u64 != (uint64_t)(5000 + i))
+			return -1;
+		rx[i].op = RTE_EVENT_OP_RELEASE;
+	}
+	rte_event_enqueue_burst(g_dev_id, PORT_CONS, rx, 16);
+
+	return 0;
+}
+
+static int
+test_stop_flush(void)
+{
+	struct rte_event rx[16];
+	struct rte_event ev[16];
+	uint16_t enqd;
+	uint16_t deqd;
+	int ret;
+	int i;
+
+	memset(ev, 0, sizeof(ev));
+
+	for (i = 0; i < 16; i++) {
+		ev[i].op = RTE_EVENT_OP_NEW;
+		ev[i].sched_type = RTE_SCHED_TYPE_PARALLEL;
+		ev[i].queue_id = Q_PARALLEL;
+		ev[i].u64 = 9000 + i;
+	}
+
+	enqd = rte_event_enqueue_burst(g_dev_id, PORT_PROD, ev, 16);
+	if (enqd != 16)
+		return -1;
+
+	/* Stop device flushes all queued events */
+	rte_event_dev_stop(g_dev_id);
+
+	/* Restart device */
+	ret = rte_event_dev_start(g_dev_id);
+	if (ret < 0)
+		return -1;
+
+	/* Verify no leftover events */
+	deqd = rte_event_dequeue_burst(g_dev_id, PORT_W1, rx, 16, 0);
+	if (deqd != 0) {
+		SLB_LOG_LINE(ERR, "Stop flush failed, received %u events after restart",
+			     deqd);
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+test_slb_eventdev(void)
+{
+	SLB_LOG_LINE(INFO, "=== Running SLB Eventdev Selftest ===");
+
+	if (init_selftest_device() < 0) {
+		SLB_LOG_LINE(ERR, "Initialization failed");
+		cleanup_selftest_device();
+		return -1;
+	}
+
+	SLB_LOG_LINE(INFO, "  [1/5] Testing Parallel Queue...");
+	if (test_parallel_queue() < 0) {
+		SLB_LOG_LINE(ERR, "  FAILED: Parallel Queue test failed");
+		cleanup_selftest_device();
+		return -1;
+	}
+	SLB_LOG_LINE(INFO, "  [1/5] Parallel Queue: PASS");
+
+	SLB_LOG_LINE(INFO, "  [2/5] Testing Atomic Queue...");
+	if (test_atomic_queue() < 0) {
+		SLB_LOG_LINE(ERR, "  FAILED: Atomic Queue test failed");
+		cleanup_selftest_device();
+		return -1;
+	}
+	SLB_LOG_LINE(INFO, "  [2/5] Atomic Queue: PASS");
+
+	SLB_LOG_LINE(INFO, "  [3/5] Testing Ordered Queue...");
+	if (test_ordered_forward() < 0) {
+		SLB_LOG_LINE(ERR, "  FAILED: Ordered Queue test failed");
+		cleanup_selftest_device();
+		return -1;
+	}
+	SLB_LOG_LINE(INFO, "  [3/5] Ordered Queue: PASS");
+
+	SLB_LOG_LINE(INFO, "  [4/5] Testing Single-Link Queue...");
+	if (test_single_link() < 0) {
+		SLB_LOG_LINE(ERR, "  FAILED: Single-Link Queue test failed");
+		cleanup_selftest_device();
+		return -1;
+	}
+	SLB_LOG_LINE(INFO, "  [4/5] Single-Link Queue: PASS");
+
+	SLB_LOG_LINE(INFO, "  [5/5] Testing Device Stop & Flush...");
+	if (test_stop_flush() < 0) {
+		SLB_LOG_LINE(ERR, "  FAILED: Stop Flush test failed");
+		cleanup_selftest_device();
+		return -1;
+	}
+	SLB_LOG_LINE(INFO, "  [5/5] Device Stop & Flush: PASS");
+
+	cleanup_selftest_device();
+	SLB_LOG_LINE(INFO, "=== SLB Eventdev Selftest PASSED ===");
+	return 0;
+}
-- 
2.53.0


  parent reply	other threads:[~2026-11-07  1:31 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-07  1:30 [PATCH v1 0/8] event/slb: introducing software load balancer eventdev PMD Pravin Pathak
2026-11-07  1:30 ` [PATCH v1 1/8] event/slb: introduce software load balancer PMD Pravin Pathak
2026-11-07  1:30 ` [PATCH v1 2/8] event/slb: add support for ordered queues Pravin Pathak
2026-11-07  1:30 ` [PATCH v1 3/8] event/slb: add support for atomic queues Pravin Pathak
2026-11-07  1:30 ` [PATCH v1 4/8] event/slb: add dynamic flow migration " Pravin Pathak
2026-11-07  1:30 ` [PATCH v1 5/8] event/slb: add extended statistics and diagnostics Pravin Pathak
2026-11-07  1:30 ` Pravin Pathak [this message]
2026-11-07  1:30 ` [PATCH v1 7/8] event/slb: update resets and credit defaults Pravin Pathak
2026-11-07  1:30 ` [PATCH v1 8/8] event/slb: improve port linking, config checks and atomic refill Pravin Pathak
2026-11-07  7:29 ` [PATCH v1 0/8] event/slb: introducing software load balancer eventdev PMD Jerin Jacob
2026-11-08 17:10   ` Stephen Hemminger
2026-11-09  2:30   ` Pravin Pathak
2026-11-09 12:55     ` Jerin Jacob
2026-11-11 14:22       ` Sarkar, Tirthendu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261107013011.2443138-7-pravinpathakdev@gmail.com \
    --to=pravinpathakdev@gmail.com \
    --cc=bruce.richardson@intel.com \
    --cc=chenbox@nvidia.com \
    --cc=david.marchand@redhat.com \
    --cc=dev@dpdk.org \
    --cc=jerinj@marvell.com \
    --cc=mike.ximing.chen@intel.com \
    --cc=nipun.gupta@amd.com \
    --cc=pravin.pathak.dev@gmail.com \
    --cc=thomas@monjalon.net \
    --cc=tirthendu.sarkar@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox