app/eventdev: add options for event timer adapter
[dpdk.git] / app / test-pmd / testpmd.c
index 12430ac..29e789e 100644 (file)
@@ -12,6 +12,7 @@
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <errno.h>
+#include <stdbool.h>
 
 #include <sys/queue.h>
 #include <sys/stat.h>
@@ -38,6 +39,7 @@
 #include <rte_mempool.h>
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
+#include <rte_mbuf_pool_ops.h>
 #include <rte_interrupts.h>
 #include <rte_pci.h>
 #include <rte_ether.h>
@@ -90,6 +92,24 @@ uint8_t socket_num = UMA_NO_CONFIG;
  */
 uint8_t mp_anon = 0;
 
+/*
+ * Store specified sockets on which memory pool to be used by ports
+ * is allocated.
+ */
+uint8_t port_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which RX ring to be used by ports
+ * is allocated.
+ */
+uint8_t rxring_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which TX ring to be used by ports
+ * is allocated.
+ */
+uint8_t txring_numa[RTE_MAX_ETHPORTS];
+
 /*
  * Record the Ethernet address of peer target ports to which packets are
  * forwarded.
@@ -191,9 +211,10 @@ queueid_t nb_txq = 1; /**< Number of TX queues per port. */
 
 /*
  * Configurable number of RX/TX ring descriptors.
+ * Defaults are supplied by drivers via ethdev.
  */
-#define RTE_TEST_RX_DESC_DEFAULT 128
-#define RTE_TEST_TX_DESC_DEFAULT 512
+#define RTE_TEST_RX_DESC_DEFAULT 0
+#define RTE_TEST_TX_DESC_DEFAULT 0
 uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; /**< Number of RX descriptors. */
 uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; /**< Number of TX descriptors. */
 
@@ -265,6 +286,8 @@ uint8_t lsc_interrupt = 1; /* enabled by default */
  */
 uint8_t rmv_interrupt = 1; /* enabled by default */
 
+uint8_t hot_plug = 0; /**< hotplug disabled by default. */
+
 /*
  * Display or mask ether events
  * Default to all events except VF_MBOX
@@ -305,13 +328,13 @@ lcoreid_t latencystats_lcore_id = -1;
  */
 struct rte_eth_rxmode rx_mode = {
        .max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */
-       .offloads = (DEV_RX_OFFLOAD_VLAN_FILTER |
-                    DEV_RX_OFFLOAD_VLAN_STRIP |
-                    DEV_RX_OFFLOAD_CRC_STRIP),
+       .offloads = DEV_RX_OFFLOAD_CRC_STRIP,
        .ignore_offload_bitfield = 1,
 };
 
-struct rte_eth_txmode tx_mode;
+struct rte_eth_txmode tx_mode = {
+       .offloads = DEV_TX_OFFLOAD_MBUF_FAST_FREE,
+};
 
 struct rte_fdir_conf fdir_conf = {
        .mode = RTE_FDIR_MODE_NONE,
@@ -372,6 +395,12 @@ static void check_all_ports_link_status(uint32_t port_mask);
 static int eth_event_callback(portid_t port_id,
                              enum rte_eth_event_type type,
                              void *param, void *ret_param);
+static void eth_dev_event_callback(char *device_name,
+                               enum rte_dev_event_type type,
+                               void *param);
+static int eth_dev_event_callback_register(void);
+static int eth_dev_event_callback_unregister(void);
+
 
 /*
  * Check if all the ports are started.
@@ -497,6 +526,8 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf,
                rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL);
        } else {
                /* wrapper to rte_mempool_create() */
+               TESTPMD_LOG(INFO, "preferred mempool ops selected: %s\n",
+                               rte_mbuf_best_mempool_ops());
                rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf,
                        mb_mempool_cache, 0, mbuf_seg_size, socket_id);
        }
@@ -532,6 +563,98 @@ check_socket_id(const unsigned int socket_id)
        return 0;
 }
 
