Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdlib.h>
6 : :
7 : : #include <rte_common.h>
8 : : #include <rte_cycles.h>
9 : : #include <rte_lcore.h>
10 : : #include <rte_service_component.h>
11 : : #include <rte_ring.h>
12 : :
13 : : #include "rte_eth_softnic_internals.h"
14 : :
15 : : /**
16 : : * Main thread: data plane thread init
17 : : */
18 : : void
19 : 0 : softnic_thread_free(struct pmd_internals *softnic)
20 : : {
21 : : uint32_t i;
22 : :
23 [ # # ]: 0 : RTE_LCORE_FOREACH_WORKER(i) {
24 : : struct softnic_thread *t = &softnic->thread[i];
25 : :
26 : : /* MSGQs */
27 : 0 : rte_ring_free(t->msgq_req);
28 : :
29 : 0 : rte_ring_free(t->msgq_rsp);
30 : : }
31 : 0 : }
32 : :
33 : : int
34 : 0 : softnic_thread_init(struct pmd_internals *softnic)
35 : : {
36 : : uint32_t i;
37 : :
38 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE; i++) {
39 : : char ring_name[NAME_MAX];
40 : : struct rte_ring *msgq_req, *msgq_rsp;
41 : : struct softnic_thread *t = &softnic->thread[i];
42 : : struct softnic_thread_data *t_data = &softnic->thread_data[i];
43 : 0 : uint32_t cpu_id = rte_lcore_to_socket_id(i);
44 : :
45 : : /* MSGQs */
46 : : snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ",
47 : 0 : softnic->params.name,
48 : : i);
49 : :
50 : 0 : msgq_req = rte_ring_create(ring_name,
51 : : THREAD_MSGQ_SIZE,
52 : : cpu_id,
53 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
54 : :
55 [ # # ]: 0 : if (msgq_req == NULL) {
56 : 0 : softnic_thread_free(softnic);
57 : 0 : return -1;
58 : : }
59 : :
60 : : snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP",
61 : : softnic->params.name,
62 : : i);
63 : :
64 : 0 : msgq_rsp = rte_ring_create(ring_name,
65 : : THREAD_MSGQ_SIZE,
66 : : cpu_id,
67 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
68 : :
69 [ # # ]: 0 : if (msgq_rsp == NULL) {
70 : 0 : softnic_thread_free(softnic);
71 : 0 : return -1;
72 : : }
73 : :
74 : : /* Main thread records */
75 : 0 : t->msgq_req = msgq_req;
76 : 0 : t->msgq_rsp = msgq_rsp;
77 : 0 : t->service_id = UINT32_MAX;
78 : :
79 : : /* Data plane thread records */
80 : 0 : t_data->n_pipelines = 0;
81 : 0 : t_data->msgq_req = msgq_req;
82 : 0 : t_data->msgq_rsp = msgq_rsp;
83 : 0 : t_data->timer_period =
84 : 0 : (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
85 : 0 : t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
86 : : }
87 : :
88 : : return 0;
89 : : }
90 : :
91 : : static inline int
92 : 0 : thread_is_valid(struct pmd_internals *softnic, uint32_t thread_id)
93 : : {
94 [ # # ]: 0 : if (thread_id >= RTE_MAX_LCORE)
95 : : return 0; /* FALSE */
96 : :
97 [ # # ]: 0 : if (thread_id == rte_get_main_lcore())
98 : : return 0; /* FALSE */
99 : :
100 [ # # # # ]: 0 : if (softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_SERVICE))
101 : : return 1; /* TRUE */
102 [ # # # # ]: 0 : if (!softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_RTE))
103 : 0 : return 1; /* TRUE */
104 : :
105 : : return 0; /* FALSE */
106 : : }
107 : :
108 : : static inline int
109 : : thread_is_running(uint32_t thread_id)
110 : : {
111 : : enum rte_lcore_state_t thread_state;
112 : :
113 : 0 : thread_state = rte_eal_get_lcore_state(thread_id);
114 : : return (thread_state == RUNNING)? 1 : 0;
115 : : }
116 : :
117 : : static int32_t
118 : : rte_pmd_softnic_run_internal(void *arg);
119 : :
120 : : static inline int
121 : 0 : thread_sc_service_up(struct pmd_internals *softnic, uint32_t thread_id)
122 : : {
123 : : struct rte_service_spec service_params;
124 : : struct softnic_thread *t = &softnic->thread[thread_id];
125 : : struct rte_eth_dev *dev;
126 : : int status;
127 : :
128 : : /* service params */
129 : 0 : dev = rte_eth_dev_get_by_name(softnic->params.name);
130 [ # # ]: 0 : if (!dev)
131 : : return -EINVAL;
132 : :
133 : : snprintf(service_params.name, sizeof(service_params.name), "%s_%u",
134 : : softnic->params.name,
135 : : thread_id);
136 : 0 : service_params.callback = rte_pmd_softnic_run_internal;
137 : 0 : service_params.callback_userdata = dev;
138 : 0 : service_params.capabilities = 0;
139 : 0 : service_params.socket_id = (int)softnic->params.cpu_id;
140 : :
141 : : /* service register */
142 : 0 : status = rte_service_component_register(&service_params, &t->service_id);
143 [ # # ]: 0 : if (status)
144 : : return status;
145 : :
146 : 0 : status = rte_service_component_runstate_set(t->service_id, 1);
147 [ # # ]: 0 : if (status) {
148 : 0 : rte_service_component_unregister(t->service_id);
149 : 0 : t->service_id = UINT32_MAX;
150 : 0 : return status;
151 : : }
152 : :
153 : 0 : status = rte_service_runstate_set(t->service_id, 1);
154 [ # # ]: 0 : if (status) {
155 : 0 : rte_service_component_runstate_set(t->service_id, 0);
156 : 0 : rte_service_component_unregister(t->service_id);
157 : 0 : t->service_id = UINT32_MAX;
158 : 0 : return status;
159 : : }
160 : :
161 : : /* service map to thread */
162 : 0 : status = rte_service_map_lcore_set(t->service_id, thread_id, 1);
163 [ # # ]: 0 : if (status) {
164 : 0 : rte_service_runstate_set(t->service_id, 0);
165 : 0 : rte_service_component_runstate_set(t->service_id, 0);
166 : 0 : rte_service_component_unregister(t->service_id);
167 : 0 : t->service_id = UINT32_MAX;
168 : 0 : return status;
169 : : }
170 : :
171 : : return 0;
172 : : }
173 : :
174 : : static inline void
175 : 0 : thread_sc_service_down(struct pmd_internals *softnic, uint32_t thread_id)
176 : : {
177 : : struct softnic_thread *t = &softnic->thread[thread_id];
178 : :
179 : : /* service unmap from thread */
180 : 0 : rte_service_map_lcore_set(t->service_id, thread_id, 0);
181 : :
182 : : /* service unregister */
183 : 0 : rte_service_runstate_set(t->service_id, 0);
184 : 0 : rte_service_component_runstate_set(t->service_id, 0);
185 : 0 : rte_service_component_unregister(t->service_id);
186 : :
187 : 0 : t->service_id = UINT32_MAX;
188 : 0 : }
189 : :
190 : : void
191 : 0 : softnic_thread_pipeline_disable_all(struct pmd_internals *softnic)
192 : : {
193 : : uint32_t thread_id;
194 : :
195 [ # # ]: 0 : for (thread_id = 0; thread_id < RTE_MAX_LCORE; thread_id++) {
196 : : struct softnic_thread_data *td = &softnic->thread_data[thread_id];
197 : :
198 [ # # ]: 0 : if (!thread_is_valid(softnic, thread_id))
199 : 0 : continue;
200 : :
201 [ # # # # ]: 0 : if (softnic->params.sc && td->n_pipelines)
202 : 0 : thread_sc_service_down(softnic, thread_id);
203 : :
204 : 0 : td->n_pipelines = 0;
205 : : }
206 : 0 : }
207 : :
208 : : /**
209 : : * Main thread & data plane threads: message passing
210 : : */
211 : : enum thread_req_type {
212 : : THREAD_REQ_PIPELINE_ENABLE = 0,
213 : : THREAD_REQ_PIPELINE_DISABLE,
214 : : THREAD_REQ_MAX
215 : : };
216 : :
217 : : struct thread_msg_req {
218 : : enum thread_req_type type;
219 : :
220 : : union {
221 : : struct {
222 : : struct rte_swx_pipeline *p;
223 : : } pipeline_enable;
224 : :
225 : : struct {
226 : : struct rte_swx_pipeline *p;
227 : : } pipeline_disable;
228 : : };
229 : : };
230 : :
231 : : struct thread_msg_rsp {
232 : : int status;
233 : : };
234 : :
235 : : /**
236 : : * Main thread
237 : : */
238 : : static struct thread_msg_req *
239 : : thread_msg_alloc(void)
240 : : {
241 : : size_t size = RTE_MAX(sizeof(struct thread_msg_req),
242 : : sizeof(struct thread_msg_rsp));
243 : :
244 : 0 : return calloc(1, size);
245 : : }
246 : :
247 : : static void
248 : : thread_msg_free(struct thread_msg_rsp *rsp)
249 : : {
250 : 0 : free(rsp);
251 : : }
252 : :
253 : : static struct thread_msg_rsp *
254 : 0 : thread_msg_send_recv(struct pmd_internals *softnic,
255 : : uint32_t thread_id,
256 : : struct thread_msg_req *req)
257 : : {
258 : : struct softnic_thread *t = &softnic->thread[thread_id];
259 : 0 : struct rte_ring *msgq_req = t->msgq_req;
260 : 0 : struct rte_ring *msgq_rsp = t->msgq_rsp;
261 : : struct thread_msg_rsp *rsp;
262 : : int status;
263 : :
264 : : /* send */
265 : : do {
266 : 0 : status = rte_ring_sp_enqueue(msgq_req, req);
267 : : } while (status == -ENOBUFS);
268 : :
269 : : /* recv */
270 : : do {
271 : : status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
272 : : } while (status != 0);
273 : :
274 : 0 : return rsp;
275 : : }
276 : :
277 : : int
278 : 0 : softnic_thread_pipeline_enable(struct pmd_internals *softnic,
279 : : uint32_t thread_id,
280 : : struct pipeline *p)
281 : : {
282 : : struct thread_msg_req *req;
283 : : struct thread_msg_rsp *rsp;
284 : : uint32_t n_pipelines;
285 : : int status;
286 : :
287 : : /* Check input params */
288 [ # # # # ]: 0 : if (!thread_is_valid(softnic, thread_id) ||
289 : 0 : (p == NULL) ||
290 [ # # ]: 0 : p->enabled)
291 : : return -1;
292 : :
293 : 0 : n_pipelines = softnic_pipeline_thread_count(softnic, thread_id);
294 [ # # ]: 0 : if (n_pipelines >= THREAD_PIPELINES_MAX)
295 : : return -1;
296 : :
297 [ # # # # ]: 0 : if (softnic->params.sc && (n_pipelines == 0)) {
298 : 0 : status = thread_sc_service_up(softnic, thread_id);
299 [ # # ]: 0 : if (status)
300 : : return status;
301 : : }
302 : :
303 [ # # ]: 0 : if (!thread_is_running(thread_id)) {
304 : : struct softnic_thread_data *td = &softnic->thread_data[thread_id];
305 : :
306 : : /* Data plane thread */
307 : 0 : td->p[td->n_pipelines] = p->p;
308 : 0 : td->n_pipelines++;
309 : :
310 : : /* Pipeline */
311 : 0 : p->thread_id = thread_id;
312 : 0 : p->enabled = 1;
313 : :
314 : 0 : return 0;
315 : : }
316 : :
317 : : /* Allocate request */
318 : : req = thread_msg_alloc();
319 [ # # ]: 0 : if (req == NULL)
320 : : return -1;
321 : :
322 : : /* Write request */
323 : : req->type = THREAD_REQ_PIPELINE_ENABLE;
324 : 0 : req->pipeline_enable.p = p->p;
325 : :
326 : : /* Send request and wait for response */
327 : 0 : rsp = thread_msg_send_recv(softnic, thread_id, req);
328 : :
329 : : /* Read response */
330 : 0 : status = rsp->status;
331 : :
332 : : /* Free response */
333 : : thread_msg_free(rsp);
334 : :
335 : : /* Request completion */
336 [ # # ]: 0 : if (status)
337 : : return status;
338 : :
339 : 0 : p->thread_id = thread_id;
340 : 0 : p->enabled = 1;
341 : :
342 : 0 : return 0;
343 : : }
344 : :
345 : : int
346 : 0 : softnic_thread_pipeline_disable(struct pmd_internals *softnic,
347 : : uint32_t thread_id,
348 : : struct pipeline *p)
349 : : {
350 : : struct thread_msg_req *req;
351 : : struct thread_msg_rsp *rsp;
352 : : uint32_t n_pipelines;
353 : : int status;
354 : :
355 : : /* Check input params */
356 [ # # # # ]: 0 : if (!thread_is_valid(softnic, thread_id) ||
357 : 0 : (p == NULL) ||
358 [ # # # # ]: 0 : (p->enabled && (p->thread_id != thread_id)))
359 : : return -1;
360 : :
361 [ # # ]: 0 : if (p->enabled == 0)
362 : : return 0;
363 : :
364 [ # # ]: 0 : if (!thread_is_running(thread_id)) {
365 : : struct softnic_thread_data *td = &softnic->thread_data[thread_id];
366 : : uint32_t i;
367 : :
368 [ # # ]: 0 : for (i = 0; i < td->n_pipelines; i++) {
369 [ # # ]: 0 : if (td->p[i] != p->p)
370 : : continue;
371 : :
372 : : /* Data plane thread */
373 [ # # ]: 0 : if (i < td->n_pipelines - 1)
374 : 0 : td->p[i] = td->p[td->n_pipelines - 1];
375 : :
376 : 0 : td->n_pipelines--;
377 : :
378 : : /* Pipeline */
379 : 0 : p->enabled = 0;
380 : :
381 : 0 : break;
382 : : }
383 : :
384 [ # # # # ]: 0 : if (softnic->params.sc && (td->n_pipelines == 0))
385 : 0 : thread_sc_service_down(softnic, thread_id);
386 : :
387 : 0 : return 0;
388 : : }
389 : :
390 : : /* Allocate request */
391 : : req = thread_msg_alloc();
392 [ # # ]: 0 : if (req == NULL)
393 : : return -1;
394 : :
395 : : /* Write request */
396 : 0 : req->type = THREAD_REQ_PIPELINE_DISABLE;
397 : 0 : req->pipeline_disable.p = p->p;
398 : :
399 : : /* Send request and wait for response */
400 : 0 : rsp = thread_msg_send_recv(softnic, thread_id, req);
401 : :
402 : : /* Read response */
403 : 0 : status = rsp->status;
404 : :
405 : : /* Free response */
406 : : thread_msg_free(rsp);
407 : :
408 : : /* Request completion */
409 [ # # ]: 0 : if (status)
410 : : return status;
411 : :
412 : 0 : p->enabled = 0;
413 : :
414 : 0 : n_pipelines = softnic_pipeline_thread_count(softnic, thread_id);
415 [ # # # # ]: 0 : if (softnic->params.sc && (n_pipelines == 0))
416 : 0 : thread_sc_service_down(softnic, thread_id);
417 : :
418 : : return 0;
419 : : }
420 : :
421 : : /**
422 : : * Data plane threads: message handling
423 : : */
424 : : static inline struct thread_msg_req *
425 : 0 : thread_msg_recv(struct rte_ring *msgq_req)
426 : : {
427 : : struct thread_msg_req *req;
428 : :
429 : : int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
430 : :
431 : : if (status != 0)
432 : 0 : return NULL;
433 : :
434 : 0 : return req;
435 : : }
436 : :
437 : : static inline void
438 : 0 : thread_msg_send(struct rte_ring *msgq_rsp,
439 : : struct thread_msg_rsp *rsp)
440 : : {
441 : : int status;
442 : :
443 : : do {
444 : 0 : status = rte_ring_sp_enqueue(msgq_rsp, rsp);
445 : : } while (status == -ENOBUFS);
446 : 0 : }
447 : :
448 : : static struct thread_msg_rsp *
449 : : thread_msg_handle_pipeline_enable(struct softnic_thread_data *t,
450 : : struct thread_msg_req *req)
451 : : {
452 : : struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
453 : :
454 : : /* Request */
455 : 0 : t->p[t->n_pipelines] = req->pipeline_enable.p;
456 : 0 : t->n_pipelines++;
457 : :
458 : : /* Response */
459 : 0 : rsp->status = 0;
460 : : return rsp;
461 : : }
462 : :
463 : : static struct thread_msg_rsp *
464 : : thread_msg_handle_pipeline_disable(struct softnic_thread_data *t,
465 : : struct thread_msg_req *req)
466 : : {
467 : : struct thread_msg_rsp *rsp = (struct thread_msg_rsp *)req;
468 : 0 : uint32_t n_pipelines = t->n_pipelines;
469 : 0 : struct rte_swx_pipeline *pipeline = req->pipeline_disable.p;
470 : : uint32_t i;
471 : :
472 : : /* find pipeline */
473 [ # # ]: 0 : for (i = 0; i < n_pipelines; i++) {
474 [ # # ]: 0 : if (t->p[i] != pipeline)
475 : : continue;
476 : :
477 [ # # ]: 0 : if (i < n_pipelines - 1)
478 : 0 : t->p[i] = t->p[n_pipelines - 1];
479 : :
480 : 0 : t->n_pipelines--;
481 : :
482 : 0 : rsp->status = 0;
483 : 0 : return rsp;
484 : : }
485 : :
486 : : /* should not get here */
487 : 0 : rsp->status = 0;
488 : 0 : return rsp;
489 : : }
490 : :
491 : : static void
492 : 0 : thread_msg_handle(struct softnic_thread_data *t)
493 : : {
494 : 0 : for ( ; ; ) {
495 : : struct thread_msg_req *req;
496 : : struct thread_msg_rsp *rsp;
497 : :
498 : 0 : req = thread_msg_recv(t->msgq_req);
499 [ # # ]: 0 : if (req == NULL)
500 : : break;
501 : :
502 [ # # # ]: 0 : switch (req->type) {
503 : : case THREAD_REQ_PIPELINE_ENABLE:
504 : : rsp = thread_msg_handle_pipeline_enable(t, req);
505 : 0 : break;
506 : :
507 : : case THREAD_REQ_PIPELINE_DISABLE:
508 : : rsp = thread_msg_handle_pipeline_disable(t, req);
509 : : break;
510 : :
511 : 0 : default:
512 : : rsp = (struct thread_msg_rsp *)req;
513 : 0 : rsp->status = -1;
514 : : }
515 : :
516 : 0 : thread_msg_send(t->msgq_rsp, rsp);
517 : : }
518 : 0 : }
519 : :
520 : : /**
521 : : * Data plane threads: main
522 : : */
523 : : static int32_t
524 : 0 : rte_pmd_softnic_run_internal(void *arg)
525 : : {
526 : : struct rte_eth_dev *dev = arg;
527 : : struct pmd_internals *softnic;
528 : : struct softnic_thread_data *t;
529 : : uint32_t thread_id, j;
530 : :
531 : 0 : softnic = dev->data->dev_private;
532 : : thread_id = rte_lcore_id();
533 : 0 : t = &softnic->thread_data[thread_id];
534 : 0 : t->iter++;
535 : :
536 : : /* Data Plane */
537 [ # # ]: 0 : for (j = 0; j < t->n_pipelines; j++)
538 : 0 : rte_swx_pipeline_run(t->p[j], PIPELINE_INSTR_QUANTA);
539 : :
540 : : /* Control Plane */
541 [ # # ]: 0 : if ((t->iter & 0xFLLU) == 0) {
542 : : uint64_t time = rte_get_tsc_cycles();
543 : 0 : uint64_t time_next = t->time_next;
544 : :
545 [ # # ]: 0 : if (time < time_next)
546 : : return 0;
547 : :
548 : : /* Thread message queues */
549 : 0 : thread_msg_handle(t);
550 : :
551 : 0 : t->time_next = time_next + t->timer_period;
552 : : }
553 : :
554 : : return 0;
555 : : }
556 : :
557 : : int
558 : 0 : rte_pmd_softnic_run(uint16_t port_id)
559 : : {
560 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[port_id];
561 : :
562 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
563 : : RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
564 : : #endif
565 : :
566 : 0 : return (int)rte_pmd_softnic_run_internal(dev);
567 : : }
|