From: Pravin Pathak <[email protected]>

- Force RTE_SCHED_TYPE_ATOMIC on events dequeued from single-link queues
  and skip atomic/ordered state allocations for single-link queues.
- Remove RTE_EVENT_DEV_CAP_RUNTIME_PORT_LINK advertisement from driver
  info, feature matrix, and release notes.
- Reset atomic queue flow-to-port mappings, hold buffers, migration
  state, per-port stats, ordered reorder buffers, and port history when
  the device is stopped in slb_stop().
- Default port new_event_threshold in slb_port_def_conf() to 1/4 of
  SLB_IN_RING_SIZE (clamped to nb_events_limit when configured) and
  lower SLB_MIN_CREDIT_LOAN from 512 to 256 so more ports can borrow
  credits concurrently.

Signed-off-by: Pravin Pathak <[email protected]>
---
 doc/guides/eventdevs/features/slb.ini |  1 -
 doc/guides/eventdevs/slb.rst          | 31 ++++------
 drivers/event/slb/slb_evdev.c         | 81 +++++++++++++++++++++------
 drivers/event/slb/slb_evdev.h         |  5 +-
 drivers/event/slb/slb_event.c         | 23 ++++++--
 drivers/event/slb/slb_selftest.c      | 12 ++++
 6 files changed, 110 insertions(+), 43 deletions(-)

diff --git a/doc/guides/eventdevs/features/slb.ini 
b/doc/guides/eventdevs/features/slb.ini
index 0364840bc9..33036301a8 100644
--- a/doc/guides/eventdevs/features/slb.ini
+++ b/doc/guides/eventdevs/features/slb.ini
@@ -11,7 +11,6 @@ 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
diff --git a/doc/guides/eventdevs/slb.rst b/doc/guides/eventdevs/slb.rst
index d319b94920..b109a1e2ca 100644
--- a/doc/guides/eventdevs/slb.rst
+++ b/doc/guides/eventdevs/slb.rst
@@ -4,9 +4,10 @@
 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.
+The Software Load Balancer (SLB) is a software event device and a poll-mode 
Eventdev driver.
+It uses a distributed scheduler, allowing it to scale well. SLB does not 
require dedicated
+cores for scheduling. It supports Atomic, Parallel, and Ordered queues with 
dynamic atomic
+flow load balancing. SLB also requires no internal core communication and is 
maintenance-free.
 
 Features
 --------
@@ -19,25 +20,17 @@ Queues
 * **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.
+* **Ordered**: Sequence number-based tracking and reordering.
+* **Single-Link**: Implemented using optimized multi-producer 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.
+* **Distributed Scheduling**: No dedicated service core required.
 * **Dynamic Flow Migration**: Atomic queues monitor port dequeue loads and 
migrate
-  eligible victim flows from overloaded ports to underloaded ports with 
cooling cycles.
+  Eligible 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``).
 
@@ -62,7 +55,7 @@ application code or from the EAL command line:
 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``).
