/* SPDX-License-Identifier: BSD-3-Clause * Copyright(C) 2019 Marvell International Ltd. */ #include #include #include #include "l3fwd.h" #include "l3fwd_event.h" static void print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) { char buf[RTE_ETHER_ADDR_FMT_SIZE]; rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); printf("%s%s", name, buf); } struct l3fwd_event_resources * l3fwd_get_eventdev_rsrc(void) { static struct l3fwd_event_resources *rsrc; if (rsrc != NULL) return rsrc; rsrc = rte_zmalloc("l3fwd", sizeof(struct l3fwd_event_resources), 0); if (rsrc != NULL) { rsrc->sched_type = RTE_SCHED_TYPE_ATOMIC; rsrc->eth_rx_queues = 1; return rsrc; } rte_exit(EXIT_FAILURE, "Unable to allocate memory for eventdev cfg\n"); return NULL; } static void l3fwd_eth_dev_port_setup(struct rte_eth_conf *port_conf) { struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); uint16_t nb_ports = rte_eth_dev_count_avail(); uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; unsigned int nb_lcores = rte_lcore_count(); struct rte_eth_conf local_port_conf; struct rte_eth_dev_info dev_info; struct rte_eth_txconf txconf; struct rte_eth_rxconf rxconf; unsigned int nb_mbuf; uint16_t port_id; uint8_t eth_qid; int32_t ret; /* initialize all ports */ RTE_ETH_FOREACH_DEV(port_id) { local_port_conf = *port_conf; /* skip ports that are not enabled */ if ((evt_rsrc->port_mask & (1 << port_id)) == 0) { printf("\nSkipping disabled port %d\n", port_id); continue; } /* init port */ printf("Initializing port %d ... ", port_id); fflush(stdout); printf("Creating queues: nb_rxq=%d nb_txq=1...\n", evt_rsrc->eth_rx_queues); ret = rte_eth_dev_info_get(port_id, &dev_info); if (ret != 0) rte_panic("Error during getting device (port %u) info:" "%s\n", port_id, strerror(-ret)); if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) local_port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE; local_port_conf.rx_adv_conf.rss_conf.rss_hf &= dev_info.flow_type_rss_offloads; if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != port_conf->rx_adv_conf.rss_conf.rss_hf) { printf("Port %u modified RSS hash function " "based on hardware support," "requested:%#"PRIx64" configured:%#"PRIx64"\n", port_id, port_conf->rx_adv_conf.rss_conf.rss_hf, local_port_conf.rx_adv_conf.rss_conf.rss_hf); } ret = rte_eth_dev_configure(port_id, evt_rsrc->eth_rx_queues, 1, &local_port_conf); if (ret < 0) rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n", ret, port_id); ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, &nb_txd); if (ret < 0) rte_exit(EXIT_FAILURE, "Cannot adjust number of descriptors: err=%d, " "port=%d\n", ret, port_id); rte_eth_macaddr_get(port_id, &ports_eth_addr[port_id]); print_ethaddr(" Address:", &ports_eth_addr[port_id]); printf(", "); print_ethaddr("Destination:", (const struct rte_ether_addr *)&dest_eth_addr[port_id]); printf(", "); /* prepare source MAC for each port. */ rte_ether_addr_copy(&ports_eth_addr[port_id], (struct rte_ether_addr *)(val_eth + port_id) + 1); /* init memory */ if (!evt_rsrc->per_port_pool) { /* port_id = 0; this is *not* signifying the first port, * rather, it signifies that port_id is ignored. */ nb_mbuf = RTE_MAX(nb_ports * nb_rxd + nb_ports * nb_txd + nb_ports * nb_lcores * MAX_PKT_BURST + nb_lcores * MEMPOOL_CACHE_SIZE, 8192u); ret = init_mem(0, nb_mbuf); } else { nb_mbuf = RTE_MAX(nb_rxd + nb_rxd + nb_lcores * MAX_PKT_BURST + nb_lcores * MEMPOOL_CACHE_SIZE, 8192u); ret = init_mem(port_id, nb_mbuf); } /* init Rx queues per port */ rxconf = dev_info.default_rxconf; rxconf.offloads = local_port_conf.rxmode.offloads; for (eth_qid = 0; eth_qid < evt_rsrc->eth_rx_queues; eth_qid++) { if (!evt_rsrc->per_port_pool) ret = rte_eth_rx_queue_setup(port_id, eth_qid, nb_rxd, 0, &rxconf, evt_rsrc->pkt_pool[0][0]); else ret = rte_eth_rx_queue_setup(port_id, eth_qid, nb_rxd, 0, &rxconf, evt_rsrc->pkt_pool[port_id][0]); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d, " "port=%d, eth_qid: %d\n", ret, port_id, eth_qid); } /* init one Tx queue per port */ txconf = dev_info.default_txconf; txconf.offloads = local_port_conf.txmode.offloads; ret = rte_eth_tx_queue_setup(port_id, 0, nb_txd, 0, &txconf); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, " "port=%d\n", ret, port_id); } } static void l3fwd_event_capability_setup(void) { struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); uint32_t caps = 0; uint16_t i; int ret; RTE_ETH_FOREACH_DEV(i) { ret = rte_event_eth_tx_adapter_caps_get(0, i, &caps); if (ret) rte_exit(EXIT_FAILURE, "Invalid capability for Tx adptr port %d\n", i); evt_rsrc->tx_mode_q |= !(caps & RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT); } if (evt_rsrc->tx_mode_q) l3fwd_event_set_generic_ops(&evt_rsrc->ops); else l3fwd_event_set_internal_port_ops(&evt_rsrc->ops); } int l3fwd_get_free_event_port(struct l3fwd_event_resources *evt_rsrc) { static int index; int port_id; rte_spinlock_lock(&evt_rsrc->evp.lock); if (index >= evt_rsrc->evp.nb_ports) { printf("No free event port is available\n"); return -1; } port_id = evt_rsrc->evp.event_p_id[index]; index++; rte_spinlock_unlock(&evt_rsrc->evp.lock); return port_id; } void l3fwd_event_resource_setup(struct rte_eth_conf *port_conf) { struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc(); const event_loop_cb lpm_event_loop[2][2] = { [0][0] = lpm_event_main_loop_tx_d, [0][1] = lpm_event_main_loop_tx_d_burst, [1][0] = lpm_event_main_loop_tx_q, [1][1] = lpm_event_main_loop_tx_q_burst, }; const event_loop_cb em_event_loop[2][2] = { [0][0] = em_event_main_loop_tx_d, [0][1] = em_event_main_loop_tx_d_burst, [1][0] = em_event_main_loop_tx_q, [1][1] = em_event_main_loop_tx_q_burst, }; const event_loop_cb fib_event_loop[2][2] = { [0][0] = fib_event_main_loop_tx_d, [0][1] = fib_event_main_loop_tx_d_burst, [1][0] = fib_event_main_loop_tx_q, [1][1] = fib_event_main_loop_tx_q_burst, }; uint32_t event_queue_cfg; int ret; if (!evt_rsrc->enabled) return; if (!rte_event_dev_count()) rte_exit(EXIT_FAILURE, "No Eventdev found"); /* Setup eventdev capability callbacks */ l3fwd_event_capability_setup(); /* Ethernet device configuration */ l3fwd_eth_dev_port_setup(port_conf); /* Event device configuration */ event_queue_cfg = evt_rsrc->ops.event_device_setup(); /* Event queue configuration */ evt_rsrc->ops.event_queue_setup(event_queue_cfg); /* Event port configuration */ evt_rsrc->ops.event_port_setup(); /* Rx/Tx adapters configuration */ evt_rsrc->ops.adapter_setup(); /* Start event device */ ret = rte_event_dev_start(evt_rsrc->event_d_id); if (ret < 0) rte_exit(EXIT_FAILURE, "Error in starting eventdev"); evt_rsrc->ops.lpm_event_loop = lpm_event_loop[evt_rsrc->tx_mode_q] [evt_rsrc->has_burst]; evt_rsrc->ops.em_event_loop = em_event_loop[evt_rsrc->tx_mode_q] [evt_rsrc->has_burst]; evt_rsrc->ops.fib_event_loop = fib_event_loop[evt_rsrc->tx_mode_q] [evt_rsrc->has_burst]; }