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