-/******************************************************************************
-*
-* Copyright (c) 2019 Intel.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*
-*******************************************************************************/
-
-
-/**
- * @brief This file has all definitions for the Ethernet Data Interface Layer
- * @file ethdi.c
- * @ingroup group_lte_source_auxlib
- * @author Intel Corporation
- **/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <sys/queue.h>
-#include <err.h>
-#include <assert.h>
-#include <linux/limits.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <rte_config.h>
-#include <rte_common.h>
-#include <rte_log.h>
-#include <rte_memory.h>
-#include <rte_memcpy.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_per_lcore.h>
-#include <rte_launch.h>
-#include <rte_atomic.h>
-#include <rte_cycles.h>
-#include <rte_prefetch.h>
-#include <rte_lcore.h>
-#include <rte_per_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_debug.h>
-#include <rte_ethdev.h>
-#include <rte_ring.h>
-#include <rte_mbuf.h>
-#include <rte_timer.h>
-
-#include "ethernet.h"
-#include "ethdi.h"
-#ifndef MLOG_ENABLED
-#include "../src/mlog_lnx_xRAN.h"
-#else
-#include "mlog_lnx.h"
-#endif
-
-#include "../src/xran_lib_mlog_tasks_id.h"
-
-struct xran_ethdi_ctx g_ethdi_ctx = { 0 };
-enum xran_if_state xran_if_current_state = XRAN_STOPPED;
-
-struct rte_mbuf *xran_ethdi_mbuf_alloc(void)
-{
- return rte_pktmbuf_alloc(_eth_mbuf_pool);
-}
-
-int xran_ethdi_mbuf_send(struct rte_mbuf *mb, uint16_t ethertype)
-{
- struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
- int res = 0;
-
- mb->port = ctx->io_cfg.port[ETHDI_UP_VF];
- xran_add_eth_hdr_vlan(&ctx->entities[ID_RU], ethertype, mb, ctx->up_vtag);
-
- res = xran_enqueue_mbuf(mb, ctx->tx_ring[ETHDI_UP_VF]);
- return res;
-}
-
-int xran_ethdi_mbuf_send_cp(struct rte_mbuf *mb, uint16_t ethertype)
-{
- struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
- int res = 0;
-
- mb->port = ctx->io_cfg.port[ETHDI_CP_VF];
- xran_add_eth_hdr_vlan(&ctx->entities[ID_RU], ethertype, mb, ctx->cp_vtag);
-
- res = xran_enqueue_mbuf(mb, ctx->tx_ring[ETHDI_CP_VF]);
- return res;
-}
-
-void xran_ethdi_stop_tx()
-{
- struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
- rte_timer_stop_sync(&ctx->timer_tx);
-}
-
-
-struct {
- uint16_t ethertype;
- ethertype_handler fn;
-} xran_ethertype_handlers[] = {
- { ETHER_TYPE_ETHDI, NULL },
- { ETHER_TYPE_ECPRI, NULL },
- { ETHER_TYPE_START_TX, NULL }
-};
-
-
-
-int xran_register_ethertype_handler(uint16_t ethertype, ethertype_handler callback)
-{
- int i;
-
- for (i = 0; i < RTE_DIM(xran_ethertype_handlers); ++i)
- if (xran_ethertype_handlers[i].ethertype == ethertype) {
- xran_ethertype_handlers[i].fn = callback;
-
- return 1;
- }
-
- elog("support for ethertype %u not found", ethertype);
-
- return 0;
-}
-
-int xran_handle_ether(uint16_t ethertype, struct rte_mbuf *pkt, uint64_t rx_time)
-{
- int i;
-
- for (i = 0; i < RTE_DIM(xran_ethertype_handlers); ++i)
- if (xran_ethertype_handlers[i].ethertype == ethertype)
- if (xran_ethertype_handlers[i].fn)
- return xran_ethertype_handlers[i].fn(pkt, rx_time);
-
- wlog("Packet with unrecognized ethertype '%.4X' dropped", ethertype);
-
- return 0;
-};
-
-
-/* Process vlan tag. Cut the ethernet header. Call the etherype handlers. */
-int xran_ethdi_filter_packet(struct rte_mbuf *pkt, uint64_t rx_time)
-{
- struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
-
-#ifdef VLAN_SUPPORT
- if (rte_vlan_strip(pkt) == 0) {
- if (pkt->vlan_tci == ctx->cp_vtag) {
- dlog("VLAN tci matches %d", pkt->vlan_tci);
- } else {
- wlog("packet with wrong VLAN tag %d, dropping",
- pkt->vlan_tci);
- return 0;
- }
- } else
- dlog("Packet not vlan tagged");
-#endif
-
- const struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(pkt, void *);
-
-#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1
- nlog("*** processing RX'ed packet of size %d ***",
- rte_pktmbuf_data_len(pkt));
- /* TODO: just dump ethernet header in readable format? */
-#endif
-
-#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1
- {
- char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";
- char src[ETHER_ADDR_FMT_SIZE] = "(empty)";
-
- ether_format_addr(dst, sizeof(dst), ð_hdr->d_addr);
- ether_format_addr(src, sizeof(src), ð_hdr->s_addr);
- nlog("src: %s dst: %s ethertype: %.4X", dst, src,
- rte_be_to_cpu_16(eth_hdr->ether_type));
- }
-#endif
-
- /* Cut out the ethernet header. It's not needed anymore. */
- if (rte_pktmbuf_adj(pkt, sizeof(*eth_hdr)) == NULL) {
- wlog("Packet too short, dropping");
- return 0;
- }
-
-
- return xran_handle_ether(rte_be_to_cpu_16(eth_hdr->ether_type), pkt, rx_time);
-}
-
-
-
-
-int xran_ethdi_init_dpdk_io(char *name, const struct xran_io_loop_cfg *io_cfg,
- int *lcore_id, struct ether_addr *p_lls_cu_addr, struct ether_addr *p_ru_addr,
- uint16_t cp_vlan, uint16_t up_vlan)
-{
- uint16_t port[2] = {0, 0};
- struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
- int i;
- char core_mask[20];
- char *argv[] = { name, core_mask, "-m3072", "--proc-type=auto",
- "--file-prefix", name, "-w", "0000:00:00.0" };
-
- if (io_cfg == NULL)
- return 0;
-
- snprintf(core_mask, sizeof(core_mask), "-c%x",
- (1 << io_cfg->core) |
- (1 << io_cfg->system_core) |
- (1 << io_cfg->pkt_proc_core) |
- (1 << io_cfg->pkt_aux_core) |
- (1 << io_cfg->timing_core));
-
- ctx->io_cfg = *io_cfg;
- ctx->ping_state = PING_IDLE;
- ctx->known_peers = 1;
- ctx->busy_poll_till = rte_rdtsc();
- ctx->cp_vtag = cp_vlan;
- ctx->up_vtag = up_vlan;
-
- for (i = 0; i <= ID_BROADCAST; i++) /* Initialize all as broadcast */
- memset(&ctx->entities[i], 0xFF, sizeof(ctx->entities[0]));
-
- /* This will return on system_core, which is not necessarily the
- * one we're on right now. */
- if (rte_eal_init(RTE_DIM(argv), argv) < 0)
- rte_panic("Cannot init EAL: %s\n", rte_strerror(rte_errno));
-
- xran_init_mbuf_pool();
-
- /* Timers. */
- rte_timer_subsystem_init();
- rte_timer_init(&ctx->timer_ping);
- rte_timer_init(&ctx->timer_sync);
- rte_timer_init(&ctx->timer_tx);
-
- *lcore_id = rte_get_next_lcore(rte_lcore_id(), 0, 0);
-
- PANIC_ON(*lcore_id == RTE_MAX_LCORE, "out of lcores for io_loop()");
-
- if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
- for (i = 0; i < ETHDI_VF_MAX; i ++){
- if (rte_eth_dev_attach(io_cfg->dpdk_dev[i], &port[i]) != 0 ||
- rte_eth_dev_count_avail() == 0)
- errx(1, "Network port doesn't exist.");
- xran_init_port(port[i], p_lls_cu_addr); /* we only have 1 port at this stage */
- if(i==0){
- ctx->tx_ring[i] = rte_ring_create("tx_ring_up", NUM_MBUFS,
- rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
- ctx->rx_ring[i] = rte_ring_create("rx_ring_up", NUM_MBUFS,
- rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
- ctx->pkt_dump_ring[i] = rte_ring_create("pkt_dump_ring_up", NUM_MBUFS,
- rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
- }else {
- ctx->tx_ring[i] = rte_ring_create("tx_ring_cp", NUM_MBUFS,
- rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
- ctx->rx_ring[i] = rte_ring_create("rx_ring_cp", NUM_MBUFS,
- rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
- ctx->pkt_dump_ring[i] = rte_ring_create("pkt_dump_ring_cp", NUM_MBUFS,
- rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
- }
- }
- } else {
- rte_panic("ethdi_dpdk_io_loop() failed to start with RTE_PROC_SECONDARY\n");
- }
- PANIC_ON(ctx->tx_ring == NULL, "failed to allocate tx ring");
- PANIC_ON(ctx->rx_ring == NULL, "failed to allocate rx ring");
- PANIC_ON(ctx->pkt_dump_ring == NULL, "failed to allocate pkt dumping ring");
- for (i = 0; i < ETHDI_VF_MAX; i++)
- ctx->io_cfg.port[i] = port[i];
-
- rte_eth_macaddr_get(port[ETHDI_UP_VF], &ctx->entities[io_cfg->id]);
- ether_addr_copy(p_ru_addr, &ctx->entities[ID_RU]);
-
- /* Start the actual IO thread */
- if (rte_eal_remote_launch(xran_ethdi_dpdk_io_loop, &ctx->io_cfg, *lcore_id))
- rte_panic("ethdi_dpdk_io_loop() failed to start\n");
-
- return 1;
-}
-
-static inline uint16_t xran_tx_from_ring(int port, struct rte_ring *r)
-{
- struct rte_mbuf *mbufs[BURST_SIZE];
- uint16_t dequeued, sent = 0;
- uint32_t remaining;
- int i;
- long t1 = MLogTick();
-
- dequeued = rte_ring_dequeue_burst(r, (void **)mbufs, BURST_SIZE,
- &remaining);
- if (!dequeued)
- return 0; /* Nothing to send. */
-
- while (1) { /* When tx queue is full it is trying again till succeed */
- t1 = MLogTick();
- sent += rte_eth_tx_burst(port, 0, &mbufs[sent], dequeued - sent);
- MLogTask(PID_RADIO_ETH_TX_BURST, t1, MLogTick());
-
- if (sent == dequeued)
- return remaining;
- }
-}
-
-
-
-/*
- * This is the main DPDK-IO loop.
- * This will sleep if there's no packets incoming and there's
- * no work enqueued, sleep lenth is defined in IDLE_SLEEP_MICROSECS
- */
-int xran_ethdi_dpdk_io_loop(void *io_loop_cfg)
-{
- struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
- const struct xran_io_loop_cfg *const cfg = io_loop_cfg;
- const int port[ETHDI_VF_MAX] = {cfg->port[ETHDI_UP_VF], cfg->port[ETHDI_CP_VF]};
- int port_id = 0;
- struct sched_param sched_param;
- int res = 0;
-
- printf("%s [PORT: %d %d] [CPU %2d] [PID: %6d]\n", __FUNCTION__, port[ETHDI_UP_VF], port[ETHDI_CP_VF] , rte_lcore_id(), getpid());
-
- printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__, rte_lcore_id(), getpid());
- sched_param.sched_priority = XRAN_THREAD_DEFAULT_PRIO;
- if ((res = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched_param)))
- {
- printf("priority is not changed: coreId = %d, result1 = %d\n",rte_lcore_id(), res);
- }
-
- for (;;) {
- for (port_id = 0; port_id < ETHDI_VF_MAX; port_id++){
- struct rte_mbuf *mbufs[BURST_SIZE];
- /* RX */
- const uint16_t rxed = rte_eth_rx_burst(port[port_id], 0, mbufs, BURST_SIZE);
- if (rxed != 0){
- long t1 = MLogTick();
- rte_ring_enqueue_burst(ctx->rx_ring[port_id], (void*)mbufs, rxed, NULL);
- MLogTask(PID_RADIO_RX_VALIDATE, t1, MLogTick());
- }
-
- /* TX */
- const uint16_t sent = xran_tx_from_ring(port[port_id], ctx->tx_ring[port_id]);
- if (rxed | sent)
- continue; /* more packets might be waiting in queues */
-
- rte_pause(); /* short pause, optimize memory access */
- if (XRAN_STOPPED == xran_if_current_state)
- break;
- }
-
- if (XRAN_STOPPED == xran_if_current_state)
- break;
- }
-
- fflush(stderr);
- fflush(stdout);
- puts("IO loop finished");
-
- //for (port_id = 0; port_id < ETHDI_VF_MAX; port_id++)
- // xran_ethdi_port_stats(port[port_id]);
-
- return 0;
-}
+/******************************************************************************\r
+*\r
+* Copyright (c) 2019 Intel.\r
+*\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*\r
+*******************************************************************************/\r
+\r
+/**\r
+ * @brief This file has all definitions for the Ethernet Data Interface Layer\r
+ * @file ethdi.c\r
+ * @ingroup group_lte_source_auxlib\r
+ * @author Intel Corporation\r
+ **/\r
+\r
+#define _GNU_SOURCE\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdint.h>\r
+#include <errno.h>\r
+#include <sys/queue.h>\r
+#include <err.h>\r
+#include <assert.h>\r
+#include <linux/limits.h>\r
+#include <sys/types.h>\r
+#include <stdlib.h>\r
+#include <sys/time.h>\r
+#include <time.h>\r
+#include <unistd.h>\r
+\r
+#include <rte_config.h>\r
+#include <rte_common.h>\r
+#include <rte_log.h>\r
+#include <rte_memory.h>\r
+#include <rte_memcpy.h>\r
+#include <rte_memzone.h>\r
+#include <rte_eal.h>\r
+#include <rte_per_lcore.h>\r
+#include <rte_launch.h>\r
+#include <rte_atomic.h>\r
+#include <rte_cycles.h>\r
+#include <rte_prefetch.h>\r
+#include <rte_lcore.h>\r
+#include <rte_per_lcore.h>\r
+#include <rte_branch_prediction.h>\r
+#include <rte_interrupts.h>\r
+#include <rte_pci.h>\r
+#include <rte_debug.h>\r
+#include <rte_ethdev.h>\r
+#include <rte_ring.h>\r
+#include <rte_mbuf.h>\r
+#include <rte_timer.h>\r
+\r
+#include "ethernet.h"\r
+#include "ethdi.h"\r
+#include "xran_fh_o_du.h"\r
+#include "xran_mlog_lnx.h"\r
+#include "xran_printf.h"\r
+\r
+#include "../src/xran_lib_mlog_tasks_id.h"\r
+\r
+#define BURST_RX_IO_SIZE 48\r
+\r
+struct xran_ethdi_ctx g_ethdi_ctx = { 0 };\r
+enum xran_if_state xran_if_current_state = XRAN_STOPPED;\r
+\r
+struct rte_mbuf *xran_ethdi_mbuf_alloc(void)\r
+{\r
+ return rte_pktmbuf_alloc(_eth_mbuf_pool);\r
+}\r
+\r
+int xran_ethdi_mbuf_send(struct rte_mbuf *mb, uint16_t ethertype)\r
+{\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+ int res = 0;\r
+\r
+ mb->port = ctx->io_cfg.port[ETHDI_UP_VF];\r
+ xran_add_eth_hdr_vlan(&ctx->entities[ID_RU], ethertype, mb, ctx->up_vtag);\r
+\r
+ res = xran_enqueue_mbuf(mb, ctx->tx_ring[ETHDI_UP_VF]);\r
+ return res;\r
+}\r
+\r
+int xran_ethdi_mbuf_send_cp(struct rte_mbuf *mb, uint16_t ethertype)\r
+{\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+ int res = 0;\r
+\r
+ mb->port = ctx->io_cfg.port[ETHDI_CP_VF];\r
+ xran_add_eth_hdr_vlan(&ctx->entities[ID_RU], ethertype, mb, ctx->cp_vtag);\r
+\r
+ res = xran_enqueue_mbuf(mb, ctx->tx_ring[ETHDI_CP_VF]);\r
+ return res;\r
+}\r
+#if 0\r
+void xran_ethdi_stop_tx()\r
+{\r
+ struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();\r
+ rte_timer_stop_sync(&ctx->timer_tx);\r
+}\r
+#endif\r
+\r
+struct {\r
+ uint16_t ethertype;\r
+ ethertype_handler fn;\r
+} xran_ethertype_handlers[] = {\r
+ { ETHER_TYPE_ETHDI, NULL },\r
+ { ETHER_TYPE_ECPRI, NULL },\r
+ { ETHER_TYPE_START_TX, NULL }\r
+};\r
+\r
+\r
+\r
+int xran_register_ethertype_handler(uint16_t ethertype, ethertype_handler callback)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < RTE_DIM(xran_ethertype_handlers); ++i)\r
+ if (xran_ethertype_handlers[i].ethertype == ethertype) {\r
+ xran_ethertype_handlers[i].fn = callback;\r
+\r
+ return 1;\r
+ }\r
+\r
+ elog("support for ethertype %u not found", ethertype);\r
+\r
+ return 0;\r
+}\r
+\r
+int xran_handle_ether(uint16_t ethertype, struct rte_mbuf *pkt, uint64_t rx_time)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < RTE_DIM(xran_ethertype_handlers); ++i)\r
+ if (xran_ethertype_handlers[i].ethertype == ethertype)\r
+ if (xran_ethertype_handlers[i].fn)\r
+ return xran_ethertype_handlers[i].fn(pkt, rx_time);\r
+\r
+ wlog("Packet with unrecognized ethertype '%.4X' dropped", ethertype);\r
+\r
+ return 0;\r
+};\r
+\r
+\r
+/* Process vlan tag. Cut the ethernet header. Call the etherype handlers. */\r
+int xran_ethdi_filter_packet(struct rte_mbuf *pkt, uint64_t rx_time)\r
+{\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+\r
+#ifdef VLAN_SUPPORT\r
+ if (rte_vlan_strip(pkt) == 0) {\r
+ if (pkt->vlan_tci == ctx->cp_vtag) {\r
+ dlog("VLAN tci matches %d", pkt->vlan_tci);\r
+ } else {\r
+ wlog("packet with wrong VLAN tag %d, dropping",\r
+ pkt->vlan_tci);\r
+ return 0;\r
+ }\r
+ } else\r
+ dlog("Packet not vlan tagged");\r
+#endif\r
+\r
+ const struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(pkt, void *);\r
+\r
+#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1\r
+ nlog("*** processing RX'ed packet of size %d ***",\r
+ rte_pktmbuf_data_len(pkt));\r
+ /* TODO: just dump ethernet header in readable format? */\r
+#endif\r
+\r
+#if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1\r
+ {\r
+ char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";\r
+ char src[ETHER_ADDR_FMT_SIZE] = "(empty)";\r
+\r
+ ether_format_addr(dst, sizeof(dst), ð_hdr->d_addr);\r
+ ether_format_addr(src, sizeof(src), ð_hdr->s_addr);\r
+ nlog("src: %s dst: %s ethertype: %.4X", dst, src,\r
+ rte_be_to_cpu_16(eth_hdr->ether_type));\r
+ }\r
+#endif\r
+\r
+ /* Cut out the ethernet header. It's not needed anymore. */\r
+ if (rte_pktmbuf_adj(pkt, sizeof(*eth_hdr)) == NULL) {\r
+ wlog("Packet too short, dropping");\r
+ return 0;\r
+ }\r
+\r
+\r
+ return xran_handle_ether(rte_be_to_cpu_16(eth_hdr->ether_type), pkt, rx_time);\r
+}\r
+\r
+#if 0\r
+//-------------------------------------------------------------------------------------------\r
+/** @ingroup xran\r
+ *\r
+ * @param[in] port - DPDK ETH port id\r
+ *\r
+ * @return void\r
+ *\r
+ * @description\r
+ * Prints statistics of usage of DPDK port\r
+ *\r
+**/\r
+//-------------------------------------------------------------------------------------------\r
+void xran_ethdi_ports_stats(void)\r
+{\r
+ struct rte_eth_stats stats;\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+ int32_t i = 0;\r
+\r
+ for(i = 0; i < ETHDI_VF_MAX; i++){\r
+ /* Get stats (extended stats includes common stats) */\r
+ rte_eth_stats_get(ctx->io_cfg.port[i], &stats);\r
+ printf("DPDK stats:\n");\r
+ printf("** Port %hhu **\n", ctx->io_cfg.port[i]);\r
+ printf("ierrors:\t%lu\n", stats.ierrors);\r
+ printf("oerrors:\t%lu\n", stats.oerrors);\r
+ printf("ipackets:\t%lu\n", stats.ipackets);\r
+ printf("opackets:\t%lu\n", stats.opackets);\r
+ printf("imissed:\t%lu\n", stats.imissed);\r
+ printf("rx_nombuf:\t%lu\n", stats.rx_nombuf);\r
+ }\r
+ return ;\r
+}\r
+#endif\r
+/* Check the link status of all ports in up to 9s, and print them finally */\r
+static void check_port_link_status(uint8_t portid)\r
+{\r
+#define CHECK_INTERVAL 100 /* 100ms */\r
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */\r
+ uint8_t count, all_ports_up, print_flag = 0;\r
+ struct rte_eth_link link;\r
+\r
+ printf("\nChecking link status");\r
+ fflush(stdout);\r
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {\r
+ all_ports_up = 1;\r
+ memset(&link, 0, sizeof(link));\r
+ rte_eth_link_get_nowait(portid, &link);\r
+\r
+ /* print link status if flag set */\r
+ if (print_flag == 1) {\r
+ if (link.link_status)\r
+ printf("Port %d Link Up - speed %u "\r
+ "Mbps - %s\n", (uint8_t)portid,\r
+ (unsigned)link.link_speed,\r
+ (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?\r
+ ("full-duplex") : ("half-duplex\n"));\r
+ else\r
+ printf("Port %d Link Down\n",\r
+ (uint8_t)portid);\r
+ }\r
+ /* clear all_ports_up flag if any link down */\r
+ if (link.link_status == ETH_LINK_DOWN) {\r
+ all_ports_up = 0;\r
+ break;\r
+ }\r
+ /* after finally printing all link status, get out */\r
+ if (print_flag == 1)\r
+ break;\r
+\r
+ if (all_ports_up == 0) {\r
+ printf(".");\r
+ fflush(stdout);\r
+ rte_delay_ms(CHECK_INTERVAL);\r
+ }\r
+\r
+ /* set the print_flag if all ports up or timeout */\r
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {\r
+ print_flag = 1;\r
+ printf(" ... done\n");\r
+ }\r
+ }\r
+}\r
+\r
+\r
+int xran_ethdi_init_dpdk_io(char *name, const struct xran_io_loop_cfg *io_cfg,\r
+ int *lcore_id, struct ether_addr *p_lls_cu_addr, struct ether_addr *p_ru_addr,\r
+ uint16_t cp_vlan, uint16_t up_vlan)\r
+{\r
+ uint16_t port[2] = {0xffff, 0xffff};\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+ int i;\r
+ char core_mask[64];\r
+ long c_mask=0;\r
+ char bbdev_wdev[32] = "";\r
+ char bbdev_vdev[32] = "";\r
+\r
+ char *argv[] = { name, /*"-c 0xFFFFF00000FFFFF"*/core_mask, "-n2", "--socket-mem=8192", "--proc-type=auto",\r
+ "--file-prefix", name, "-w", "0000:00:00.0", bbdev_wdev, bbdev_vdev};\r
+\r
+ if (io_cfg == NULL)\r
+ return 0;\r
+ if(io_cfg->bbdev_mode != XRAN_BBDEV_NOT_USED){\r
+ printf("BBDEV_FEC_ACCL_NR5G\n");\r
+ if (io_cfg->bbdev_mode == XRAN_BBDEV_MODE_HW_ON){\r
+ // hw-accelerated bbdev\r
+ printf("hw-accelerated bbdev %s\n", io_cfg->bbdev_dev[0]);\r
+ sprintf(bbdev_wdev, "-w %s", io_cfg->bbdev_dev[0]);\r
+ } else if (io_cfg->bbdev_mode == XRAN_BBDEV_MODE_HW_OFF){\r
+ // hw-accelerated bbdev disable\r
+ if(io_cfg->bbdev_dev[0]){\r
+ printf("hw-accelerated bbdev disable %s\n", io_cfg->bbdev_dev[0]);\r
+ sprintf(bbdev_wdev, "-b %s", io_cfg->bbdev_dev[0]);\r
+ }\r
+ sprintf(bbdev_wdev, "%s", "--vdev=baseband_turbo_sw");\r
+ } else {\r
+ rte_panic("Cannot init DPDK incorrect [bbdev_mode %d]\n", io_cfg->bbdev_mode);\r
+ }\r
+ }\r
+\r
+ c_mask = (long)(1L << io_cfg->core) |\r
+ (long)(1L << io_cfg->system_core) |\r
+ (long)(1L << io_cfg->pkt_proc_core) |\r
+ (long)(1L << io_cfg->pkt_aux_core) |\r
+ (long)(1L << io_cfg->timing_core);\r
+\r
+ printf("c_mask 0x%lx core %d system_core %d pkt_proc_core %d pkt_aux_core %d timing_core %d\n",\r
+ c_mask, io_cfg->core, io_cfg->system_core, io_cfg->pkt_proc_core, io_cfg->pkt_aux_core, io_cfg->timing_core);\r
+\r
+ snprintf(core_mask, sizeof(core_mask), "-c 0x%lx", c_mask);\r
+\r
+ ctx->io_cfg = *io_cfg;\r
+ ctx->ping_state = PING_IDLE;\r
+ ctx->known_peers = 1;\r
+ ctx->busy_poll_till = rte_rdtsc();\r
+ ctx->cp_vtag = cp_vlan;\r
+ ctx->up_vtag = up_vlan;\r
+\r
+ for (i = 0; i <= ID_BROADCAST; i++) /* Initialize all as broadcast */\r
+ memset(&ctx->entities[i], 0xFF, sizeof(ctx->entities[0]));\r
+\r
+ printf("%s: Calling rte_eal_init:", __FUNCTION__);\r
+ for (i = 0; i < RTE_DIM(argv); i++)\r
+ {\r
+ printf("%s ", argv[i]);\r
+ }\r
+ printf("\n");\r
+\r
+\r
+ /* This will return on system_core, which is not necessarily the\r
+ * one we're on right now. */\r
+ if (rte_eal_init(RTE_DIM(argv), argv) < 0)\r
+ rte_panic("Cannot init EAL: %s\n", rte_strerror(rte_errno));\r
+\r
+ xran_init_mbuf_pool();\r
+\r
+#ifdef RTE_LIBRTE_PDUMP\r
+ /* initialize packet capture framework */\r
+ rte_pdump_init(NULL);\r
+#endif\r
+\r
+ /* Timers. */\r
+ rte_timer_subsystem_init();\r
+ rte_timer_init(&ctx->timer_ping);\r
+ rte_timer_init(&ctx->timer_sync);\r
+ rte_timer_init(&ctx->timer_tx);\r
+\r
+ *lcore_id = rte_get_next_lcore(rte_lcore_id(), 0, 0);\r
+\r
+ PANIC_ON(*lcore_id == RTE_MAX_LCORE, "out of lcores for io_loop()");\r
+\r
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {\r
+ for (i = 0; i < ETHDI_VF_MAX; i ++){\r
+ if(io_cfg->dpdk_dev[i]){\r
+ if (rte_eth_dev_attach(io_cfg->dpdk_dev[i], &port[i]) != 0 ||\r
+ rte_eth_dev_count_avail() == 0)\r
+ errx(1, "Network port doesn't exist.");\r
+ xran_init_port(port[i], p_lls_cu_addr);\r
+ } else {\r
+ printf("no DPDK port provided\n");\r
+ }\r
+ if(i==0){\r
+ ctx->tx_ring[i] = rte_ring_create("tx_ring_up", NUM_MBUFS,\r
+ rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);\r
+ ctx->rx_ring[i] = rte_ring_create("rx_ring_up", NUM_MBUFS,\r
+ rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);\r
+ ctx->pkt_dump_ring[i] = rte_ring_create("pkt_dump_ring_up", NUM_MBUFS,\r
+ rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);\r
+ }else {\r
+ ctx->tx_ring[i] = rte_ring_create("tx_ring_cp", NUM_MBUFS,\r
+ rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);\r
+ ctx->rx_ring[i] = rte_ring_create("rx_ring_cp", NUM_MBUFS,\r
+ rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);\r
+ ctx->pkt_dump_ring[i] = rte_ring_create("pkt_dump_ring_cp", NUM_MBUFS,\r
+ rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);\r
+ }\r
+ if(io_cfg->dpdk_dev[i])\r
+ check_port_link_status(port[i]);\r
+ }\r
+ } else {\r
+ rte_panic("ethdi_dpdk_io_loop() failed to start with RTE_PROC_SECONDARY\n");\r
+ }\r
+ PANIC_ON(ctx->tx_ring == NULL, "failed to allocate tx ring");\r
+ PANIC_ON(ctx->rx_ring == NULL, "failed to allocate rx ring");\r
+ PANIC_ON(ctx->pkt_dump_ring == NULL, "failed to allocate pkt dumping ring");\r
+ for (i = 0; i < ETHDI_VF_MAX; i++){\r
+ ctx->io_cfg.port[i] = port[i];\r
+ print_dbg("port_id 0x%04x\n", ctx->io_cfg.port[i]);\r
+ }\r
+\r
+ if(io_cfg->dpdk_dev[ETHDI_UP_VF]){\r
+ rte_eth_macaddr_get(port[ETHDI_UP_VF], &ctx->entities[io_cfg->id]);\r
+ ether_addr_copy(p_ru_addr, &ctx->entities[ID_RU]);\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+static inline uint16_t xran_tx_from_ring(int port, struct rte_ring *r)\r
+{\r
+ struct rte_mbuf *mbufs[BURST_SIZE];\r
+ uint16_t dequeued, sent = 0;\r
+ uint32_t remaining;\r
+ int i;\r
+ long t1 = MLogTick();\r
+\r
+ dequeued = rte_ring_dequeue_burst(r, (void **)mbufs, BURST_SIZE,\r
+ &remaining);\r
+ if (!dequeued)\r
+ return 0; /* Nothing to send. */\r
+\r
+ while (1) { /* When tx queue is full it is trying again till succeed */\r
+ t1 = MLogTick();\r
+ sent += rte_eth_tx_burst(port, 0, &mbufs[sent], dequeued - sent);\r
+\r
+ MLogTask(PID_RADIO_ETH_TX_BURST, t1, MLogTick());\r
+\r
+ if (sent == dequeued)\r
+ return remaining;\r
+ }\r
+}\r
+\r
+int32_t process_dpdk_io(void)\r
+{\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+ const struct xran_io_loop_cfg *const cfg = &(xran_ethdi_get_ctx()->io_cfg);\r
+ const int port[ETHDI_VF_MAX] = {cfg->port[ETHDI_UP_VF], cfg->port[ETHDI_CP_VF]};\r
+ int port_id = 0;\r
+\r
+ for (port_id = 0; port_id < ETHDI_VF_MAX; port_id++){\r
+ struct rte_mbuf *mbufs[BURST_RX_IO_SIZE];\r
+ if(port[port_id] == 0xFF)\r
+ return 0;\r
+ /* RX */\r
+ const uint16_t rxed = rte_eth_rx_burst(port[port_id], 0, mbufs, BURST_RX_IO_SIZE);\r
+ if (rxed != 0){\r
+ unsigned enq_n = 0;\r
+ long t1 = MLogTick();\r
+ enq_n = rte_ring_enqueue_burst(ctx->rx_ring[port_id], (void*)mbufs, rxed, NULL);\r
+ if(rxed - enq_n)\r
+ rte_panic("error enq\n");\r
+ MLogTask(PID_RADIO_RX_VALIDATE, t1, MLogTick());\r
+ }\r
+\r
+ /* TX */\r
+ const uint16_t sent = xran_tx_from_ring(port[port_id], ctx->tx_ring[port_id]);\r
+\r
+ if (XRAN_STOPPED == xran_if_current_state)\r
+ return -1;\r
+ }\r
+\r
+ if (XRAN_STOPPED == xran_if_current_state)\r
+ return -1;\r
+\r
+ return 0;\r
+}\r
+\r
+#if 0\r
+static inline void xran_process_rx_burst(struct rte_mbuf *mbufs[], uint16_t n_mbufs,\r
+ uint64_t rx_time)\r
+{\r
+ int i;\r
+\r
+ if (!n_mbufs)\r
+ return;\r
+\r
+ for (i = 0; i < n_mbufs; ++i)\r
+ {\r
+ if (xran_ethdi_filter_packet(mbufs[i], rx_time) == MBUF_FREE)\r
+ rte_pktmbuf_free(mbufs[i]);\r
+ }\r
+\r
+#ifdef DPDKIO_LATENCY_DEBUG\r
+ struct timeval tv_now, tv_diff;\r
+\r
+ gettimeofday(&tv_now, NULL);\r
+ if (n_mbufs > 1)\r
+ nlog("Warning - received %d mbufs in a row", n_mbufs);\r
+\r
+ timersub(&tv_now, &rx_time, &tv_diff);\r
+ nlog("rx processing took %d usec", tv_diff.tv_usec);\r
+#endif\r
+}\r
+\r
+/*\r
+ * This is the main DPDK-IO loop.\r
+ * This will sleep if there's no packets incoming and there's\r
+ * no work enqueued, sleep lenth is defined in IDLE_SLEEP_MICROSECS\r
+ */\r
+int xran_ethdi_dpdk_io_loop(void *io_loop_cfg)\r
+{\r
+ struct sched_param sched_param;\r
+ int res = 0;\r
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();\r
+ const struct xran_io_loop_cfg *const cfg = &(xran_ethdi_get_ctx()->io_cfg);\r
+ const int port[ETHDI_VF_MAX] = {cfg->port[ETHDI_UP_VF], cfg->port[ETHDI_CP_VF]};\r
+\r
+ printf("%s [PORT: %d %d] [CPU %2d] [PID: %6d]\n", __FUNCTION__, port[ETHDI_UP_VF], port[ETHDI_CP_VF] , rte_lcore_id(), getpid());\r
+\r
+ printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__, rte_lcore_id(), getpid());\r
+ sched_param.sched_priority = XRAN_THREAD_DEFAULT_PRIO;\r
+ if ((res = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched_param))) {\r
+ printf("priority is not changed: coreId = %d, result1 = %d\n",rte_lcore_id(), res);\r
+ }\r
+\r
+ for (;;){\r
+ if(process_dpdk_io()!=0)\r
+ break;\r
+ }\r
+\r
+ fflush(stderr);\r
+ fflush(stdout);\r
+ puts("IO loop finished");\r
+\r
+ return 0;\r
+}\r
+#endif\r
+\r