examples/l3fwd: add event em main loop
[dpdk.git] / examples / l3fwd / l3fwd_event.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4
5 #include <stdbool.h>
6 #include <getopt.h>
7
8 #include <rte_malloc.h>
9
10 #include "l3fwd.h"
11 #include "l3fwd_event.h"
12
13 static void
14 print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
15 {
16         char buf[RTE_ETHER_ADDR_FMT_SIZE];
17         rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
18         printf("%s%s", name, buf);
19 }
20
21 struct l3fwd_event_resources *
22 l3fwd_get_eventdev_rsrc(void)
23 {
24         static struct l3fwd_event_resources *rsrc;
25
26         if (rsrc != NULL)
27                 return rsrc;
28
29         rsrc = rte_zmalloc("l3fwd", sizeof(struct l3fwd_event_resources), 0);
30         if (rsrc != NULL) {
31                 rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC;
32                 rsrc->eth_rx_queues = 1;
33                 return rsrc;
34         }
35
36         rte_exit(EXIT_FAILURE, "Unable to allocate memory for eventdev cfg\n");
37
38         return NULL;
39 }
40
41 static void
42 l3fwd_eth_dev_port_setup(struct rte_eth_conf *port_conf)
43 {
44         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
45         uint16_t nb_ports = rte_eth_dev_count_avail();
46         uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
47         uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
48         unsigned int nb_lcores = rte_lcore_count();
49         struct rte_eth_conf local_port_conf;
50         struct rte_eth_dev_info dev_info;
51         struct rte_eth_txconf txconf;
52         struct rte_eth_rxconf rxconf;
53         unsigned int nb_mbuf;
54         uint16_t port_id;
55         uint8_t eth_qid;
56         int32_t ret;
57
58         /* initialize all ports */
59         RTE_ETH_FOREACH_DEV(port_id) {
60                 local_port_conf = *port_conf;
61                 /* skip ports that are not enabled */
62                 if ((evt_rsrc->port_mask & (1 << port_id)) == 0) {
63                         printf("\nSkipping disabled port %d\n", port_id);
64                         continue;
65                 }
66
67                 /* init port */
68                 printf("Initializing port %d ... ", port_id);
69                 fflush(stdout);
70                 printf("Creating queues: nb_rxq=%d nb_txq=1...\n",
71                        evt_rsrc->eth_rx_queues);
72
73                 rte_eth_dev_info_get(port_id, &dev_info);
74                 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
75                         local_port_conf.txmode.offloads |=
76                                                 DEV_TX_OFFLOAD_MBUF_FAST_FREE;
77
78                 local_port_conf.rx_adv_conf.rss_conf.rss_hf &=
79                                                 dev_info.flow_type_rss_offloads;
80                 if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=
81                                 port_conf->rx_adv_conf.rss_conf.rss_hf) {
82                         printf("Port %u modified RSS hash function "
83                                "based on hardware support,"
84                                "requested:%#"PRIx64" configured:%#"PRIx64"\n",
85                                port_id,
86                                port_conf->rx_adv_conf.rss_conf.rss_hf,
87                                local_port_conf.rx_adv_conf.rss_conf.rss_hf);
88                 }
89
90                 ret = rte_eth_dev_configure(port_id, evt_rsrc->eth_rx_queues,
91                                             1, &local_port_conf);
92                 if (ret < 0)
93                         rte_exit(EXIT_FAILURE,
94                                  "Cannot configure device: err=%d, port=%d\n",
95                                  ret, port_id);
96
97                 ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd,
98                                                        &nb_txd);
99                 if (ret < 0)
100                         rte_exit(EXIT_FAILURE,
101                                  "Cannot adjust number of descriptors: err=%d, "
102                                  "port=%d\n", ret, port_id);
103
104                 rte_eth_macaddr_get(port_id, &ports_eth_addr[port_id]);
105                 print_ethaddr(" Address:", &ports_eth_addr[port_id]);
106                 printf(", ");
107                 print_ethaddr("Destination:",
108                         (const struct rte_ether_addr *)&dest_eth_addr[port_id]);
109                 printf(", ");
110
111                 /* prepare source MAC for each port. */
112                 rte_ether_addr_copy(&ports_eth_addr[port_id],
113                         (struct rte_ether_addr *)(val_eth + port_id) + 1);
114
115                 /* init memory */
116                 if (!evt_rsrc->per_port_pool) {
117                         /* port_id = 0; this is *not* signifying the first port,
118                          * rather, it signifies that port_id is ignored.
119                          */
120                         nb_mbuf = RTE_MAX(nb_ports * nb_rxd +
121                                           nb_ports * nb_txd +
122                                           nb_ports * nb_lcores *
123                                                         MAX_PKT_BURST +
124                                           nb_lcores * MEMPOOL_CACHE_SIZE,
125                                           8192u);
126                         ret = init_mem(0, nb_mbuf);
127                 } else {
128                         nb_mbuf = RTE_MAX(nb_rxd + nb_rxd +
129                                           nb_lcores * MAX_PKT_BURST +
130                                           nb_lcores * MEMPOOL_CACHE_SIZE,
131                                           8192u);
132                         ret = init_mem(port_id, nb_mbuf);
133                 }
134                 /* init Rx queues per port */
135                 rxconf = dev_info.default_rxconf;
136                 rxconf.offloads = local_port_conf.rxmode.offloads;
137
138                 for (eth_qid = 0; eth_qid < evt_rsrc->eth_rx_queues;
139                      eth_qid++) {
140                         if (!evt_rsrc->per_port_pool)
141                                 ret = rte_eth_rx_queue_setup(port_id, eth_qid,
142                                         nb_rxd, 0, &rxconf,
143                                         evt_rsrc->pkt_pool[0][0]);
144                         else
145                                 ret = rte_eth_rx_queue_setup(port_id, eth_qid,
146                                         nb_rxd, 0, &rxconf,
147                                         evt_rsrc->pkt_pool[port_id][0]);
148                         if (ret < 0)
149                                 rte_exit(EXIT_FAILURE,
150                                          "rte_eth_rx_queue_setup: err=%d, "
151                                          "port=%d, eth_qid: %d\n",
152                                          ret, port_id, eth_qid);
153                 }
154
155                 /* init one Tx queue per port */
156                 txconf = dev_info.default_txconf;
157                 txconf.offloads = local_port_conf.txmode.offloads;
158                 ret = rte_eth_tx_queue_setup(port_id, 0, nb_txd, 0, &txconf);
159                 if (ret < 0)
160                         rte_exit(EXIT_FAILURE,
161                                  "rte_eth_tx_queue_setup: err=%d, "
162                                  "port=%d\n", ret, port_id);
163         }
164 }
165
166 static void
167 l3fwd_event_capability_setup(void)
168 {
169         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
170         uint32_t caps = 0;
171         uint16_t i;
172         int ret;
173
174         RTE_ETH_FOREACH_DEV(i) {
175                 ret = rte_event_eth_tx_adapter_caps_get(0, i, &caps);
176                 if (ret)
177                         rte_exit(EXIT_FAILURE,
178                                  "Invalid capability for Tx adptr port %d\n",
179                                  i);
180
181                 evt_rsrc->tx_mode_q |= !(caps &
182                                    RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT);
183         }
184
185         if (evt_rsrc->tx_mode_q)
186                 l3fwd_event_set_generic_ops(&evt_rsrc->ops);
187         else
188                 l3fwd_event_set_internal_port_ops(&evt_rsrc->ops);
189 }
190
191 int
192 l3fwd_get_free_event_port(struct l3fwd_event_resources *evt_rsrc)
193 {
194         static int index;
195         int port_id;
196
197         rte_spinlock_lock(&evt_rsrc->evp.lock);
198         if (index >= evt_rsrc->evp.nb_ports) {
199                 printf("No free event port is available\n");
200                 return -1;
201         }
202
203         port_id = evt_rsrc->evp.event_p_id[index];
204         index++;
205         rte_spinlock_unlock(&evt_rsrc->evp.lock);
206
207         return port_id;
208 }
209
210 void
211 l3fwd_event_resource_setup(struct rte_eth_conf *port_conf)
212 {
213         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
214         const event_loop_cb lpm_event_loop[2][2] = {
215                 [0][0] = lpm_event_main_loop_tx_d,
216                 [0][1] = lpm_event_main_loop_tx_d_burst,
217                 [1][0] = lpm_event_main_loop_tx_q,
218                 [1][1] = lpm_event_main_loop_tx_q_burst,
219         };
220         const event_loop_cb em_event_loop[2][2] = {
221                 [0][0] = em_event_main_loop_tx_d,
222                 [0][1] = em_event_main_loop_tx_d_burst,
223                 [1][0] = em_event_main_loop_tx_q,
224                 [1][1] = em_event_main_loop_tx_q_burst,
225         };
226         uint32_t event_queue_cfg;
227         int ret;
228
229         if (!evt_rsrc->enabled)
230                 return;
231
232         if (!rte_event_dev_count())
233                 rte_exit(EXIT_FAILURE, "No Eventdev found");
234
235         /* Setup eventdev capability callbacks */
236         l3fwd_event_capability_setup();
237
238         /* Ethernet device configuration */
239         l3fwd_eth_dev_port_setup(port_conf);
240
241         /* Event device configuration */
242         event_queue_cfg = evt_rsrc->ops.event_device_setup();
243
244         /* Event queue configuration */
245         evt_rsrc->ops.event_queue_setup(event_queue_cfg);
246
247         /* Event port configuration */
248         evt_rsrc->ops.event_port_setup();
249
250         /* Rx/Tx adapters configuration */
251         evt_rsrc->ops.adapter_setup();
252
253         /* Start event device */
254         ret = rte_event_dev_start(evt_rsrc->event_d_id);
255         if (ret < 0)
256                 rte_exit(EXIT_FAILURE, "Error in starting eventdev");
257
258         evt_rsrc->ops.lpm_event_loop = lpm_event_loop[evt_rsrc->tx_mode_q]
259                                                        [evt_rsrc->has_burst];
260
261         evt_rsrc->ops.em_event_loop = em_event_loop[evt_rsrc->tx_mode_q]
262                                                        [evt_rsrc->has_burst];
263 }