Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2025 Ericsson AB
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <unistd.h>
7 : :
8 : : #include "test_atomic_common.h"
9 : :
10 : : #define NB_QUEUES 2
11 : : #define NB_STAGES 2
12 : :
13 : : static rte_spinlock_t *atomic_locks;
14 : :
15 : : static inline void
16 : 0 : atomic_queue_process_stage_0(struct test_order *const t,
17 : : struct rte_event *const ev,
18 : : uint32_t nb_flows,
19 : : uint32_t port)
20 : : {
21 : 0 : const uint32_t flow = *order_mbuf_flow_id(t, ev->mbuf);
22 : :
23 : 0 : atomic_lock_verify(atomic_locks, 0, flow, nb_flows, t, port);
24 : :
25 : 0 : ev->queue_id = 1;
26 : 0 : ev->op = RTE_EVENT_OP_FORWARD;
27 : 0 : ev->sched_type = RTE_SCHED_TYPE_ATOMIC;
28 : 0 : ev->event_type = RTE_EVENT_TYPE_CPU;
29 : :
30 : 0 : atomic_spinlock_unlock(atomic_locks, 0, flow, nb_flows);
31 : 0 : }
32 : :
33 : : static inline void
34 : 0 : atomic_queue_process_stage_1(struct test_order *const t,
35 : : struct rte_event *const ev,
36 : : uint32_t nb_flows,
37 : : rte_spinlock_t *atomic_locks,
38 : : uint32_t *const expected_flow_seq,
39 : : RTE_ATOMIC(uint64_t) * const outstand_pkts,
40 : : uint32_t port)
41 : : {
42 : 0 : const uint32_t flow = *order_mbuf_flow_id(t, ev->mbuf);
43 : 0 : const uint32_t seq = *order_mbuf_seqn(t, ev->mbuf);
44 : :
45 : 0 : atomic_lock_verify(atomic_locks, 1, flow, nb_flows, t, port);
46 : :
47 : : /* compare the seqn against expected value */
48 : 0 : if (seq != expected_flow_seq[flow]) {
49 : 0 : evt_err("flow=%x seqn mismatch got=%x expected=%x", flow, seq,
50 : : expected_flow_seq[flow]);
51 : 0 : t->err = true;
52 : : }
53 : :
54 : 0 : expected_flow_seq[flow]++;
55 : 0 : rte_pktmbuf_free(ev->mbuf);
56 : :
57 : 0 : rte_atomic_fetch_sub_explicit(outstand_pkts, 1, rte_memory_order_relaxed);
58 : :
59 : 0 : ev->op = RTE_EVENT_OP_RELEASE;
60 : :
61 : : atomic_spinlock_unlock(atomic_locks, 1, flow, nb_flows);
62 : 0 : }
63 : :
64 : : static int
65 : 0 : atomic_queue_worker_burst(void *arg, bool flow_id_cap, uint32_t max_burst)
66 : : {
67 : 0 : ORDER_WORKER_INIT;
68 : : struct rte_event ev[BURST_SIZE];
69 : : uint16_t i;
70 : :
71 : 0 : while (t->err == false) {
72 : :
73 : 0 : uint16_t const nb_rx = rte_event_dequeue_burst(dev_id, port, ev, max_burst, 0);
74 : :
75 : 0 : if (nb_rx == 0) {
76 : 0 : if (rte_atomic_load_explicit(outstand_pkts, rte_memory_order_relaxed) <= 0)
77 : : break;
78 : : rte_pause();
79 : 0 : continue;
80 : : }
81 : :
82 : 0 : for (i = 0; i < nb_rx; i++) {
83 : 0 : if (!flow_id_cap)
84 : 0 : order_flow_id_copy_from_mbuf(t, &ev[i]);
85 : :
86 : 0 : switch (ev[i].queue_id) {
87 : 0 : case 0:
88 : 0 : atomic_queue_process_stage_0(t, &ev[i], nb_flows, port);
89 : 0 : break;
90 : 0 : case 1:
91 : 0 : atomic_queue_process_stage_1(t, &ev[i], nb_flows, atomic_locks,
92 : : expected_flow_seq, outstand_pkts, port);
93 : 0 : break;
94 : 0 : default:
95 : : order_process_stage_invalid(t, &ev[i]);
96 : : break;
97 : : }
98 : : }
99 : :
100 : : uint16_t total_enq = 0;
101 : :
102 : : do {
103 : 0 : total_enq += rte_event_enqueue_burst(
104 : 0 : dev_id, port, ev + total_enq, nb_rx - total_enq);
105 : 0 : } while (total_enq < nb_rx);
106 : : }
107 : :
108 : 0 : return 0;
109 : : }
110 : :
111 : : static int
112 : 0 : worker_wrapper(void *arg)
113 : : {
114 : : struct worker_data *w = arg;
115 : 0 : int max_burst = evt_has_burst_mode(w->dev_id) ? BURST_SIZE : 1;
116 : 0 : const bool flow_id_cap = evt_has_flow_id(w->dev_id);
117 : :
118 : 0 : return atomic_queue_worker_burst(arg, flow_id_cap, max_burst);
119 : : }
120 : :
121 : : static int
122 : 0 : atomic_queue_launch_lcores(struct evt_test *test, struct evt_options *opt)
123 : : {
124 : 0 : int ret = atomic_launch_lcores(test, opt, worker_wrapper);
125 : 0 : rte_free(atomic_locks);
126 : 0 : return ret;
127 : : }
128 : :
129 : : static int
130 : 0 : atomic_queue_eventdev_setup(struct evt_test *test, struct evt_options *opt)
131 : : {
132 : : int ret;
133 : :
134 : 0 : const uint8_t nb_workers = evt_nr_active_lcores(opt->wlcores);
135 : : /* number of active worker cores + 1 producer */
136 : 0 : const uint8_t nb_ports = nb_workers + 1;
137 : :
138 : 0 : ret = evt_configure_eventdev(opt, NB_QUEUES, nb_ports);
139 : 0 : if (ret) {
140 : 0 : evt_err("failed to configure eventdev %d", opt->dev_id);
141 : 0 : return ret;
142 : : }
143 : :
144 : : /* q0 configuration */
145 : 0 : struct rte_event_queue_conf q0_atomic_conf = {
146 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
147 : : .schedule_type = RTE_SCHED_TYPE_ATOMIC,
148 : 0 : .nb_atomic_flows = opt->nb_flows,
149 : : .nb_atomic_order_sequences = opt->nb_flows,
150 : : };
151 : 0 : ret = rte_event_queue_setup(opt->dev_id, 0, &q0_atomic_conf);
152 : 0 : if (ret) {
153 : 0 : evt_err("failed to setup queue0 eventdev %d err %d", opt->dev_id, ret);
154 : 0 : return ret;
155 : : }
156 : :
157 : : /* q1 configuration */
158 : 0 : struct rte_event_queue_conf q1_atomic_conf = {
159 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
160 : : .schedule_type = RTE_SCHED_TYPE_ATOMIC,
161 : 0 : .nb_atomic_flows = opt->nb_flows,
162 : : .nb_atomic_order_sequences = opt->nb_flows,
163 : : };
164 : 0 : ret = rte_event_queue_setup(opt->dev_id, 1, &q1_atomic_conf);
165 : 0 : if (ret) {
166 : 0 : evt_err("failed to setup queue0 eventdev %d err %d", opt->dev_id, ret);
167 : 0 : return ret;
168 : : }
169 : :
170 : : /* setup one port per worker, linking to all queues */
171 : 0 : ret = order_event_dev_port_setup(test, opt, nb_workers, NB_QUEUES);
172 : 0 : if (ret)
173 : : return ret;
174 : :
175 : 0 : if (!evt_has_distributed_sched(opt->dev_id)) {
176 : : uint32_t service_id;
177 : 0 : rte_event_dev_service_id_get(opt->dev_id, &service_id);
178 : 0 : ret = evt_service_setup(service_id);
179 : 0 : if (ret) {
180 : 0 : evt_err("No service lcore found to run event dev.");
181 : 0 : return ret;
182 : : }
183 : : }
184 : :
185 : 0 : ret = rte_event_dev_start(opt->dev_id);
186 : 0 : if (ret) {
187 : 0 : evt_err("failed to start eventdev %d", opt->dev_id);
188 : 0 : return ret;
189 : : }
190 : :
191 : 0 : atomic_locks = atomic_init_locks(NB_STAGES, opt->nb_flows);
192 : :
193 : 0 : return 0;
194 : : }
195 : :
196 : : static void
197 : 0 : atomic_queue_opt_dump(struct evt_options *opt)
198 : : {
199 : 0 : order_opt_dump(opt);
200 : : evt_dump("nb_evdev_queues", "%d", NB_QUEUES);
201 : 0 : }
202 : :
203 : : static bool
204 : 0 : atomic_queue_capability_check(struct evt_options *opt)
205 : : {
206 : : struct rte_event_dev_info dev_info;
207 : :
208 : 0 : rte_event_dev_info_get(opt->dev_id, &dev_info);
209 : 0 : if (dev_info.max_event_queues < NB_QUEUES ||
210 : 0 : dev_info.max_event_ports < order_nb_event_ports(opt)) {
211 : 0 : evt_err("not enough eventdev queues=%d/%d or ports=%d/%d", NB_QUEUES,
212 : : dev_info.max_event_queues, order_nb_event_ports(opt),
213 : : dev_info.max_event_ports);
214 : 0 : return false;
215 : : }
216 : :
217 : : return true;
218 : : }
219 : :
220 : : static const struct evt_test_ops atomic_queue = {
221 : : .cap_check = atomic_queue_capability_check,
222 : : .opt_check = order_opt_check,
223 : : .opt_dump = atomic_queue_opt_dump,
224 : : .test_setup = order_test_setup,
225 : : .mempool_setup = order_mempool_setup,
226 : : .eventdev_setup = atomic_queue_eventdev_setup,
227 : : .launch_lcores = atomic_queue_launch_lcores,
228 : : .eventdev_destroy = order_eventdev_destroy,
229 : : .mempool_destroy = order_mempool_destroy,
230 : : .test_result = order_test_result,
231 : : .test_destroy = order_test_destroy,
232 : : };
233 : :
234 : 0 : EVT_TEST_REGISTER(atomic_queue);
|