+/*
+ * Get the allowed maximum number of RX queues.
+ * *pid return the port id which has minimal value of
+ * max_rx_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_rxq(portid_t *pid)
+{
+       queueid_t allowed_max_rxq = MAX_QUEUE_ID;
+       portid_t pi;
+       struct rte_eth_dev_info dev_info;
+
+       RTE_ETH_FOREACH_DEV(pi) {
+               rte_eth_dev_info_get(pi, &dev_info);
+               if (dev_info.max_rx_queues < allowed_max_rxq) {
+                       allowed_max_rxq = dev_info.max_rx_queues;
+                       *pid = pi;
+               }
+       }
+       return allowed_max_rxq;
+}
+
+/*
+ * Check input rxq is valid or not.
+ * If input rxq is not greater than any of maximum number
+ * of RX queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_rxq(queueid_t rxq)
+{
+       queueid_t allowed_max_rxq;
+       portid_t pid = 0;
+
+       allowed_max_rxq = get_allowed_max_nb_rxq(&pid);
+       if (rxq > allowed_max_rxq) {
+               printf("Fail: input rxq (%u) can't be greater "
+                      "than max_rx_queues (%u) of port %u\n",
+                      rxq,
+                      allowed_max_rxq,
+                      pid);
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ * Get the allowed maximum number of TX queues.
+ * *pid return the port id which has minimal value of
+ * max_tx_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_txq(portid_t *pid)
+{
+       queueid_t allowed_max_txq = MAX_QUEUE_ID;
+       portid_t pi;
+       struct rte_eth_dev_info dev_info;
+
+       RTE_ETH_FOREACH_DEV(pi) {
+               rte_eth_dev_info_get(pi, &dev_info);
+               if (dev_info.max_tx_queues < allowed_max_txq) {
+                       allowed_max_txq = dev_info.max_tx_queues;
+                       *pid = pi;
+               }
+       }
+       return allowed_max_txq;
+}
+
+/*
+ * Check input txq is valid or not.
+ * If input txq is not greater than any of maximum number
+ * of TX queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_txq(queueid_t txq)
+{
+       queueid_t allowed_max_txq;
+       portid_t pid = 0;
+
+       allowed_max_txq = get_allowed_max_nb_txq(&pid);
+       if (txq > allowed_max_txq) {
+               printf("Fail: input txq (%u) can't be greater "
+                      "than max_tx_queues (%u) of port %u\n",
+                      txq,
+                      allowed_max_txq,
+                      pid);
+               return -1;
+       }
+       return 0;
+}
+
 static void
 init_config(void)
 {
@@ -573,10 +696,14 @@ init_config(void)
 
        RTE_ETH_FOREACH_DEV(pid) {
                port = &ports[pid];
-               /* Apply default Tx configuration for all ports */
+               /* Apply default TxRx configuration for all ports */
                port->dev_conf.txmode = tx_mode;
+               port->dev_conf.rxmode = rx_mode;
                rte_eth_dev_info_get(pid, &port->dev_info);
-
+               if (!(port->dev_info.tx_offload_capa &
+                     DEV_TX_OFFLOAD_MBUF_FAST_FREE))
+                       port->dev_conf.txmode.offloads &=
+                               ~DEV_TX_OFFLOAD_MBUF_FAST_FREE;
                if (numa_support) {
                        if (port_numa[pid] != NUMA_NO_CONFIG)
                                port_per_socket[port_numa[pid]]++;
@@ -1547,20 +1674,6 @@ start_port(portid_t pid)
                        }
                }
 
-               for (event_type = RTE_ETH_EVENT_UNKNOWN;
-                    event_type < RTE_ETH_EVENT_MAX;
-                    event_type++) {
-                       diag = rte_eth_dev_callback_register(pi,
-                                                       event_type,
-                                                       eth_event_callback,
-                                                       NULL);
-                       if (diag) {
-                               printf("Failed to setup even callback for event %d\n",
-                                       event_type);
-                               return -1;
-                       }
-               }
-
                /* start port */
                if (rte_eth_dev_start(pi) < 0) {
                        printf("Fail to start port %d\n", pi);
@@ -1587,6 +1700,20 @@ start_port(portid_t pid)
                need_check_link_status = 1;
        }
 
+       for (event_type = RTE_ETH_EVENT_UNKNOWN;
+            event_type < RTE_ETH_EVENT_MAX;
+            event_type++) {
+               diag = rte_eth_dev_callback_register(RTE_ETH_ALL,
+                                               event_type,
+                                               eth_event_callback,
+                                               NULL);
+               if (diag) {
+                       printf("Failed to setup even callback for event %d\n",
+                               event_type);
+                       return -1;
+               }
+       }
+
        if (need_check_link_status == 1 && !no_link_check)
                check_all_ports_link_status(RTE_PORT_ALL);
        else if (need_check_link_status == 0)
@@ -1736,6 +1863,39 @@ reset_port(portid_t pid)
        printf("Done\n");
 }
 