+* **Maximum Ports and Queues**: Supports up to 64 ports and 64 queues.
+* **Priorities and linking**: Supports two levels of service priority to link 
up to
+  eight queues per port at each priority. SLB currently does not support event 
priority.
+* **Queues Types**: Does not support all-type queues.
diff --git a/drivers/event/slb/slb_evdev.c b/drivers/event/slb/slb_evdev.c
index c86b934b03..16bfefaa68 100644
--- a/drivers/event/slb/slb_evdev.c
+++ b/drivers/event/slb/slb_evdev.c
@@ -26,6 +26,7 @@ slb_port_reset_history(struct slb_port *port)
 {
        port->history[0].active = false;
        port->history[0].next_free = SLB_PORT_HISTORY_FREE_END;
+       /* 1 -> 2 -> 3 ..... 255 -> END */
        for (int i = 1; i < SLB_PORT_HISTORY_SIZE; i++) {
                port->history[i].active = false;
                port->history[i].next_free = i + 1;
@@ -36,7 +37,7 @@ slb_port_reset_history(struct slb_port *port)
        port->history_avail = SLB_PORT_HISTORY_MAX_TOKENS;
 }
 
-/* Setup Eventdev port. Reset all mapped queues */
+/* Setup Eventdev port. Reset all mapped queues and history tracking */
 static int
 slb_port_setup(struct rte_eventdev *dev, uint8_t port_id,
               const struct rte_event_port_conf *conf)
@@ -103,12 +104,18 @@ slb_port_setup(struct rte_eventdev *dev, uint8_t port_id,
 
 /* Default Eventdev port configuration for SLB */
 static void
-slb_port_def_conf(struct rte_eventdev *dev __rte_unused,
+slb_port_def_conf(struct rte_eventdev *dev,
                  uint8_t port_id __rte_unused,
                  struct rte_event_port_conf *port_conf)
 {
+       int32_t threshold = SLB_IN_RING_SIZE / 4;
+
+       if (dev->data->dev_conf.nb_events_limit > 0 &&
+           threshold > dev->data->dev_conf.nb_events_limit)
+               threshold = dev->data->dev_conf.nb_events_limit;
+
        *port_conf = (struct rte_event_port_conf) {
-               .new_event_threshold = 1024,
+               .new_event_threshold = threshold,
                .dequeue_depth = SLB_MAX_PORT_DEQUEUE_DEPTH / 4,
                .enqueue_depth = SLB_MAX_PORT_ENQUEUE_DEPTH / 4
        };
@@ -146,7 +153,9 @@ slb_queue_release(struct rte_eventdev *dev, uint8_t 
queue_id)
        }
 }
 
-/* Setup Eventdev queue. Eventdev queues are implemented as DPDK rings */
+/* Setup Eventdev queue. Eventdev queues are implemented as DPDK rings.
+ *  SLB Supports single-link, atomic, parallel, and ordered queues.
+ */
 static int
 slb_queue_setup(struct rte_eventdev *dev, uint8_t queue_id,
                const struct rte_event_queue_conf *conf)
@@ -190,12 +199,15 @@ slb_queue_setup(struct rte_eventdev *dev, uint8_t 
queue_id,
                return -ENOMEM;
 
        queue->q_ring = ring;
-       queue->schedule_type = conf->schedule_type;
+       /* Single-link queue uses atomic schedule type */
+       queue->schedule_type = queue->is_single_link ?
+                              RTE_SCHED_TYPE_ATOMIC : conf->schedule_type;
        queue->serving_ports_mask = 0;
        queue->num_serving_ports = 0;
 
-       /* Atomic queue allocation */
-       if (conf->schedule_type == RTE_SCHED_TYPE_ATOMIC) {
+       /* Atomic queue state allocation */
+       if (!queue->is_single_link &&
+           conf->schedule_type == RTE_SCHED_TYPE_ATOMIC) {
                for (int i = 0; i < SLB_MAX_PORTS; i++)
                        queue->per_port_rings[i] = NULL;
 
@@ -224,7 +236,8 @@ slb_queue_setup(struct rte_eventdev *dev, uint8_t queue_id,
        }
 
        /* Ordered queue reorder buffer allocation */
-       if (conf->schedule_type == RTE_SCHED_TYPE_ORDERED) {
+       if (!queue->is_single_link &&
+           conf->schedule_type == RTE_SCHED_TYPE_ORDERED) {
                queue->reorder_buffer = rte_zmalloc_socket("slb_reorder_buf",
                        sizeof(struct slb_reorder_entry) * ring->r.size,
                        RTE_CACHE_LINE_SIZE, dev->data->socket_id);
@@ -293,7 +306,8 @@ slb_port_link_one(struct slb_port *port, struct slb_queue 
*queue,
                port->single_linked_q = queue;
                port->single_linked_ring = queue->q_ring;
        } else {
-               if (queue->schedule_type == RTE_SCHED_TYPE_ATOMIC &&
+               if (!queue->is_single_link &&
+                   queue->schedule_type == RTE_SCHED_TYPE_ATOMIC &&
                    queue->per_port_rings[port->id] == NULL) {
                        char ring_name[RTE_RING_NAMESIZE];
                        struct rte_event_ring *ring;
@@ -332,7 +346,8 @@ slb_port_link_one(struct slb_port *port, struct slb_queue 
*queue,
                if (!found) {
                        uint16_t slot = port->num_q[prio];
                        struct rte_event_ring *dq_ring =
-                               (queue->schedule_type == RTE_SCHED_TYPE_ATOMIC) 
?
+                               (!queue->is_single_link &&
+                                queue->schedule_type == RTE_SCHED_TYPE_ATOMIC) 
?
                                queue->per_port_rings[port->id] : queue->q_ring;
 
                        if (slot >= SLB_PORT_MAX_Q_MAP_PER_PRIO) {
@@ -344,6 +359,8 @@ slb_port_link_one(struct slb_port *port, struct slb_queue 
*queue,
                        port->q_entries[prio][slot].queue_id = qid;
                        port->q_entries[prio][slot].schedule_type =
                                queue->schedule_type;
+                       port->q_entries[prio][slot].is_single_link =
+                               queue->is_single_link;
                        port->num_q[prio]++;
                }
 
@@ -464,7 +481,6 @@ slb_info_get(struct rte_eventdev *dev __rte_unused,
                RTE_EVENT_DEV_CAP_IMPLICIT_RELEASE_DISABLE |
                RTE_EVENT_DEV_CAP_NONSEQ_MODE |
                RTE_EVENT_DEV_CAP_MULTIPLE_QUEUE_PORT |
-               RTE_EVENT_DEV_CAP_RUNTIME_PORT_LINK |
                RTE_EVENT_DEV_CAP_CARRY_FLOW_ID |
                RTE_EVENT_DEV_CAP_MAINTENANCE_FREE |
                RTE_EVENT_DEV_CAP_INDEPENDENT_ENQ
@@ -555,22 +571,52 @@ slb_stop(struct rte_eventdev *dev)
        for (uint8_t qid = 0; qid < slb->num_queues; qid++) {
                struct slb_queue *q = &slb->queues[qid];
 
-               if (q->schedule_type == RTE_SCHED_TYPE_ATOMIC && 
q->atomic_state != NULL) {
+               if (q->schedule_type == RTE_SCHED_TYPE_ATOMIC &&
+                   q->atomic_state != NULL) {
+                       struct slb_atomic_state *astate = q->atomic_state;
+
+                       for (uint16_t h = 0; h < astate->hold_count; h++) {
+                               if (flush != NULL)
+                                       flush(dev_id, astate->hold_buffer[h],
+                                             flush_arg);
+                       }
+                       astate->hold_count = 0;
+                       astate->next_port_rr = 0;
+                       astate->migration.in_progress = false;
+
                        for (int f = 0; f < SLB_ATOMIC_FLOWS; f++) {
                                rte_atomic_store_explicit(
-                                       
&q->atomic_state->flow_map.flows[f].port_id,
+                                       &astate->flow_map.flows[f].port_id,
                                        -1, rte_memory_order_relaxed);
-                               q->atomic_state->flow_last_migrated[f] = 0;
+                               astate->flow_last_migrated[f] = 0;
                        }
-                       q->atomic_state->migration.in_progress = false;
+
+                       memset(astate->port_stats, 0,
+                              sizeof(astate->port_stats));
 
                        for (uint16_t pid = 0; pid < slb->num_ports; pid++) {
-                               q->atomic_state->port_stats[pid].load_counter = 
0;
                                if (q->per_port_rings[pid] != NULL)
                                        slb_drain_ring(dev_id,
                                                       q->per_port_rings[pid],
                                                       flush, flush_arg);
                        }
+               } else if (q->schedule_type == RTE_SCHED_TYPE_ORDERED &&
+                          q->reorder_buffer != NULL && q->q_ring != NULL) {
+                       for (uint32_t s = 0; s < q->q_ring->r.size; s++) {
+                               uint8_t st = rte_atomic_load_explicit(
+                                       &q->reorder_buffer[s].state,
+                                       rte_memory_order_relaxed);
+
+                               if (st == SLB_REORDER_READY && flush != NULL)
+                                       flush(dev_id,
+                                             q->reorder_buffer[s].event,
+                                             flush_arg);
+                               rte_atomic_store_explicit(
+                                       &q->reorder_buffer[s].state,
+                                       SLB_REORDER_EMPTY,
+                                       rte_memory_order_relaxed);
+                       }
+                       q->reorder_drain_idx = 0;
                }
 
                if (q->q_ring != NULL)
@@ -581,7 +627,10 @@ slb_stop(struct rte_eventdev *dev)
                struct slb_port *port = &slb->ports[i];
                port->inflight_credits = 0;
                port->credits_drained = false;
+               port->pending_releases = 0;
                port->is_loaded = false;
+               port->last_migrated_time = 0;
+               slb_port_reset_history(port);
                for (int p = 0; p < SLB_MAX_PRIORITIES; p++)
                        port->next_q[p] = 0;
        }
diff --git a/drivers/event/slb/slb_evdev.h b/drivers/event/slb/slb_evdev.h
index f727a1b83c..bf262903cd 100644
--- a/drivers/event/slb/slb_evdev.h
+++ b/drivers/event/slb/slb_evdev.h
@@ -28,7 +28,7 @@
 #define SLB_MAX_FLOWS_MASK (SLB_MAX_FLOWS - 1)
 
 /* Avoid making small 'loans' from the central in-flight event credit pool */
-#define SLB_MIN_CREDIT_LOAN (512)
+#define SLB_MIN_CREDIT_LOAN (256)
 #define SLB_PORT_MAX_CREDITS (2 * SLB_MIN_CREDIT_LOAN)
 #define SLB_PORT_MIN_CREDITS (SLB_MIN_CREDIT_LOAN)
 
@@ -56,7 +56,8 @@ struct slb_port_q_entry {
        struct slb_queue *queue;
        uint8_t queue_id;
        uint8_t schedule_type;
-       uint8_t pad[6];
+       bool is_single_link;
+       uint8_t pad[5];
 };
 
 #define SLB_PORT_HISTORY_SIZE 256
diff --git a/drivers/event/slb/slb_event.c b/drivers/event/slb/slb_event.c
index 3a0f7f6fde..c44deba905 100644
--- a/drivers/event/slb/slb_event.c
+++ b/drivers/event/slb/slb_event.c
@@ -976,8 +976,10 @@ slb_port_dequeue(struct slb_port *port, struct rte_event 
events[],
                        return 0;
                dequeued = 
rte_event_ring_dequeue_burst(port->single_linked_ring,
                                                        events, num, NULL);
-               for (uint16_t j = 0; j < dequeued; j++)
+               for (uint16_t j = 0; j < dequeued; j++) {
+                       events[j].sched_type = RTE_SCHED_TYPE_ATOMIC;
                        events[j].impl_opaque = 0;
+               }
                return dequeued;
        }
 
@@ -1015,8 +1017,11 @@ slb_port_dequeue(struct slb_port *port, struct rte_event 
events[],
                                continue;
 
                        uint8_t sched_type = qent->schedule_type;
-                       bool is_ordered = (sched_type == 
RTE_SCHED_TYPE_ORDERED);
-                       bool is_atomic = (sched_type == RTE_SCHED_TYPE_ATOMIC);
+                       bool is_single_link = qent->is_single_link;
+                       bool is_ordered = !is_single_link &&
+                                         (sched_type == 
RTE_SCHED_TYPE_ORDERED);
+                       bool is_atomic = !is_single_link &&
+                                        (sched_type == RTE_SCHED_TYPE_ATOMIC);
 
                        if (is_ordered || is_atomic) {
                                if (unlikely(port->history_avail == 0))
@@ -1050,8 +1055,16 @@ slb_port_dequeue(struct slb_port *port, struct rte_event 
events[],
                        } else {
                                dequeued = rte_event_ring_dequeue_burst(
                                        ring_to_dq, events, num, NULL);
-                               for (uint16_t j = 0; j < dequeued; j++)
-                                       events[j].impl_opaque = 0;
+                               if (is_single_link) {
+                                       for (uint16_t j = 0; j < dequeued; j++) 
{
+                                               events[j].sched_type =
+                                                       RTE_SCHED_TYPE_ATOMIC;
+                                               events[j].impl_opaque = 0;
+                                       }
+                               } else {
+                                       for (uint16_t j = 0; j < dequeued; j++)
+                                               events[j].impl_opaque = 0;
+                               }
                        }
 
                        if (dequeued > 0) {
diff --git a/drivers/event/slb/slb_selftest.c b/drivers/event/slb/slb_selftest.c
index 4a072b811b..776b6d6ab4 100644
--- a/drivers/event/slb/slb_selftest.c
+++ b/drivers/event/slb/slb_selftest.c
@@ -362,6 +362,12 @@ test_ordered_forward(void)
                                             cons_rx, rx[i].u64);
                                return -1;
                        }
+                       if (rx[i].sched_type != RTE_SCHED_TYPE_ATOMIC) {
+                               SLB_LOG_LINE(ERR,
+                                            "Single-link dequeue sched_type 
expected %u, got %u",
+                                            RTE_SCHED_TYPE_ATOMIC, 
rx[i].sched_type);
+                               return -1;
+                       }
                        cons_rx++;
                        rx[i].op = RTE_EVENT_OP_RELEASE;
                }
@@ -416,6 +422,12 @@ test_single_link(void)
        for (i = 0; i < 16; i++) {
                if (rx[i].u64 != (uint64_t)(5000 + i))
                        return -1;
+               if (rx[i].sched_type != RTE_SCHED_TYPE_ATOMIC) {
+                       SLB_LOG_LINE(ERR,
+                                    "Single-link dequeue sched_type expected 
%u, got %u",
+                                    RTE_SCHED_TYPE_ATOMIC, rx[i].sched_type);
+                       return -1;
+               }
                rx[i].op = RTE_EVENT_OP_RELEASE;
        }
        rte_event_enqueue_burst(g_dev_id, PORT_CONS, rx, 16);
-- 
2.53.0

Reply via email to