Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : :
5 : : #include "roc_api.h"
6 : :
7 : : #include "cn10k_worker.h"
8 : : #include "cnxk_eventdev.h"
9 : : #include "cnxk_worker.h"
10 : :
11 : : /* SSO Operations */
12 : :
13 : : static __rte_always_inline uint8_t
14 : : cn10k_sso_hws_new_event(struct cn10k_sso_hws *ws, const struct rte_event *ev)
15 : : {
16 : 0 : const uint32_t tag = (uint32_t)ev->event;
17 : 0 : const uint8_t new_tt = ev->sched_type;
18 : 0 : const uint64_t event_ptr = ev->u64;
19 [ # # ]: 0 : const uint16_t grp = ev->queue_id;
20 : :
21 : : rte_atomic_thread_fence(rte_memory_order_acq_rel);
22 [ # # ]: 0 : if (ws->xaq_lmt <= *ws->fc_mem)
23 : : return 0;
24 : :
25 : 0 : cnxk_sso_hws_add_work(event_ptr, tag, new_tt, ws->grp_base + (grp << 12));
26 : 0 : return 1;
27 : : }
28 : :
29 : : static __rte_always_inline void
30 : : cn10k_sso_hws_fwd_swtag(struct cn10k_sso_hws *ws, const struct rte_event *ev)
31 : : {
32 : 0 : const uint32_t tag = (uint32_t)ev->event;
33 : 0 : const uint8_t new_tt = ev->sched_type;
34 : 0 : const uint8_t cur_tt = CNXK_TT_FROM_TAG(ws->gw_rdata);
35 : :
36 : : /* CNXK model
37 : : * cur_tt/new_tt SSO_TT_ORDERED SSO_TT_ATOMIC SSO_TT_UNTAGGED
38 : : *
39 : : * SSO_TT_ORDERED norm norm untag
40 : : * SSO_TT_ATOMIC norm norm untag
41 : : * SSO_TT_UNTAGGED norm norm NOOP
42 : : */
43 : :
44 [ # # # # ]: 0 : if (new_tt == SSO_TT_UNTAGGED) {
45 [ # # # # ]: 0 : if (cur_tt != SSO_TT_UNTAGGED)
46 : 0 : cnxk_sso_hws_swtag_untag(ws->base + SSOW_LF_GWS_OP_SWTAG_UNTAG);
47 : : } else {
48 : 0 : cnxk_sso_hws_swtag_norm(tag, new_tt, ws->base + SSOW_LF_GWS_OP_SWTAG_NORM);
49 : : }
50 : 0 : ws->swtag_req = 1;
51 : 0 : }
52 : :
53 : : static __rte_always_inline void
54 : : cn10k_sso_hws_fwd_group(struct cn10k_sso_hws *ws, const struct rte_event *ev,
55 : : const uint16_t grp)
56 : : {
57 : 0 : const uint32_t tag = (uint32_t)ev->event;
58 : 0 : const uint8_t new_tt = ev->sched_type;
59 : :
60 : 0 : plt_write64(ev->u64, ws->base + SSOW_LF_GWS_OP_UPD_WQP_GRP1);
61 : 0 : cnxk_sso_hws_swtag_desched(tag, new_tt, grp, ws->base + SSOW_LF_GWS_OP_SWTAG_DESCHED);
62 : 0 : }
63 : :
64 : : static __rte_always_inline void
65 : : cn10k_sso_hws_forward_event(struct cn10k_sso_hws *ws,
66 : : 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 : : cn10k_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 : : cn10k_sso_hws_fwd_group(ws, ev, grp);
80 : : }
81 : :
82 : : static inline int32_t
83 : : sso_read_xaq_space(struct cn10k_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 cn10k_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 : 0 : goto retry;
110 : : }
111 : 0 : }
112 : :
113 : : #define VECTOR_SIZE_BITS 0xFFFFFFFFFFF80000ULL
114 : : #define VECTOR_GET_LINE_OFFSET(line) (19 + (3 * line))
115 : :
116 : : static uint64_t
117 : : vector_size_partial_mask(uint16_t off, uint16_t cnt)
118 : : {
119 : 0 : return (VECTOR_SIZE_BITS & ~(~0x0ULL << off)) |
120 : 0 : ((uint64_t)(cnt - 1) << off);
121 : : }
122 : :
123 : : static __rte_always_inline uint16_t
124 : : cn10k_sso_hws_new_event_lmtst(struct cn10k_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->lmt_base;
135 : : ROC_LMT_BASE_ID_GET(lmt_addr, lmt_id);
136 : :
137 : : left = n;
138 : 0 : again:
139 : 0 : burst = RTE_MIN(
140 : : BIT(ROC_SSO_AW_PER_LMT_LINE_LOG2 + ROC_LMT_LINES_PER_CORE_LOG2),
141 : : left);
142 : :
143 : : /* Set wdata */
144 : 0 : lines = burst >> ROC_SSO_AW_PER_LMT_LINE_LOG2;
145 : 0 : partial_line = burst & (BIT(ROC_SSO_AW_PER_LMT_LINE_LOG2) - 1);
146 : : wdata[0] = wdata[1] = 0;
147 [ # # ]: 0 : if (lines > BIT(ROC_LMT_LINES_PER_STR_LOG2)) {
148 : : wdata[0] = lmt_id;
149 : : wdata[0] |= 15ULL << 12;
150 : : wdata[0] |= VECTOR_SIZE_BITS;
151 : : pa[0] = (ws->grp_base + (queue_id << 12) +
152 : : SSO_LF_GGRP_OP_AW_LMTST) |
153 : : (0x7 << 4);
154 : : sz0 = 16 << ROC_SSO_AW_PER_LMT_LINE_LOG2;
155 : :
156 : : wdata[1] = lmt_id + 16;
157 : : pa[1] = (ws->grp_base + (queue_id << 12) +
158 : : SSO_LF_GGRP_OP_AW_LMTST) |
159 : : (0x7 << 4);
160 : :
161 : 0 : lines -= 17;
162 [ # # ]: 0 : wdata[1] |= partial_line ? (uint64_t)(lines + 1) << 12 :
163 : 0 : (uint64_t)(lines << 12);
164 : 0 : wdata[1] |= partial_line ?
165 : 0 : vector_size_partial_mask(
166 : 0 : VECTOR_GET_LINE_OFFSET(lines),
167 [ # # ]: 0 : partial_line) :
168 : : VECTOR_SIZE_BITS;
169 : 0 : sz1 = burst - sz0;
170 : : partial_line = 0;
171 [ # # ]: 0 : } else if (lines) {
172 : : /* We need to handle two cases here:
173 : : * 1. Partial line spill over to wdata[1] i.e. lines == 16
174 : : * 2. Partial line with spill lines < 16.
175 : : */
176 : : wdata[0] = lmt_id;
177 : : pa[0] = (ws->grp_base + (queue_id << 12) +
178 : : SSO_LF_GGRP_OP_AW_LMTST) |
179 : : (0x7 << 4);
180 : 0 : sz0 = lines << ROC_SSO_AW_PER_LMT_LINE_LOG2;
181 [ # # ]: 0 : if (lines == 16) {
182 : : wdata[0] |= 15ULL << 12;
183 : : wdata[0] |= VECTOR_SIZE_BITS;
184 [ # # ]: 0 : if (partial_line) {
185 : : wdata[1] = lmt_id + 16;
186 : : pa[1] = (ws->grp_base + (queue_id << 12) +
187 : : SSO_LF_GGRP_OP_AW_LMTST) |
188 : : ((partial_line - 1) << 4);
189 : : }
190 : : } else {
191 : : lines -= 1;
192 : : wdata[0] |= partial_line ? (uint64_t)(lines + 1) << 12 :
193 : : (uint64_t)(lines << 12);
194 : : wdata[0] |=
195 : : partial_line ?
196 : : vector_size_partial_mask(
197 : : VECTOR_GET_LINE_OFFSET(lines),
198 : : partial_line) :
199 : : VECTOR_SIZE_BITS;
200 : 0 : sz0 += partial_line;
201 : : }
202 : 0 : sz1 = burst - sz0;
203 : : partial_line = 0;
204 : : }
205 : :
206 : : /* Only partial lines */
207 [ # # ]: 0 : if (partial_line) {
208 : : wdata[0] = lmt_id;
209 : : pa[0] = (ws->grp_base + (queue_id << 12) +
210 : : SSO_LF_GGRP_OP_AW_LMTST) |
211 : : ((partial_line - 1) << 4);
212 : : sz0 = partial_line;
213 : 0 : sz1 = burst - sz0;
214 : : }
215 : :
216 : : #if defined(RTE_ARCH_ARM64)
217 : : uint64x2_t aw_mask = {0xC0FFFFFFFFULL, ~0x0ULL};
218 : : uint64x2_t tt_mask = {0x300000000ULL, 0};
219 : : uint16_t parts;
220 : :
221 : : while (burst) {
222 : : parts = burst > 7 ? 8 : plt_align32prevpow2(burst);
223 : : burst -= parts;
224 : : /* Lets try to fill at least one line per burst. */
225 : : switch (parts) {
226 : : case 8: {
227 : : uint64x2_t aw0, aw1, aw2, aw3, aw4, aw5, aw6, aw7;
228 : :
229 : : aw0 = vandq_u64(vld1q_u64((const uint64_t *)&ev[0]),
230 : : aw_mask);
231 : : aw1 = vandq_u64(vld1q_u64((const uint64_t *)&ev[1]),
232 : : aw_mask);
233 : : aw2 = vandq_u64(vld1q_u64((const uint64_t *)&ev[2]),
234 : : aw_mask);
235 : : aw3 = vandq_u64(vld1q_u64((const uint64_t *)&ev[3]),
236 : : aw_mask);
237 : : aw4 = vandq_u64(vld1q_u64((const uint64_t *)&ev[4]),
238 : : aw_mask);
239 : : aw5 = vandq_u64(vld1q_u64((const uint64_t *)&ev[5]),
240 : : aw_mask);
241 : : aw6 = vandq_u64(vld1q_u64((const uint64_t *)&ev[6]),
242 : : aw_mask);
243 : : aw7 = vandq_u64(vld1q_u64((const uint64_t *)&ev[7]),
244 : : aw_mask);
245 : :
246 : : aw0 = vorrq_u64(vandq_u64(vshrq_n_u64(aw0, 6), tt_mask),
247 : : aw0);
248 : : aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask),
249 : : aw1);
250 : : aw2 = vorrq_u64(vandq_u64(vshrq_n_u64(aw2, 6), tt_mask),
251 : : aw2);
252 : : aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask),
253 : : aw3);
254 : : aw4 = vorrq_u64(vandq_u64(vshrq_n_u64(aw4, 6), tt_mask),
255 : : aw4);
256 : : aw5 = vorrq_u64(vandq_u64(vshrq_n_u64(aw5, 6), tt_mask),
257 : : aw5);
258 : : aw6 = vorrq_u64(vandq_u64(vshrq_n_u64(aw6, 6), tt_mask),
259 : : aw6);
260 : : aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask),
261 : : aw7);
262 : :
263 : : vst1q_u64((void *)lmt_addr, aw0);
264 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
265 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
266 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
267 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
268 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
269 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
270 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
271 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
272 : : } break;
273 : : case 4: {
274 : : uint64x2_t aw0, aw1, aw2, aw3;
275 : : aw0 = vandq_u64(vld1q_u64((const uint64_t *)&ev[0]),
276 : : aw_mask);
277 : : aw1 = vandq_u64(vld1q_u64((const uint64_t *)&ev[1]),
278 : : aw_mask);
279 : : aw2 = vandq_u64(vld1q_u64((const uint64_t *)&ev[2]),
280 : : aw_mask);
281 : : aw3 = vandq_u64(vld1q_u64((const uint64_t *)&ev[3]),
282 : : aw_mask);
283 : :
284 : : aw0 = vorrq_u64(vandq_u64(vshrq_n_u64(aw0, 6), tt_mask),
285 : : aw0);
286 : : aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask),
287 : : aw1);
288 : : aw2 = vorrq_u64(vandq_u64(vshrq_n_u64(aw2, 6), tt_mask),
289 : : aw2);
290 : : aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask),
291 : : aw3);
292 : :
293 : : vst1q_u64((void *)lmt_addr, aw0);
294 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
295 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
296 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
297 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
298 : : } break;
299 : : case 2: {
300 : : uint64x2_t aw0, aw1;
301 : :
302 : : aw0 = vandq_u64(vld1q_u64((const uint64_t *)&ev[0]),
303 : : aw_mask);
304 : : aw1 = vandq_u64(vld1q_u64((const uint64_t *)&ev[1]),
305 : : aw_mask);
306 : :
307 : : aw0 = vorrq_u64(vandq_u64(vshrq_n_u64(aw0, 6), tt_mask),
308 : : aw0);
309 : : aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask),
310 : : aw1);
311 : :
312 : : vst1q_u64((void *)lmt_addr, aw0);
313 : : vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
314 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
315 : : } break;
316 : : case 1: {
317 : : __uint128_t aw0;
318 : :
319 : : aw0 = ev[0].u64;
320 : : aw0 <<= 64;
321 : : aw0 |= ev[0].event & (BIT_ULL(32) - 1);
322 : : aw0 |= (uint64_t)ev[0].sched_type << 32;
323 : :
324 : : *((__uint128_t *)lmt_addr) = aw0;
325 : : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
326 : : } break;
327 : : }
328 : : ev += parts;
329 : : }
330 : : #else
331 : : uint16_t i;
332 : :
333 [ # # ]: 0 : for (i = 0; i < burst; i++) {
334 : : __uint128_t aw0;
335 : :
336 : 0 : aw0 = ev[0].u64;
337 : 0 : aw0 <<= 64;
338 : 0 : aw0 |= ev[0].event & (BIT_ULL(32) - 1);
339 : 0 : aw0 |= (uint64_t)ev[0].sched_type << 32;
340 : 0 : *((__uint128_t *)lmt_addr) = aw0;
341 : 0 : lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
342 : : }
343 : : #endif
344 : :
345 : : /* wdata[0] will be always valid */
346 : 0 : sso_lmt_aw_wait_fc(ws, sz0);
347 : : roc_lmt_submit_steorl(wdata[0], pa[0]);
348 [ # # ]: 0 : if (wdata[1]) {
349 : 0 : sso_lmt_aw_wait_fc(ws, sz1);
350 : : roc_lmt_submit_steorl(wdata[1], pa[1]);
351 : : }
352 : :
353 : 0 : left -= (sz0 + sz1);
354 [ # # ]: 0 : if (left)
355 : 0 : goto again;
356 : :
357 : : return n;
358 : : }
359 : :
360 : : uint16_t __rte_hot
361 : 0 : cn10k_sso_hws_enq_burst(void *port, const struct rte_event ev[],
362 : : uint16_t nb_events)
363 : : {
364 : : struct cn10k_sso_hws *ws = port;
365 : :
366 : : RTE_SET_USED(nb_events);
367 : :
368 [ # # # # ]: 0 : switch (ev->op) {
369 : : case RTE_EVENT_OP_NEW:
370 : 0 : return cn10k_sso_hws_new_event(ws, ev);
371 : : case RTE_EVENT_OP_FORWARD:
372 : : cn10k_sso_hws_forward_event(ws, ev);
373 : : break;
374 : 0 : case RTE_EVENT_OP_RELEASE:
375 [ # # ]: 0 : if (ws->swtag_req) {
376 : 0 : cnxk_sso_hws_desched(ev->u64, ws->base);
377 : 0 : ws->swtag_req = 0;
378 : 0 : break;
379 : : }
380 : 0 : cnxk_sso_hws_swtag_flush(ws->base);
381 : : break;
382 : : default:
383 : : return 0;
384 : : }
385 : :
386 : : return 1;
387 : : }
388 : :
389 : : uint16_t __rte_hot
390 : 0 : cn10k_sso_hws_enq_new_burst(void *port, const struct rte_event ev[],
391 : : uint16_t nb_events)
392 : : {
393 : : uint16_t idx = 0, done = 0, rc = 0;
394 : : struct cn10k_sso_hws *ws = port;
395 : : uint8_t queue_id;
396 : : int32_t space;
397 : :
398 : : /* Do a common back-pressure check and return */
399 : 0 : space = sso_read_xaq_space(ws) - ws->xae_waes;
400 [ # # ]: 0 : if (space <= 0)
401 : : return 0;
402 : 0 : nb_events = space < nb_events ? space : nb_events;
403 : :
404 : : do {
405 : 0 : queue_id = ev[idx].queue_id;
406 [ # # ]: 0 : for (idx = idx + 1; idx < nb_events; idx++)
407 [ # # ]: 0 : if (queue_id != ev[idx].queue_id)
408 : : break;
409 : :
410 : 0 : rc = cn10k_sso_hws_new_event_lmtst(ws, queue_id, &ev[done],
411 : 0 : idx - done);
412 [ # # ]: 0 : if (rc != (idx - done))
413 : 0 : return rc + done;
414 : : done += rc;
415 : :
416 [ # # ]: 0 : } while (done < nb_events);
417 : :
418 : : return done;
419 : : }
420 : :
421 : : uint16_t __rte_hot
422 [ # # ]: 0 : cn10k_sso_hws_enq_fwd_burst(void *port, const struct rte_event ev[],
423 : : uint16_t nb_events)
424 : : {
425 : : struct cn10k_sso_hws *ws = port;
426 : :
427 : : RTE_SET_USED(nb_events);
428 : : cn10k_sso_hws_forward_event(ws, ev);
429 : :
430 : 0 : return 1;
431 : : }
432 : :
433 : : int __rte_hot
434 : 0 : cn10k_sso_hws_profile_switch(void *port, uint8_t profile)
435 : : {
436 : : struct cn10k_sso_hws *ws = port;
437 : :
438 : 0 : ws->gw_wdata &= ~(0xFFUL);
439 : 0 : ws->gw_wdata |= (profile + 1);
440 : :
441 : 0 : return 0;
442 : : }
443 : :
444 : : int __rte_hot
445 : 0 : cn10k_sso_hws_preschedule_modify(void *port, enum rte_event_dev_preschedule_type type)
446 : : {
447 : : struct cn10k_sso_hws *ws = port;
448 : :
449 : 0 : ws->gw_wdata &= ~(BIT(19) | BIT(20));
450 [ # # # ]: 0 : switch (type) {
451 : : default:
452 : : case RTE_EVENT_PRESCHEDULE_NONE:
453 : : break;
454 : 0 : case RTE_EVENT_PRESCHEDULE:
455 : 0 : ws->gw_wdata |= BIT(19);
456 : 0 : break;
457 : 0 : case RTE_EVENT_PRESCHEDULE_ADAPTIVE:
458 : 0 : ws->gw_wdata |= BIT(19) | BIT(20);
459 : 0 : break;
460 : : }
461 : :
462 : 0 : return 0;
463 : : }
|