Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2024 Marvell.
3 : : */
4 : :
5 : : #include <rte_vect.h>
6 : :
7 : : #include "roc_api.h"
8 : :
9 : : #include "cn20k_worker.h"
10 : : #include "cnxk_eventdev.h"
11 : : #include "cnxk_worker.h"
12 : :
13 : : /* SSO Operations */
14 : :
15 : : static __rte_always_inline uint8_t
16 : : cn20k_sso_hws_new_event(struct cn20k_sso_hws *ws, const struct rte_event *ev)
17 : : {
18 : 0 : const uint32_t tag = (uint32_t)ev->event;
19 : 0 : const uint8_t new_tt = ev->sched_type;
20 : 0 : const uint64_t event_ptr = ev->u64;
21 [ # # ]: 0 : const uint16_t grp = ev->queue_id;
22 : :
23 : : rte_atomic_thread_fence(rte_memory_order_acq_rel);
24 [ # # ]: 0 : if (ws->xaq_lmt <= *ws->fc_mem)
25 : : return 0;
26 : :
27 : 0 : cnxk_sso_hws_add_work(event_ptr, tag, new_tt, ws->grp_base + (grp << 12));
28 : 0 : return 1;
29 : : }
30 : :
31 : : static __rte_always_inline void
32 : : cn20k_sso_hws_fwd_swtag(struct cn20k_sso_hws *ws, const struct rte_event *ev)
33 : : {
34 : 0 : const uint32_t tag = (uint32_t)ev->event;
35 : 0 : const uint8_t new_tt = ev->sched_type;
36 : 0 : const uint8_t cur_tt = CNXK_TT_FROM_TAG(ws->gw_rdata);
37 : :
38 : : /* CNXK model
39 : : * cur_tt/new_tt SSO_TT_ORDERED SSO_TT_ATOMIC SSO_TT_UNTAGGED
40 : : *
41 : : * SSO_TT_ORDERED norm norm untag
42 : : * SSO_TT_ATOMIC norm norm untag
43 : : * SSO_TT_UNTAGGED norm norm NOOP
44 : : */
45 : :
46 [ # # # # ]: 0 : if (new_tt == SSO_TT_UNTAGGED) {
47 [ # # # # ]: 0 : if (cur_tt != SSO_TT_UNTAGGED)
48 : 0 : cnxk_sso_hws_swtag_untag(ws->base + SSOW_LF_GWS_OP_SWTAG_UNTAG);
49 : : } else {
50 : 0 : cnxk_sso_hws_swtag_norm(tag, new_tt, ws->base + SSOW_LF_GWS_OP_SWTAG_NORM);
51 : : }
52 : 0 : ws->swtag_req = 1;
53 : 0 : }
54 : :
55 : : static __rte_always_inline void
56 : : cn20k_sso_hws_fwd_group(struct cn20k_sso_hws *ws, const struct rte_event *ev, const uint16_t grp)
57 : : {
58 : 0 : const uint32_t tag = (uint32_t)ev->event;
59 : 0 : const uint8_t new_tt = ev->sched_type;
60 : :
61 : 0 : plt_write64(ev->u64, ws->base + SSOW_LF_GWS_OP_UPD_WQP_GRP1);
62 : 0 : cnxk_sso_hws_swtag_desched(tag, new_tt, grp, ws->base + SSOW_LF_GWS_OP_SWTAG_DESCHED);
63 : 0 : }
64 : :
65 : : static __rte_always_inline void
66 : : cn20k_sso_hws_forward_event(struct cn20k_sso_hws *ws, const struct rte_event *ev)
67 : : {
68 : 0 : const uint8_t grp = ev->queue_id;
69 : :
70 : : /* Group hasn't changed, Use SWTAG to forward the event */
71 [ # # ]: 0 : if (CNXK_GRP_FROM_TAG(ws->gw_rdata) == grp)
72 : : cn20k_sso_hws_fwd_swtag(ws, ev);
73 : : else
74 : : /*
75 : : * Group has been changed for group based work pipelining,
76 : : * Use deschedule/add_work operation to transfer the event to
77 : : * new group/core
78 : : */
79 : : cn20k_sso_hws_fwd_group(ws, ev, grp);
80 : : }
81 : :
82 : : static inline int32_t
83 : : sso_read_xaq_space(struct cn20k_sso_hws *ws)
84 : : {
85 : 0 : return (ws->xaq_lmt - rte_atomic_load_explicit(ws->fc_mem, rte_memory_order_relaxed)) *
86 : 0 : ws->xae_waes;
87 : : }
88 : :
89 : : static inline void
90 : 0 : sso_lmt_aw_wait_fc(struct cn20k_sso_hws *ws, int64_t req)
91 : : {
92 : : int64_t cached, refill;
93 : :
94 : 0 : retry:
95 [ # # ]: 0 : while (rte_atomic_load_explicit(ws->fc_cache_space, rte_memory_order_relaxed) < 0)
96 : : ;
97 : :
98 : 0 : cached = rte_atomic_fetch_sub_explicit(ws->fc_cache_space, req, rte_memory_order_acquire) -
99 : : req;
100 : : /* Check if there is enough space, else update and retry. */
101 [ # # ]: 0 : if (cached < 0) {
102 : : /* Check if we have space else retry. */
103 : : do {
104 : 0 : refill = sso_read_xaq_space(ws);
105 [ # # ]: 0 : } while (refill <= 0);
106 : 0 : rte_atomic_compare_exchange_strong_explicit(ws->fc_cache_space, &cached, refill,
107 : : rte_memory_order_release,
108 : : rte_memory_order_relaxed);
109 : :
110 : 0 : goto retry;
111 : : }
112 : 0 : }
113 : :
114 : : #define VECTOR_SIZE_BITS 0xFFFFFFFFFFF80000ULL
115 : : #define VECTOR_GET_LINE_OFFSET(line) (19 + (3 * line))
116 : :
117 : : static uint64_t
118 : : vector_size_partial_mask(uint16_t off, uint16_t cnt)
119 : : {
120 : 0 : return (VECTOR_SIZE_BITS & ~(~0x0ULL << off)) | ((uint64_t)(cnt - 1) << off);
121 : : }
122 : :
123 : : static __rte_always_inline uint16_t
124 : : cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
125 : : const struct rte_event ev[], uint16_t n)
126 : : {
127 : : uint16_t lines, partial_line, burst, left;
128 : : uint64_t wdata[2], pa[2] = {0};
129 : : uintptr_t lmt_addr;
130 : : uint16_t sz0, sz1;
131 : : uint16_t lmt_id;
132 : :
133 : : sz0 = sz1 = 0;
134 : 0 : lmt_addr = ws->aw_lmt;
135 : : ROC_LMT_BASE_ID_GET(lmt_addr, lmt_id);
136 : :
137 : : left = n;
138 : 0 : again:
139 : 0 : burst = RTE_MIN(BIT(ROC_SSO_AW_PER_LMT_LINE_LOG2 + ROC_LMT_LINES_PER_CORE_LOG2), left);
140 : :
141 : : /* Set wdata */
142 : 0 : lines = burst >> ROC_SSO_AW_PER_LMT_LINE_LOG2;
143 : 0 : partial_line = burst & (BIT(ROC_SSO_AW_PER_LMT_LINE_LOG2) - 1);
144 : : wdata[0] = wdata[1] = 0;
145 [ # # ]: 0 : if (lines > BIT(ROC_LMT_LINES_PER_STR_LOG2)) {
146 : : wdata[0] = lmt_id;
147 : : wdata[0] |= 15ULL << 12;
148 : : wdata[0] |= VECTOR_SIZE_BITS;
149 : : pa[0] = (ws->grp_base + (queue_id << 12) + SSO_LF_GGRP_OP_AW_LMTST) | (0x7 << 4);
150 : : sz0 = 16 << ROC_SSO_AW_PER_LMT_LINE_LOG2;
151 : :
152 : : wdata[1] = lmt_id + 16;
153 : : pa[1] = (ws->grp_base + (queue_id << 12) + SSO_LF_GGRP_OP_AW_LMTST) | (0x7 << 4);
154 : :
155 : 0 : lines -= 17;
156 [ # # ]: 0 : wdata[1] |= partial_line ? (uint64_t)(lines + 1) << 12 : (uint64_t)(lines << 12);
157 : 0 : wdata[1] |= partial_line ? vector_size_partial_mask(VECTOR_GET_LINE_OFFSET(lines),
158 [ # # ]: 0 : partial_line) :
159 : : VECTOR_SIZE_BITS;
160 : 0 : sz1 = burst - sz0;
161 : : partial_line = 0;
162 [ # # ]: 0 : } else if (lines) {
163 : : /* We need to handle two cases here:
164 : : * 1. Partial line spill over to wdata[1] i.e. lines == 16
165 : : * 2. Partial line with spill lines < 16.
166 : : */
167 : : wdata[0] = lmt_id;
168 : : pa[0] = (ws->grp_base + (queue_id << 12) + SSO_LF_GGRP_OP_AW_LMTST) | (0x7 << 4);
169 : 0 : sz0 = lines << ROC_SSO_AW_PER_LMT_LINE_LOG2;
170 [ # # ]: 0 : if (lines == 16) {
171 : : wdata[0] |= 15ULL << 12;
172 : : wdata[0] |= VECTOR_SIZE_BITS;
173 [ # # ]: 0 : if (partial_line) {
174 : : wdata[1] = lmt_id + 16;
175 : : pa[1] = (ws->grp_base + (queue_id << 12) +
176 : : SSO_LF_GGRP_OP_AW_LMTST) |
177 : : ((partial_line - 1) << 4);
178 : : }
179 : : } else {
180 : : lines -= 1;
181 : : wdata[0] |= partial_line ? (uint64_t)(lines + 1) << 12 :
182 : : (uint64_t)(lines << 12);
183 : : wdata[0] |= partial_line ?
184 : : vector_size_partial_mask(VECTOR_GET_LINE_OFFSET(lines),
185 : : partial_line) :
186 : : VECTOR_SIZE_BITS;
187 : 0 : sz0 += partial_line;
188 : : }
189 : 0 : sz1 = burst - sz0;
190 : : partial_line = 0;
191 : : }
192 : :
193 : : /* Only partial lines */
194 [ # # ]: 0 : if (partial_line) {
195 : : wdata[0] = lmt_id;
196 : : pa[0] = (ws->grp_base + (queue_id << 12) + SSO_LF_GGRP_OP_AW_LMTST) |
197 : : ((partial_line - 1) << 4);
198 : : sz0 = partial_line;
199 : 0 : sz1 = burst - sz0;
200 : : }
201 : :
202 : : #if defined(RTE_ARCH_ARM64)
203 : : uint64x2_t aw_mask = {0xC0FFFFFFFFULL, ~0x0ULL};
204 : : uint64x2_t tt_mask = {0x300000000ULL, 0};
205 : : uint16_t parts;
206 : :
207 : : while (burst) {
208 : : parts = burst > 7 ? 8 : plt_align32prevpow2(burst);
209 : : burst -= parts;
210 : : /* Lets try to fill at least one line per burst. */
211 : : switch (parts) {
212 : : case 8: {
213 : : uint64x2_t aw0, aw1, aw2, aw3, aw4, aw5, aw6, aw7;
214 : :
215 : : aw0 = vandq_u64(vld1q_u64((const uint64_t *)&ev[0]), aw_mask);
216 : : aw1 = vandq_u64(vld1q_u64((const uint64_t *)&ev[1]), aw_mask);
217 : : aw2 = vandq_u64(vld1q_u64((const uint64_t *)&ev[2]), aw_mask);
218 : : aw3 = vandq_u64(vld1q_u64((const uint64_t *)&ev[3]), aw_mask);
219 : : aw4 = vandq_u64(vld1q_u64((const uint64_t *)&ev[4]), aw_mask);
220 : : aw5 = vandq_u64(vld1q_u64((const uint64_t *)&ev[5]), aw_mask);
221 : : aw6 = vandq_u64(vld1q_u64((const uint64_t *)&ev[6]), aw_mask);
222 : : aw7 = vandq_u64(vld1q_u64((const uint64_t *)&ev[7]), aw_mask);
223 : :
224 : : aw0 = vorrq_u64(vandq_u64(vshrq_n_u64(aw0, 6), tt_mask), aw0);
225 : : aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
226 : : aw2 = vorrq_u64(vandq_u64(vshrq_n_u64(aw2, 6), tt_mask), aw2);
227 : : aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
228 : : aw4 = vorrq_u64(vandq_u64(vshrq_n_u64(aw4, 6), tt_mask), aw4);
229 : : aw5 = vorrq_u64(vandq_u64(vshrq_n_u64(aw5, 6), tt_mask), aw5);
230 : : aw6 = vorrq_u64(vandq_u64(vshrq_n_u64(aw6, 6), tt_mask), aw6);
231 : : aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
232 : :
233 : : vst1q_u64((void *)lmt_addr, aw0);
234 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
235 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
236 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
237 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
238 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
239 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
240 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
241 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
242 : : } break;
243 : : case 4: {
244 : : uint64x2_t aw0, aw1, aw2, aw3;
245 : : aw0 = vandq_u64(vld1q_u64((const uint64_t *)&ev[0]), aw_mask);
246 : : aw1 = vandq_u64(vld1q_u64((const uint64_t *)&ev[1]), aw_mask);
247 : : aw2 = vandq_u64(vld1q_u64((const uint64_t *)&ev[2]), aw_mask);
248 : : aw3 = vandq_u64(vld1q_u64((const uint64_t *)&ev[3]), aw_mask);
249 : :
250 : : aw0 = vorrq_u64(vandq_u64(vshrq_n_u64(aw0, 6), tt_mask), aw0);
251 : : aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
252 : : aw2 = vorrq_u64(vandq_u64(vshrq_n_u64(aw2, 6), tt_mask), aw2);
253 : : aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
254 : :
255 : : vst1q_u64((void *)lmt_addr, aw0);
256 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
257 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
258 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
259 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
260 : : } break;
261 : : case 2: {
262 : : uint64x2_t aw0, aw1;
263 : :
264 : : aw0 = vandq_u64(vld1q_u64((const uint64_t *)&ev[0]), aw_mask);
265 : : aw1 = vandq_u64(vld1q_u64((const uint64_t *)&ev[1]), aw_mask);
266 : :
267 : : aw0 = vorrq_u64(vandq_u64(vshrq_n_u64(aw0, 6), tt_mask), aw0);
268 : : aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
269 : :
270 : : vst1q_u64((void *)lmt_addr, aw0);
271 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
272 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
273 : : } break;
274 : : case 1: {
275 : : __uint128_t aw0;
276 : :
277 : : aw0 = ev[0].u64;
278 : : aw0 <<= 64;
279 : : aw0 |= ev[0].event & (BIT_ULL(32) - 1);
280 : : aw0 |= (uint64_t)ev[0].sched_type << 32;
281 : :
282 : : *((__uint128_t *)lmt_addr) = aw0;
283 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
284 : : } break;
285 : : }
286 : : ev += parts;
287 : : }
288 : : #else
289 : : uint16_t i;
290 : :
291 [ # # ]: 0 : for (i = 0; i < burst; i++) {
292 : : __uint128_t aw0;
293 : :
294 : 0 : aw0 = ev[0].u64;
295 : 0 : aw0 <<= 64;
296 : 0 : aw0 |= ev[0].event & (BIT_ULL(32) - 1);
297 : 0 : aw0 |= (uint64_t)ev[0].sched_type << 32;
298 : 0 : *((__uint128_t *)lmt_addr) = aw0;
299 : 0 : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
300 : : }
301 : : #endif
302 : :
303 : : /* wdata[0] will be always valid */
304 : 0 : sso_lmt_aw_wait_fc(ws, sz0);
305 : : roc_lmt_submit_steorl(wdata[0], pa[0]);
306 [ # # ]: 0 : if (wdata[1]) {
307 : 0 : sso_lmt_aw_wait_fc(ws, sz1);
308 : : roc_lmt_submit_steorl(wdata[1], pa[1]);
309 : : }
310 : :
311 : 0 : left -= (sz0 + sz1);
312 [ # # ]: 0 : if (left)
313 : 0 : goto again;
314 : :
315 : : return n;
316 : : }
317 : :
318 : : uint16_t __rte_hot
319 : 0 : cn20k_sso_hws_enq_burst(void *port, const struct rte_event ev[], uint16_t nb_events)
320 : : {
321 : : struct cn20k_sso_hws *ws = port;
322 : :
323 : : RTE_SET_USED(nb_events);
324 [ # # # # ]: 0 : switch (ev->op) {
325 : : case RTE_EVENT_OP_NEW:
326 : 0 : return cn20k_sso_hws_new_event(ws, ev);
327 : : case RTE_EVENT_OP_FORWARD:
328 : : cn20k_sso_hws_forward_event(ws, ev);
329 : : break;
330 : 0 : case RTE_EVENT_OP_RELEASE:
331 [ # # ]: 0 : if (ws->swtag_req) {
332 : 0 : cnxk_sso_hws_desched(ev->u64, ws->base);
333 : 0 : ws->swtag_req = 0;
334 : 0 : break;
335 : : }
336 : 0 : cnxk_sso_hws_swtag_flush(ws->base);
337 : : break;
338 : : default:
339 : : return 0;
340 : : }
341 : :
342 : : return 1;
343 : : }
344 : :
345 : : uint16_t __rte_hot
346 : 0 : cn20k_sso_hws_enq_new_burst(void *port, const struct rte_event ev[], uint16_t nb_events)
347 : : {
348 : : uint16_t idx = 0, done = 0, rc = 0;
349 : : struct cn20k_sso_hws *ws = port;
350 : : uint8_t queue_id;
351 : : int32_t space;
352 : :
353 : : /* Do a common back-pressure check and return */
354 : 0 : space = sso_read_xaq_space(ws) - ws->xae_waes;
355 [ # # ]: 0 : if (space <= 0)
356 : : return 0;
357 : 0 : nb_events = space < nb_events ? space : nb_events;
358 : :
359 : : do {
360 : 0 : queue_id = ev[idx].queue_id;
361 [ # # ]: 0 : for (idx = idx + 1; idx < nb_events; idx++)
362 [ # # ]: 0 : if (queue_id != ev[idx].queue_id)
363 : : break;
364 : :
365 : 0 : rc = cn20k_sso_hws_new_event_lmtst(ws, queue_id, &ev[done], idx - done);
366 [ # # ]: 0 : if (rc != (idx - done))
367 : 0 : return rc + done;
368 : : done += rc;
369 : :
370 [ # # ]: 0 : } while (done < nb_events);
371 : :
372 : : return done;
373 : : }
374 : :
375 : : uint16_t __rte_hot
376 [ # # ]: 0 : cn20k_sso_hws_enq_fwd_burst(void *port, const struct rte_event ev[], uint16_t nb_events)
377 : : {
378 : : struct cn20k_sso_hws *ws = port;
379 : :
380 : : RTE_SET_USED(nb_events);
381 : : cn20k_sso_hws_forward_event(ws, ev);
382 : :
383 : 0 : return 1;
384 : : }
385 : :
386 : : int __rte_hot
387 : 0 : cn20k_sso_hws_profile_switch(void *port, uint8_t profile)
388 : : {
389 : : struct cn20k_sso_hws *ws = port;
390 : :
391 : 0 : ws->gw_wdata &= ~(0xFFUL);
392 : 0 : ws->gw_wdata |= (profile + 1);
393 : :
394 : 0 : return 0;
395 : : }
396 : :
397 : : int __rte_hot
398 : 0 : cn20k_sso_hws_preschedule_modify(void *port, enum rte_event_dev_preschedule_type type)
399 : : {
400 : : struct cn20k_sso_hws *ws = port;
401 : :
402 : 0 : ws->gw_wdata &= ~(BIT(19) | BIT(20));
403 [ # # # ]: 0 : switch (type) {
404 : : default:
405 : : case RTE_EVENT_PRESCHEDULE_NONE:
406 : : break;
407 : 0 : case RTE_EVENT_PRESCHEDULE:
408 : 0 : ws->gw_wdata |= BIT(19);
409 : 0 : break;
410 : 0 : case RTE_EVENT_PRESCHEDULE_ADAPTIVE:
411 : 0 : ws->gw_wdata |= BIT(19) | BIT(20);
412 : 0 : break;
413 : : }
414 : :
415 : 0 : return 0;
416 : : }
417 : :
418 : : void __rte_hot
419 : 0 : cn20k_sso_hws_preschedule(void *port, enum rte_event_dev_preschedule_type type)
420 : : {
421 : : struct cn20k_sso_hws *ws = port;
422 : :
423 : : RTE_SET_USED(type);
424 : 0 : plt_write64(ws->gw_wdata, ws->base + SSOW_LF_GWS_OP_PRF_GETWORK);
425 : 0 : }
|