net/mlx5: add queue start and stop
[dpdk.git] / drivers / net / mlx5 / linux / mlx5_os.c
index dea4ee7..9622eb3 100644 (file)
 #include <linux/ethtool.h>
 #include <fcntl.h>
 
-/* Verbs header. */
-/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
-#ifdef PEDANTIC
-#pragma GCC diagnostic ignored "-Wpedantic"
-#endif
-#include <infiniband/verbs.h>
-#ifdef PEDANTIC
-#pragma GCC diagnostic error "-Wpedantic"
-#endif
-
 #include <rte_malloc.h>
 #include <rte_ethdev_driver.h>
 #include <rte_ethdev_pci.h>
 #define MLX5DV_CONTEXT_FLAGS_CQE_128B_COMP (1 << 4)
 #endif
 
+static const char *MZ_MLX5_PMD_SHARED_DATA = "mlx5_pmd_shared_data";
+
+/* Spinlock for mlx5_shared_data allocation. */
+static rte_spinlock_t mlx5_shared_data_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* Process local data for secondary processes. */
+static struct mlx5_local_data mlx5_local_data;
+
 /**
- * Get MAC address by querying netdevice.
+ * Set the completion channel file descriptor interrupt as non-blocking.
  *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[out] mac
- *   MAC address output buffer.
+ * @param[in] rxq_obj
+ *   Pointer to RQ channel object, which includes the channel fd
+ *
+ * @param[out] fd
+ *   The file descriptor (representing the intetrrupt) used in this channel.
  *
  * @return
- *   0 on success, a negative errno value otherwise and rte_errno is set.
+ *   0 on successfully setting the fd to non-blocking, non-zero otherwise.
  */
