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
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.