+static int
+eth_dev_event_callback_register(void)
+{
+       int ret;
+
+       /* register the device event callback */
+       ret = rte_dev_event_callback_register(NULL,
+               eth_dev_event_callback, NULL);
+       if (ret) {
+               printf("Failed to register device event callback\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+static int
+eth_dev_event_callback_unregister(void)
+{
+       int ret;
+
+       /* unregister the device event callback */
+       ret = rte_dev_event_callback_unregister(NULL,
+               eth_dev_event_callback, NULL);
+       if (ret < 0) {
+               printf("Failed to unregister device event callback\n");
+               return -1;
+       }
+
+       return 0;
+}
+
 void
 attach_port(char *identifier)
 {
@@ -1799,6 +1959,7 @@ void
 pmd_test_exit(void)
 {
        portid_t pt_id;
+       int ret;
 
        if (test_done == 0)
                stop_packet_forwarding();
@@ -1812,6 +1973,19 @@ pmd_test_exit(void)
                        close_port(pt_id);
                }
        }
+
+       if (hot_plug) {
+               ret = rte_dev_event_monitor_stop();
+               if (ret)
+                       RTE_LOG(ERR, EAL,
+                               "fail to stop device event monitor.");
+
+               ret = eth_dev_event_callback_unregister();
+               if (ret)
+                       RTE_LOG(ERR, EAL,
+                               "fail to unregister all event callbacks.");
+       }
+
        printf("\nBye...\n");
 }
 
@@ -1909,6 +2083,8 @@ eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
                [RTE_ETH_EVENT_VF_MBOX] = "VF Mbox",
                [RTE_ETH_EVENT_MACSEC] = "MACsec",
                [RTE_ETH_EVENT_INTR_RMV] = "device removal",
+               [RTE_ETH_EVENT_NEW] = "device probed",
+               [RTE_ETH_EVENT_DESTROY] = "device released",
                [RTE_ETH_EVENT_MAX] = NULL,
        };
 
@@ -1925,6 +2101,9 @@ eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
                fflush(stdout);
        }
 
+       if (port_id_is_invalid(port_id, DISABLED_WARN))
+               return 0;
+
        switch (type) {
        case RTE_ETH_EVENT_INTR_RMV:
                if (rte_eal_alarm_set(100000,
@@ -1937,6 +2116,37 @@ eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
        return 0;
 }
 
+/* This function is used by the interrupt thread */
+static void
+eth_dev_event_callback(char *device_name, enum rte_dev_event_type type,
+                            __rte_unused void *arg)
+{
+       if (type >= RTE_DEV_EVENT_MAX) {
+               fprintf(stderr, "%s called upon invalid event %d\n",
+                       __func__, type);
+               fflush(stderr);
+       }
+
+       switch (type) {
+       case RTE_DEV_EVENT_REMOVE:
+               RTE_LOG(ERR, EAL, "The device: %s has been removed!\n",
+                       device_name);
+               /* TODO: After finish failure handle, begin to stop
+                * packet forward, stop port, close port, detach port.
+                */
+               break;
+       case RTE_DEV_EVENT_ADD:
+               RTE_LOG(ERR, EAL, "The device: %s has been added!\n",
+                       device_name);
+               /* TODO: After finish kernel driver binding,
+                * begin to attach port.
+                */
+               break;
+       default:
+               break;
+       }
+}
+
 static int
 set_tx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port)
 {
@@ -2061,7 +2271,6 @@ init_port_config(void)
 
        RTE_ETH_FOREACH_DEV(pid) {
                port = &ports[pid];
-               port->dev_conf.rxmode = rx_mode;
                port->dev_conf.fdir_conf = fdir_conf;
                if (nb_rxq > 1) {
                        port->dev_conf.rx_adv_conf.rss_conf.rss_key = NULL;
@@ -2224,6 +2433,9 @@ init_port_dcb_config(portid_t pid,
        /* Enter DCB configuration status */
        dcb_config = 1;
 
+       port_conf.rxmode = rte_port->dev_conf.rxmode;
+       port_conf.txmode = rte_port->dev_conf.txmode;
+
        /*set configuration of DCB in vt mode and DCB in non-vt mode*/
        retval = get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en);
        if (retval < 0)
@@ -2350,8 +2562,9 @@ signal_handler(int signum)
 int
 main(int argc, char** argv)
 {
-       int  diag;
+       int diag;
        portid_t port_id;
+       int ret;
 
        signal(SIGINT, signal_handler);
        signal(SIGTERM, signal_handler);
@@ -2419,6 +2632,18 @@ main(int argc, char** argv)
                       nb_rxq, nb_txq);
 
        init_config();
+
+       if (hot_plug) {
+               /* enable hot plug monitoring */
+               ret = rte_dev_event_monitor_start();
+               if (ret) {
+                       rte_errno = EINVAL;
+                       return -1;
+               }
+               eth_dev_event_callback_register();
+
+       }
+
        if (start_port(RTE_PORT_ALL) != 0)
                rte_exit(EXIT_FAILURE, "Start ports failed\n");