2653e86aeb7f8a44f2a6869d5a72303605fab4dc
[dpdk.git] / examples / ipsec-secgw / event_helper.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (C) 2020 Marvell International Ltd.
3  */
4 #include <rte_bitmap.h>
5 #include <rte_ethdev.h>
6 #include <rte_eventdev.h>
7 #include <rte_event_eth_rx_adapter.h>
8 #include <rte_malloc.h>
9 #include <stdbool.h>
10
11 #include "event_helper.h"
12
13 static int
14 eh_get_enabled_cores(struct rte_bitmap *eth_core_mask)
15 {
16         int i, count = 0;
17
18         RTE_LCORE_FOREACH(i) {
19                 /* Check if this core is enabled in core mask*/
20                 if (rte_bitmap_get(eth_core_mask, i)) {
21                         /* Found enabled core */
22                         count++;
23                 }
24         }
25         return count;
26 }
27
28 static inline unsigned int
29 eh_get_next_eth_core(struct eventmode_conf *em_conf)
30 {
31         static unsigned int prev_core = -1;
32         unsigned int next_core;
33
34         /*
35          * Make sure we have at least one eth core running, else the following
36          * logic would lead to an infinite loop.
37          */
38         if (eh_get_enabled_cores(em_conf->eth_core_mask) == 0) {
39                 EH_LOG_ERR("No enabled eth core found");
40                 return RTE_MAX_LCORE;
41         }
42
43         /* Only some cores are marked as eth cores, skip others */
44         do {
45                 /* Get the next core */
46                 next_core = rte_get_next_lcore(prev_core, 0, 1);
47
48                 /* Check if we have reached max lcores */
49                 if (next_core == RTE_MAX_LCORE)
50                         return next_core;
51
52                 /* Update prev_core */
53                 prev_core = next_core;
54         } while (!(rte_bitmap_get(em_conf->eth_core_mask, next_core)));
55
56         return next_core;
57 }
58
59 static inline unsigned int
60 eh_get_next_active_core(struct eventmode_conf *em_conf, unsigned int prev_core)
61 {
62         unsigned int next_core;
63
64         /* Get next active core skipping cores reserved as eth cores */
65         do {
66                 /* Get the next core */
67                 next_core = rte_get_next_lcore(prev_core, 0, 0);
68
69                 /* Check if we have reached max lcores */
70                 if (next_core == RTE_MAX_LCORE)
71                         return next_core;
72
73                 prev_core = next_core;
74         } while (rte_bitmap_get(em_conf->eth_core_mask, next_core));
75
76         return next_core;
77 }
78
79 static int
80 eh_set_default_conf_eventdev(struct eventmode_conf *em_conf)
81 {
82         int lcore_count, nb_eventdev, nb_eth_dev, ret;
83         struct eventdev_params *eventdev_config;
84         struct rte_event_dev_info dev_info;
85
86         /* Get the number of event devices */
87         nb_eventdev = rte_event_dev_count();
88         if (nb_eventdev == 0) {
89                 EH_LOG_ERR("No event devices detected");
90                 return -EINVAL;
91         }
92
93         if (nb_eventdev != 1) {
94                 EH_LOG_ERR("Event mode does not support multiple event devices. "
95                            "Please provide only one event device.");
96                 return -EINVAL;
97         }
98
99         /* Get the number of eth devs */
100         nb_eth_dev = rte_eth_dev_count_avail();
101         if (nb_eth_dev == 0) {
102                 EH_LOG_ERR("No eth devices detected");
103                 return -EINVAL;
104         }
105
106         /* Get the number of lcores */
107         lcore_count = rte_lcore_count();
108
109         /* Read event device info */
110         ret = rte_event_dev_info_get(0, &dev_info);
111         if (ret < 0) {
112                 EH_LOG_ERR("Failed to read event device info %d", ret);
113                 return ret;
114         }
115
116         /* Check if enough ports are available */
117         if (dev_info.max_event_ports < 2) {
118                 EH_LOG_ERR("Not enough event ports available");
119                 return -EINVAL;
120         }
121
122         /* Get the first event dev conf */
123         eventdev_config = &(em_conf->eventdev_config[0]);
124
125         /* Save number of queues & ports available */
126         eventdev_config->eventdev_id = 0;
127         eventdev_config->nb_eventqueue = dev_info.max_event_queues;
128         eventdev_config->nb_eventport = dev_info.max_event_ports;
129         eventdev_config->ev_queue_mode = RTE_EVENT_QUEUE_CFG_ALL_TYPES;
130
131         /* Check if there are more queues than required */
132         if (eventdev_config->nb_eventqueue > nb_eth_dev + 1) {
133                 /* One queue is reserved for Tx */
134                 eventdev_config->nb_eventqueue = nb_eth_dev + 1;
135         }
136
137         /* Check if there are more ports than required */
138         if (eventdev_config->nb_eventport > lcore_count) {
139                 /* One port per lcore is enough */
140                 eventdev_config->nb_eventport = lcore_count;
141         }
142
143         /* Update the number of event devices */
144         em_conf->nb_eventdev++;
145
146         return 0;
147 }
148
149 static int
150 eh_set_default_conf_link(struct eventmode_conf *em_conf)
151 {
152         struct eventdev_params *eventdev_config;
153         struct eh_event_link_info *link;
154         unsigned int lcore_id = -1;
155         int i, link_index;
156
157         /*
158          * Create a 1:1 mapping from event ports to cores. If the number
159          * of event ports is lesser than the cores, some cores won't
160          * execute worker. If there are more event ports, then some ports
161          * won't be used.
162          *
163          */
164
165         /*
166          * The event queue-port mapping is done according to the link. Since
167          * we are falling back to the default link config, enabling
168          * "all_ev_queue_to_ev_port" mode flag. This will map all queues
169          * to the port.
170          */
171         em_conf->ext_params.all_ev_queue_to_ev_port = 1;
172
173         /* Get first event dev conf */
174         eventdev_config = &(em_conf->eventdev_config[0]);
175
176         /* Loop through the ports */
177         for (i = 0; i < eventdev_config->nb_eventport; i++) {
178
179                 /* Get next active core id */
180                 lcore_id = eh_get_next_active_core(em_conf,
181                                 lcore_id);
182
183                 if (lcore_id == RTE_MAX_LCORE) {
184                         /* Reached max cores */
185                         return 0;
186                 }
187
188                 /* Save the current combination as one link */
189
190                 /* Get the index */
191                 link_index = em_conf->nb_link;
192
193                 /* Get the corresponding link */
194                 link = &(em_conf->link[link_index]);
195
196                 /* Save link */
197                 link->eventdev_id = eventdev_config->eventdev_id;
198                 link->event_port_id = i;
199                 link->lcore_id = lcore_id;
200
201                 /*
202                  * Don't set eventq_id as by default all queues
203                  * need to be mapped to the port, which is controlled
204                  * by the operating mode.
205                  */
206
207                 /* Update number of links */
208                 em_conf->nb_link++;
209         }
210
211         return 0;
212 }
213
214 static int
215 eh_set_default_conf_rx_adapter(struct eventmode_conf *em_conf)
216 {
217         struct rx_adapter_connection_info *conn;
218         struct eventdev_params *eventdev_config;
219         struct rx_adapter_conf *adapter;
220         bool single_ev_queue = false;
221         int eventdev_id;
222         int nb_eth_dev;
223         int adapter_id;
224         int conn_id;
225         int i;
226
227         /* Create one adapter with eth queues mapped to event queue(s) */
228
229         if (em_conf->nb_eventdev == 0) {
230                 EH_LOG_ERR("No event devs registered");
231                 return -EINVAL;
232         }
233
234         /* Get the number of eth devs */
235         nb_eth_dev = rte_eth_dev_count_avail();
236
237         /* Use the first event dev */
238         eventdev_config = &(em_conf->eventdev_config[0]);
239
240         /* Get eventdev ID */
241         eventdev_id = eventdev_config->eventdev_id;
242         adapter_id = 0;
243
244         /* Get adapter conf */
245         adapter = &(em_conf->rx_adapter[adapter_id]);
246
247         /* Set adapter conf */
248         adapter->eventdev_id = eventdev_id;
249         adapter->adapter_id = adapter_id;
250         adapter->rx_core_id = eh_get_next_eth_core(em_conf);
251
252         /*
253          * Map all queues of eth device (port) to an event queue. If there
254          * are more event queues than eth ports then create 1:1 mapping.
255          * Otherwise map all eth ports to a single event queue.
256          */
257         if (nb_eth_dev > eventdev_config->nb_eventqueue)
258                 single_ev_queue = true;
259
260         for (i = 0; i < nb_eth_dev; i++) {
261
262                 /* Use only the ports enabled */
263                 if ((em_conf->eth_portmask & (1 << i)) == 0)
264                         continue;
265
266                 /* Get the connection id */
267                 conn_id = adapter->nb_connections;
268
269                 /* Get the connection */
270                 conn = &(adapter->conn[conn_id]);
271
272                 /* Set mapping between eth ports & event queues*/
273                 conn->ethdev_id = i;
274                 conn->eventq_id = single_ev_queue ? 0 : i;
275
276                 /* Add all eth queues eth port to event queue */
277                 conn->ethdev_rx_qid = -1;
278
279                 /* Update no of connections */
280                 adapter->nb_connections++;
281
282         }
283
284         /* We have setup one adapter */
285         em_conf->nb_rx_adapter = 1;
286
287         return 0;
288 }
289
290 static int
291 eh_validate_conf(struct eventmode_conf *em_conf)
292 {
293         int ret;
294
295         /*
296          * Check if event devs are specified. Else probe the event devices
297          * and initialize the config with all ports & queues available
298          */
299         if (em_conf->nb_eventdev == 0) {
300                 ret = eh_set_default_conf_eventdev(em_conf);
301                 if (ret != 0)
302                         return ret;
303         }
304
305         /*
306          * Check if links are specified. Else generate a default config for
307          * the event ports used.
308          */
309         if (em_conf->nb_link == 0) {
310                 ret = eh_set_default_conf_link(em_conf);
311                 if (ret != 0)
312                         return ret;
313         }
314
315         /*
316          * Check if rx adapters are specified. Else generate a default config
317          * with one rx adapter and all eth queues - event queue mapped.
318          */
319         if (em_conf->nb_rx_adapter == 0) {
320                 ret = eh_set_default_conf_rx_adapter(em_conf);
321                 if (ret != 0)
322                         return ret;
323         }
324
325         return 0;
326 }
327
328 static int
329 eh_initialize_eventdev(struct eventmode_conf *em_conf)
330 {
331         struct rte_event_queue_conf eventq_conf = {0};
332         struct rte_event_dev_info evdev_default_conf;
333         struct rte_event_dev_config eventdev_conf;
334         struct eventdev_params *eventdev_config;
335         int nb_eventdev = em_conf->nb_eventdev;
336         struct eh_event_link_info *link;
337         uint8_t *queue = NULL;
338         uint8_t eventdev_id;
339         int nb_eventqueue;
340         uint8_t i, j;
341         int ret;
342
343         for (i = 0; i < nb_eventdev; i++) {
344
345                 /* Get eventdev config */
346                 eventdev_config = &(em_conf->eventdev_config[i]);
347
348                 /* Get event dev ID */
349                 eventdev_id = eventdev_config->eventdev_id;
350
351                 /* Get the number of queues */
352                 nb_eventqueue = eventdev_config->nb_eventqueue;
353
354                 /* Reset the default conf */
355                 memset(&evdev_default_conf, 0,
356                         sizeof(struct rte_event_dev_info));
357
358                 /* Get default conf of eventdev */
359                 ret = rte_event_dev_info_get(eventdev_id, &evdev_default_conf);
360                 if (ret < 0) {
361                         EH_LOG_ERR(
362                                 "Error in getting event device info[devID:%d]",
363                                 eventdev_id);
364                         return ret;
365                 }
366
367                 memset(&eventdev_conf, 0, sizeof(struct rte_event_dev_config));
368                 eventdev_conf.nb_events_limit =
369                                 evdev_default_conf.max_num_events;
370                 eventdev_conf.nb_event_queues = nb_eventqueue;
371                 eventdev_conf.nb_event_ports =
372                                 eventdev_config->nb_eventport;
373                 eventdev_conf.nb_event_queue_flows =
374                                 evdev_default_conf.max_event_queue_flows;
375                 eventdev_conf.nb_event_port_dequeue_depth =
376                                 evdev_default_conf.max_event_port_dequeue_depth;
377                 eventdev_conf.nb_event_port_enqueue_depth =
378                                 evdev_default_conf.max_event_port_enqueue_depth;
379
380                 /* Configure event device */
381                 ret = rte_event_dev_configure(eventdev_id, &eventdev_conf);
382                 if (ret < 0) {
383                         EH_LOG_ERR("Error in configuring event device");
384                         return ret;
385                 }
386
387                 /* Configure event queues */
388                 for (j = 0; j < nb_eventqueue; j++) {
389
390                         memset(&eventq_conf, 0,
391                                         sizeof(struct rte_event_queue_conf));
392
393                         /* Per event dev queues can be ATQ or SINGLE LINK */
394                         eventq_conf.event_queue_cfg =
395                                         eventdev_config->ev_queue_mode;
396                         /*
397                          * All queues need to be set with sched_type as
398                          * schedule type for the application stage. One queue
399                          * would be reserved for the final eth tx stage. This
400                          * will be an atomic queue.
401                          */
402                         if (j == nb_eventqueue-1) {
403                                 eventq_conf.schedule_type =
404                                         RTE_SCHED_TYPE_ATOMIC;
405                         } else {
406                                 eventq_conf.schedule_type =
407                                         em_conf->ext_params.sched_type;
408                         }
409
410                         /* Set max atomic flows to 1024 */
411                         eventq_conf.nb_atomic_flows = 1024;
412                         eventq_conf.nb_atomic_order_sequences = 1024;
413
414                         /* Setup the queue */
415                         ret = rte_event_queue_setup(eventdev_id, j,
416                                         &eventq_conf);
417                         if (ret < 0) {
418                                 EH_LOG_ERR("Failed to setup event queue %d",
419                                            ret);
420                                 return ret;
421                         }
422                 }
423
424                 /* Configure event ports */
425                 for (j = 0; j <  eventdev_config->nb_eventport; j++) {
426                         ret = rte_event_port_setup(eventdev_id, j, NULL);
427                         if (ret < 0) {
428                                 EH_LOG_ERR("Failed to setup event port %d",
429                                            ret);
430                                 return ret;
431                         }
432                 }
433         }
434
435         /* Make event queue - event port link */
436         for (j = 0; j <  em_conf->nb_link; j++) {
437
438                 /* Get link info */
439                 link = &(em_conf->link[j]);
440
441                 /* Get event dev ID */
442                 eventdev_id = link->eventdev_id;
443
444                 /*
445                  * If "all_ev_queue_to_ev_port" params flag is selected, all
446                  * queues need to be mapped to the port.
447                  */
448                 if (em_conf->ext_params.all_ev_queue_to_ev_port)
449                         queue = NULL;
450                 else
451                         queue = &(link->eventq_id);
452
453                 /* Link queue to port */
454                 ret = rte_event_port_link(eventdev_id, link->event_port_id,
455                                 queue, NULL, 1);
456                 if (ret < 0) {
457                         EH_LOG_ERR("Failed to link event port %d", ret);
458                         return ret;
459                 }
460         }
461
462         /* Start event devices */
463         for (i = 0; i < nb_eventdev; i++) {
464
465                 /* Get eventdev config */
466                 eventdev_config = &(em_conf->eventdev_config[i]);
467
468                 ret = rte_event_dev_start(eventdev_config->eventdev_id);
469                 if (ret < 0) {
470                         EH_LOG_ERR("Failed to start event device %d, %d",
471                                    i, ret);
472                         return ret;
473                 }
474         }
475         return 0;
476 }
477
478 static int
479 eh_rx_adapter_configure(struct eventmode_conf *em_conf,
480                 struct rx_adapter_conf *adapter)
481 {
482         struct rte_event_eth_rx_adapter_queue_conf queue_conf = {0};
483         struct rte_event_dev_info evdev_default_conf = {0};
484         struct rte_event_port_conf port_conf = {0};
485         struct rx_adapter_connection_info *conn;
486         uint8_t eventdev_id;
487         uint32_t service_id;
488         int ret;
489         int j;
490
491         /* Get event dev ID */
492         eventdev_id = adapter->eventdev_id;
493
494         /* Get default configuration of event dev */
495         ret = rte_event_dev_info_get(eventdev_id, &evdev_default_conf);
496         if (ret < 0) {
497                 EH_LOG_ERR("Failed to get event dev info %d", ret);
498                 return ret;
499         }
500
501         /* Setup port conf */
502         port_conf.new_event_threshold = 1200;
503         port_conf.dequeue_depth =
504                         evdev_default_conf.max_event_port_dequeue_depth;
505         port_conf.enqueue_depth =
506                         evdev_default_conf.max_event_port_enqueue_depth;
507
508         /* Create Rx adapter */
509         ret = rte_event_eth_rx_adapter_create(adapter->adapter_id,
510                         adapter->eventdev_id, &port_conf);
511         if (ret < 0) {
512                 EH_LOG_ERR("Failed to create rx adapter %d", ret);
513                 return ret;
514         }
515
516         /* Setup various connections in the adapter */
517         for (j = 0; j < adapter->nb_connections; j++) {
518                 /* Get connection */
519                 conn = &(adapter->conn[j]);
520
521                 /* Setup queue conf */
522                 queue_conf.ev.queue_id = conn->eventq_id;
523                 queue_conf.ev.sched_type = em_conf->ext_params.sched_type;
524                 queue_conf.ev.event_type = RTE_EVENT_TYPE_ETHDEV;
525
526                 /* Add queue to the adapter */
527                 ret = rte_event_eth_rx_adapter_queue_add(adapter->adapter_id,
528                                 conn->ethdev_id, conn->ethdev_rx_qid,
529                                 &queue_conf);
530                 if (ret < 0) {
531                         EH_LOG_ERR("Failed to add eth queue to rx adapter %d",
532                                    ret);
533                         return ret;
534                 }
535         }
536
537         /* Get the service ID used by rx adapter */
538         ret = rte_event_eth_rx_adapter_service_id_get(adapter->adapter_id,
539                                                       &service_id);
540         if (ret != -ESRCH && ret < 0) {
541                 EH_LOG_ERR("Failed to get service id used by rx adapter %d",
542                            ret);
543                 return ret;
544         }
545
546         rte_service_set_runstate_mapped_check(service_id, 0);
547
548         /* Start adapter */
549         ret = rte_event_eth_rx_adapter_start(adapter->adapter_id);
550         if (ret < 0) {
551                 EH_LOG_ERR("Failed to start rx adapter %d", ret);
552                 return ret;
553         }
554
555         return 0;
556 }
557
558 static int
559 eh_initialize_rx_adapter(struct eventmode_conf *em_conf)
560 {
561         struct rx_adapter_conf *adapter;
562         int i, ret;
563
564         /* Configure rx adapters */
565         for (i = 0; i < em_conf->nb_rx_adapter; i++) {
566                 adapter = &(em_conf->rx_adapter[i]);
567                 ret = eh_rx_adapter_configure(em_conf, adapter);
568                 if (ret < 0) {
569                         EH_LOG_ERR("Failed to configure rx adapter %d", ret);
570                         return ret;
571                 }
572         }
573         return 0;
574 }
575
576 int32_t
577 eh_devs_init(struct eh_conf *conf)
578 {
579         struct eventmode_conf *em_conf;
580         uint16_t port_id;
581         int ret;
582
583         if (conf == NULL) {
584                 EH_LOG_ERR("Invalid event helper configuration");
585                 return -EINVAL;
586         }
587
588         if (conf->mode != EH_PKT_TRANSFER_MODE_EVENT)
589                 return 0;
590
591         if (conf->mode_params == NULL) {
592                 EH_LOG_ERR("Invalid event mode parameters");
593                 return -EINVAL;
594         }
595
596         /* Get eventmode conf */
597         em_conf = conf->mode_params;
598
599         /* Eventmode conf would need eth portmask */
600         em_conf->eth_portmask = conf->eth_portmask;
601
602         /* Validate the requested config */
603         ret = eh_validate_conf(em_conf);
604         if (ret < 0) {
605                 EH_LOG_ERR("Failed to validate the requested config %d", ret);
606                 return ret;
607         }
608
609         /* Stop eth devices before setting up adapter */
610         RTE_ETH_FOREACH_DEV(port_id) {
611
612                 /* Use only the ports enabled */
613                 if ((conf->eth_portmask & (1 << port_id)) == 0)
614                         continue;
615
616                 rte_eth_dev_stop(port_id);
617         }
618
619         /* Setup eventdev */
620         ret = eh_initialize_eventdev(em_conf);
621         if (ret < 0) {
622                 EH_LOG_ERR("Failed to initialize event dev %d", ret);
623                 return ret;
624         }
625
626         /* Setup Rx adapter */
627         ret = eh_initialize_rx_adapter(em_conf);
628         if (ret < 0) {
629                 EH_LOG_ERR("Failed to initialize rx adapter %d", ret);
630                 return ret;
631         }
632
633         /* Start eth devices after setting up adapter */
634         RTE_ETH_FOREACH_DEV(port_id) {
635
636                 /* Use only the ports enabled */
637                 if ((conf->eth_portmask & (1 << port_id)) == 0)
638                         continue;
639
640                 ret = rte_eth_dev_start(port_id);
641                 if (ret < 0) {
642                         EH_LOG_ERR("Failed to start eth dev %d, %d",
643                                    port_id, ret);
644                         return ret;
645                 }
646         }
647
648         return 0;
649 }
650
651 int32_t
652 eh_devs_uninit(struct eh_conf *conf)
653 {
654         struct eventmode_conf *em_conf;
655         int ret, i, j;
656         uint16_t id;
657
658         if (conf == NULL) {
659                 EH_LOG_ERR("Invalid event helper configuration");
660                 return -EINVAL;
661         }
662
663         if (conf->mode != EH_PKT_TRANSFER_MODE_EVENT)
664                 return 0;
665
666         if (conf->mode_params == NULL) {
667                 EH_LOG_ERR("Invalid event mode parameters");
668                 return -EINVAL;
669         }
670
671         /* Get eventmode conf */
672         em_conf = conf->mode_params;
673
674         /* Stop and release rx adapters */
675         for (i = 0; i < em_conf->nb_rx_adapter; i++) {
676
677                 id = em_conf->rx_adapter[i].adapter_id;
678                 ret = rte_event_eth_rx_adapter_stop(id);
679                 if (ret < 0) {
680                         EH_LOG_ERR("Failed to stop rx adapter %d", ret);
681                         return ret;
682                 }
683
684                 for (j = 0; j < em_conf->rx_adapter[i].nb_connections; j++) {
685
686                         ret = rte_event_eth_rx_adapter_queue_del(id,
687                                 em_conf->rx_adapter[i].conn[j].ethdev_id, -1);
688                         if (ret < 0) {
689                                 EH_LOG_ERR(
690                                        "Failed to remove rx adapter queues %d",
691                                        ret);
692                                 return ret;
693                         }
694                 }
695
696                 ret = rte_event_eth_rx_adapter_free(id);
697                 if (ret < 0) {
698                         EH_LOG_ERR("Failed to free rx adapter %d", ret);
699                         return ret;
700                 }
701         }
702
703         /* Stop and release event devices */
704         for (i = 0; i < em_conf->nb_eventdev; i++) {
705
706                 id = em_conf->eventdev_config[i].eventdev_id;
707                 rte_event_dev_stop(id);
708
709                 ret = rte_event_dev_close(id);
710                 if (ret < 0) {
711                         EH_LOG_ERR("Failed to close event dev %d, %d", id, ret);
712                         return ret;
713                 }
714         }
715
716         return 0;
717 }