-static int
-mlx5_get_mac(struct rte_eth_dev *dev, uint8_t (*mac)[RTE_ETHER_ADDR_LEN])
+int
+mlx5_os_set_nonblock_channel_fd(int fd)
 {
-       struct ifreq request;
-       int ret;
+       int flags;
 
-       ret = mlx5_ifreq(dev, SIOCGIFHWADDR, &request);
-       if (ret)
-               return ret;
-       memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
-       return 0;
+       flags = fcntl(fd, F_GETFL);
+       return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
 }
 
 /**
@@ -380,6 +375,109 @@ mlx5_os_free_shared_dr(struct mlx5_priv *priv)
        mlx5_free_table_hash_list(priv);
 }
 
+/**
+ * Initialize shared data between primary and secondary process.
+ *
+ * A memzone is reserved by primary process and secondary processes attach to
+ * the memzone.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_init_shared_data(void)
+{
+       const struct rte_memzone *mz;
+       int ret = 0;
+
+       rte_spinlock_lock(&mlx5_shared_data_lock);
+       if (mlx5_shared_data == NULL) {
+               if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+                       /* Allocate shared memory. */
+                       mz = rte_memzone_reserve(MZ_MLX5_PMD_SHARED_DATA,
+                                                sizeof(*mlx5_shared_data),
+                                                SOCKET_ID_ANY, 0);
+                       if (mz == NULL) {
+                               DRV_LOG(ERR,
+                                       "Cannot allocate mlx5 shared data");
+                               ret = -rte_errno;
+                               goto error;
+                       }
+                       mlx5_shared_data = mz->addr;
+                       memset(mlx5_shared_data, 0, sizeof(*mlx5_shared_data));
+                       rte_spinlock_init(&mlx5_shared_data->lock);
+               } else {
+                       /* Lookup allocated shared memory. */
+                       mz = rte_memzone_lookup(MZ_MLX5_PMD_SHARED_DATA);
+                       if (mz == NULL) {
+                               DRV_LOG(ERR,
+                                       "Cannot attach mlx5 shared data");
+                               ret = -rte_errno;
+                               goto error;
+                       }
+                       mlx5_shared_data = mz->addr;
+                       memset(&mlx5_local_data, 0, sizeof(mlx5_local_data));
+               }
+       }
+error:
+       rte_spinlock_unlock(&mlx5_shared_data_lock);
+       return ret;
+}
+
+/**
+ * PMD global initialization.
+ *
+ * Independent from individual device, this function initializes global
+ * per-PMD data structures distinguishing primary and secondary processes.
+ * Hence, each initialization is called once per a process.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_init_once(void)
+{
+       struct mlx5_shared_data *sd;
+       struct mlx5_local_data *ld = &mlx5_local_data;
+       int ret = 0;
+
+       if (mlx5_init_shared_data())
+               return -rte_errno;
+       sd = mlx5_shared_data;
+       MLX5_ASSERT(sd);
+       rte_spinlock_lock(&sd->lock);
+       switch (rte_eal_process_type()) {
+       case RTE_PROC_PRIMARY:
+               if (sd->init_done)
+                       break;
+               LIST_INIT(&sd->mem_event_cb_list);
+               rte_rwlock_init(&sd->mem_event_rwlock);
+               rte_mem_event_callback_register("MLX5_MEM_EVENT_CB",
+                                               mlx5_mr_mem_event_cb, NULL);
+               ret = mlx5_mp_init_primary(MLX5_MP_NAME,
+                                          mlx5_mp_os_primary_handle);
+               if (ret)
+                       goto out;
+               sd->init_done = true;
+               break;
+       case RTE_PROC_SECONDARY:
+               if (ld->init_done)
+                       break;
+               ret = mlx5_mp_init_secondary(MLX5_MP_NAME,
+                                            mlx5_mp_os_secondary_handle);
+               if (ret)
+                       goto out;
+               ++sd->secondary_cnt;
+               ld->init_done = true;
+               break;
+       default:
+               break;
+       }
+out:
+       rte_spinlock_unlock(&sd->lock);
+       return ret;
+}
+
 /**
  * Spawn an Ethernet device from Verbs information.
  *
@@ -2087,291 +2185,6 @@ mlx5_os_read_dev_stat(struct mlx5_priv *priv, const char *ctr_name,
        return 1;
 }
 
-/**
- * Read device counters table.
- *
- * @param dev
- *   Pointer to Ethernet device.
- * @param[out] stats
- *   Counters table output buffer.
- *
- * @return
- *   0 on success and stats is filled, negative errno value otherwise and
- *   rte_errno is set.
- */
-int
-mlx5_os_read_dev_counters(struct rte_eth_dev *dev, uint64_t *stats)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
-       unsigned int i;
-       struct ifreq ifr;
-       unsigned int stats_sz = xstats_ctrl->stats_n * sizeof(uint64_t);
-       unsigned char et_stat_buf[sizeof(struct ethtool_stats) + stats_sz];
-       struct ethtool_stats *et_stats = (struct ethtool_stats *)et_stat_buf;
-       int ret;
-
-       et_stats->cmd = ETHTOOL_GSTATS;
-       et_stats->n_stats = xstats_ctrl->stats_n;
-       ifr.ifr_data = (caddr_t)et_stats;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
-       if (ret) {
-               DRV_LOG(WARNING,
-                       "port %u unable to read statistic values from device",
-                       dev->data->port_id);
-               return ret;
-       }
-       for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
-               if (xstats_ctrl->info[i].dev) {
-                       ret = mlx5_os_read_dev_stat(priv,
-                                           xstats_ctrl->info[i].ctr_name,
-                                           &stats[i]);
-                       /* return last xstats counter if fail to read. */
-                       if (ret == 0)
-                               xstats_ctrl->xstats[i] = stats[i];
-                       else
-                               stats[i] = xstats_ctrl->xstats[i];
-               } else {
-                       stats[i] = (uint64_t)
-                               et_stats->data[xstats_ctrl->dev_table_idx[i]];
-               }
-       }
-       return 0;
-}
-
-/**
- * Query the number of statistics provided by ETHTOOL.
- *
- * @param dev
- *   Pointer to Ethernet device.
- *
- * @return
- *   Number of statistics on success, negative errno value otherwise and
- *   rte_errno is set.
- */
-int
-mlx5_os_get_stats_n(struct rte_eth_dev *dev)
-{
-       struct ethtool_drvinfo drvinfo;
-       struct ifreq ifr;
-       int ret;
-
-       drvinfo.cmd = ETHTOOL_GDRVINFO;
-       ifr.ifr_data = (caddr_t)&drvinfo;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
-       if (ret) {
-               DRV_LOG(WARNING, "port %u unable to query number of statistics",
-                       dev->data->port_id);
-               return ret;
-       }
-       return drvinfo.n_stats;
-}
-
-static const struct mlx5_counter_ctrl mlx5_counters_init[] = {
-       {
-               .dpdk_name = "rx_port_unicast_bytes",
-               .ctr_name = "rx_vport_unicast_bytes",
-       },
-       {
-               .dpdk_name = "rx_port_multicast_bytes",
-               .ctr_name = "rx_vport_multicast_bytes",
-       },
-       {
-               .dpdk_name = "rx_port_broadcast_bytes",
-               .ctr_name = "rx_vport_broadcast_bytes",
-       },
-       {
-               .dpdk_name = "rx_port_unicast_packets",
-               .ctr_name = "rx_vport_unicast_packets",
-       },
-       {
-               .dpdk_name = "rx_port_multicast_packets",
-               .ctr_name = "rx_vport_multicast_packets",
-       },
-       {
-               .dpdk_name = "rx_port_broadcast_packets",
-               .ctr_name = "rx_vport_broadcast_packets",
-       },
-       {
-               .dpdk_name = "tx_port_unicast_bytes",
-               .ctr_name = "tx_vport_unicast_bytes",
-       },
-       {
-               .dpdk_name = "tx_port_multicast_bytes",
-               .ctr_name = "tx_vport_multicast_bytes",
-       },
-       {
-               .dpdk_name = "tx_port_broadcast_bytes",
-               .ctr_name = "tx_vport_broadcast_bytes",
-       },
-       {
-               .dpdk_name = "tx_port_unicast_packets",
-               .ctr_name = "tx_vport_unicast_packets",
-       },
-       {
-               .dpdk_name = "tx_port_multicast_packets",
-               .ctr_name = "tx_vport_multicast_packets",
-       },
-       {
-               .dpdk_name = "tx_port_broadcast_packets",
-               .ctr_name = "tx_vport_broadcast_packets",
-       },
-       {
-               .dpdk_name = "rx_wqe_err",
-               .ctr_name = "rx_wqe_err",
-       },
-       {
-               .dpdk_name = "rx_crc_errors_phy",
-               .ctr_name = "rx_crc_errors_phy",
-       },
-       {
-               .dpdk_name = "rx_in_range_len_errors_phy",
-               .ctr_name = "rx_in_range_len_errors_phy",
-       },
-       {
-               .dpdk_name = "rx_symbol_err_phy",
-               .ctr_name = "rx_symbol_err_phy",
-       },
-       {
-               .dpdk_name = "tx_errors_phy",
-               .ctr_name = "tx_errors_phy",
-       },
-       {
-               .dpdk_name = "rx_out_of_buffer",
-               .ctr_name = "out_of_buffer",
-               .dev = 1,
-       },
-       {
-               .dpdk_name = "tx_packets_phy",
-               .ctr_name = "tx_packets_phy",
-       },
-       {
-               .dpdk_name = "rx_packets_phy",
-               .ctr_name = "rx_packets_phy",
-       },
-       {
-               .dpdk_name = "tx_discards_phy",
-               .ctr_name = "tx_discards_phy",
-       },
-       {
-               .dpdk_name = "rx_discards_phy",
-               .ctr_name = "rx_discards_phy",
-       },
-       {
-               .dpdk_name = "tx_bytes_phy",
-               .ctr_name = "tx_bytes_phy",
-       },
-       {
-               .dpdk_name = "rx_bytes_phy",
-               .ctr_name = "rx_bytes_phy",
-       },
-       /* Representor only */
-       {
-               .dpdk_name = "rx_packets",
-               .ctr_name = "vport_rx_packets",
-       },
-       {
-               .dpdk_name = "rx_bytes",
-               .ctr_name = "vport_rx_bytes",
-       },
-       {
-               .dpdk_name = "tx_packets",
-               .ctr_name = "vport_tx_packets",
-       },
-       {
-               .dpdk_name = "tx_bytes",
-               .ctr_name = "vport_tx_bytes",
-       },
-};
-
-static const unsigned int xstats_n = RTE_DIM(mlx5_counters_init);
-
-/**
- * Init the structures to read device counters.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-void
-mlx5_os_stats_init(struct rte_eth_dev *dev)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
-       struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
-       unsigned int i;
-       unsigned int j;
-       struct ifreq ifr;
-       struct ethtool_gstrings *strings = NULL;
-       unsigned int dev_stats_n;
-       unsigned int str_sz;
-       int ret;
-
-       /* So that it won't aggregate for each init. */
-       xstats_ctrl->mlx5_stats_n = 0;
-       ret = mlx5_os_get_stats_n(dev);
-       if (ret < 0) {
-               DRV_LOG(WARNING, "port %u no extended statistics available",
-                       dev->data->port_id);
-               return;
-       }
-       dev_stats_n = ret;
-       /* Allocate memory to grab stat names and values. */
-       str_sz = dev_stats_n * ETH_GSTRING_LEN;
-       strings = (struct ethtool_gstrings *)
-                 mlx5_malloc(0, str_sz + sizeof(struct ethtool_gstrings), 0,
-                             SOCKET_ID_ANY);
-       if (!strings) {
-               DRV_LOG(WARNING, "port %u unable to allocate memory for xstats",
-                    dev->data->port_id);
-               return;
-       }
-       strings->cmd = ETHTOOL_GSTRINGS;
-       strings->string_set = ETH_SS_STATS;
-       strings->len = dev_stats_n;
-       ifr.ifr_data = (caddr_t)strings;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
-       if (ret) {
-               DRV_LOG(WARNING, "port %u unable to get statistic names",
-                       dev->data->port_id);
-               goto free;
-       }
-       for (i = 0; i != dev_stats_n; ++i) {
-               const char *curr_string = (const char *)
-                       &strings->data[i * ETH_GSTRING_LEN];
-
-               for (j = 0; j != xstats_n; ++j) {
-                       if (!strcmp(mlx5_counters_init[j].ctr_name,
-                                   curr_string)) {
-                               unsigned int idx = xstats_ctrl->mlx5_stats_n++;
-
-                               xstats_ctrl->dev_table_idx[idx] = i;
-                               xstats_ctrl->info[idx] = mlx5_counters_init[j];
-                               break;
-                       }
-               }
-       }
-       /* Add dev counters. */
-       for (i = 0; i != xstats_n; ++i) {
-               if (mlx5_counters_init[i].dev) {
-                       unsigned int idx = xstats_ctrl->mlx5_stats_n++;
-
-                       xstats_ctrl->info[idx] = mlx5_counters_init[i];
-                       xstats_ctrl->hw_stats[idx] = 0;
-               }
-       }
-       MLX5_ASSERT(xstats_ctrl->mlx5_stats_n <= MLX5_MAX_XSTATS);
-       xstats_ctrl->stats_n = dev_stats_n;
-       /* Copy to base at first time. */
-       ret = mlx5_os_read_dev_counters(dev, xstats_ctrl->base);
-       if (ret)
-               DRV_LOG(ERR, "port %u cannot read device counters: %s",
-                       dev->data->port_id, strerror(rte_errno));
-       mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
-       stats_ctrl->imissed = 0;
-free:
-       mlx5_free(strings);
-}
-
 /**
  * Set the reg_mr and dereg_mr call backs
  *
@@ -2462,6 +2275,46 @@ mlx5_os_vf_mac_addr_modify(struct mlx5_priv *priv,
                (priv->nl_socket_route, iface_idx, mac_addr, vf_index);
 }
 
+/**
+ * Set device promiscuous mode
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param enable
+ *   0 - promiscuous is disabled, otherwise - enabled
+ *
+ * @return
+ *   0 on success, a negative error value otherwise
+ */
+int
+mlx5_os_set_promisc(struct rte_eth_dev *dev, int enable)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+
+       return mlx5_nl_promisc(priv->nl_socket_route,
+                              mlx5_ifindex(dev), !!enable);
+}
+
+/**
+ * Set device promiscuous mode
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param enable
+ *   0 - all multicase is disabled, otherwise - enabled
+ *
+ * @return
+ *   0 on success, a negative error value otherwise
+ */
+int
+mlx5_os_set_allmulti(struct rte_eth_dev *dev, int enable)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+
+       return mlx5_nl_allmulti(priv->nl_socket_route,
+                               mlx5_ifindex(dev), !!enable);
+}
+
 const struct eth_dev_ops mlx5_os_dev_ops = {
        .dev_configure = mlx5_dev_configure,
        .dev_start = mlx5_dev_start,
@@ -2490,6 +2343,10 @@ const struct eth_dev_ops mlx5_os_dev_ops = {
        .tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
        .rx_queue_release = mlx5_rx_queue_release,
        .tx_queue_release = mlx5_tx_queue_release,
+       .rx_queue_start = mlx5_rx_queue_start,
+       .rx_queue_stop = mlx5_rx_queue_stop,
+       .tx_queue_start = mlx5_tx_queue_start,
+       .tx_queue_stop = mlx5_tx_queue_stop,
        .flow_ctrl_get = mlx5_dev_get_flow_ctrl,
        .flow_ctrl_set = mlx5_dev_set_flow_ctrl,
        .mac_addr_remove = mlx5_mac_addr_remove,
@@ -2531,6 +2388,10 @@ const struct eth_dev_ops mlx5_os_dev_sec_ops = {
        .fw_version_get = mlx5_fw_version_get,
        .dev_infos_get = mlx5_dev_infos_get,
        .read_clock = mlx5_txpp_read_clock,
+       .rx_queue_start = mlx5_rx_queue_start,
+       .rx_queue_stop = mlx5_rx_queue_stop,
+       .tx_queue_start = mlx5_tx_queue_start,
+       .tx_queue_stop = mlx5_tx_queue_stop,
        .rx_descriptor_status = mlx5_rx_descriptor_status,
        .tx_descriptor_status = mlx5_tx_descriptor_status,
        .rxq_info_get = mlx5_rxq_info_get,
@@ -2570,6 +2431,10 @@ const struct eth_dev_ops mlx5_os_dev_ops_isolate = {
        .tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
        .rx_queue_release = mlx5_rx_queue_release,
        .tx_queue_release = mlx5_tx_queue_release,
+       .rx_queue_start = mlx5_rx_queue_start,
+       .rx_queue_stop = mlx5_rx_queue_stop,
+       .tx_queue_start = mlx5_tx_queue_start,
+       .tx_queue_stop = mlx5_tx_queue_stop,
        .flow_ctrl_get = mlx5_dev_get_flow_ctrl,
        .flow_ctrl_set = mlx5_dev_set_flow_ctrl,
        .mac_addr_remove = mlx5_mac_addr_remove,