mlx5: add device configure/start/stop
authorAdrien Mazarguil <adrien.mazarguil@6wind.com>
Fri, 30 Oct 2015 18:52:33 +0000 (19:52 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Fri, 30 Oct 2015 21:22:12 +0000 (22:22 +0100)
This commit adds the remaining missing callbacks to make mlx5 usable.
Like mlx4, device start and stop are implemented on top of MAC RX flows.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Francesco Santoro <francesco.santoro@6wind.com>
Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
drivers/net/mlx5/Makefile
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_ethdev.c
drivers/net/mlx5/mlx5_trigger.c [new file with mode: 0644]

index 7b9c57b..028c22c 100644 (file)
@@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_txq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_trigger.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mac.c
 
index a241c28..aafa70b 100644 (file)
@@ -129,7 +129,11 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 }
 
 static const struct eth_dev_ops mlx5_dev_ops = {
+       .dev_configure = mlx5_dev_configure,
+       .dev_start = mlx5_dev_start,
+       .dev_stop = mlx5_dev_stop,
        .dev_close = mlx5_dev_close,
+       .dev_infos_get = mlx5_dev_infos_get,
        .rx_queue_setup = mlx5_rx_queue_setup,
        .tx_queue_setup = mlx5_tx_queue_setup,
        .rx_queue_release = mlx5_rx_queue_release,
index 6ab31ad..3f47a15 100644 (file)
@@ -160,6 +160,8 @@ int priv_get_ifname(const struct priv *, char (*)[IF_NAMESIZE]);
 int priv_ifreq(const struct priv *, int req, struct ifreq *);
 int priv_get_mtu(struct priv *, uint16_t *);
 int priv_set_flags(struct priv *, unsigned int, unsigned int);
+int mlx5_dev_configure(struct rte_eth_dev *);
+void mlx5_dev_infos_get(struct rte_eth_dev *, struct rte_eth_dev_info *);
 int mlx5_ibv_device_to_pci_addr(const struct ibv_device *,
                                struct rte_pci_addr *);
 
@@ -174,4 +176,9 @@ int priv_mac_addr_add(struct priv *, unsigned int,
 void mlx5_mac_addr_add(struct rte_eth_dev *, struct ether_addr *, uint32_t,
                       uint32_t);
 
+/* mlx5_trigger.c */
+
+int mlx5_dev_start(struct rte_eth_dev *);
+void mlx5_dev_stop(struct rte_eth_dev *);
+
 #endif /* RTE_PMD_MLX5_H_ */
index b6c7d7a..6b13cec 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <stddef.h>
+#include <assert.h>
 #include <unistd.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -58,6 +59,7 @@
 #endif
 
 #include "mlx5.h"
+#include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
 
 /**
@@ -369,6 +371,152 @@ priv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags)
        return priv_set_sysfs_ulong(priv, "flags", tmp);
 }
 
+/**
+ * Ethernet device configuration.
+ *
+ * Prepare the driver for a given number of TX and RX queues.
+ * Allocate parent RSS queue when several RX queues are requested.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, errno value on failure.
+ */
+static int
+dev_configure(struct rte_eth_dev *dev)
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int rxqs_n = dev->data->nb_rx_queues;
+       unsigned int txqs_n = dev->data->nb_tx_queues;
+       unsigned int tmp;
+       int ret;
+
+       priv->rxqs = (void *)dev->data->rx_queues;
+       priv->txqs = (void *)dev->data->tx_queues;
+       if (txqs_n != priv->txqs_n) {
+               INFO("%p: TX queues number update: %u -> %u",
+                    (void *)dev, priv->txqs_n, txqs_n);
+               priv->txqs_n = txqs_n;
+       }
+       if (rxqs_n == priv->rxqs_n)
+               return 0;
+       INFO("%p: RX queues number update: %u -> %u",
+            (void *)dev, priv->rxqs_n, rxqs_n);
+       /* If RSS is enabled, disable it first. */
+       if (priv->rss) {
+               unsigned int i;
+
+               /* Only if there are no remaining child RX queues. */
+               for (i = 0; (i != priv->rxqs_n); ++i)
+                       if ((*priv->rxqs)[i] != NULL)
+                               return EINVAL;
+               rxq_cleanup(&priv->rxq_parent);
+               priv->rss = 0;
+               priv->rxqs_n = 0;
+       }
+       if (rxqs_n <= 1) {
+               /* Nothing else to do. */
+               priv->rxqs_n = rxqs_n;
+               return 0;
+       }
+       /* Allocate a new RSS parent queue if supported by hardware. */
+       if (!priv->hw_rss) {
+               ERROR("%p: only a single RX queue can be configured when"
+                     " hardware doesn't support RSS",
+                     (void *)dev);
+               return EINVAL;
+       }
+       /* Fail if hardware doesn't support that many RSS queues. */
+       if (rxqs_n >= priv->max_rss_tbl_sz) {
+               ERROR("%p: only %u RX queues can be configured for RSS",
+                     (void *)dev, priv->max_rss_tbl_sz);
+               return EINVAL;
+       }
+       priv->rss = 1;
+       tmp = priv->rxqs_n;
+       priv->rxqs_n = rxqs_n;
+       ret = rxq_setup(dev, &priv->rxq_parent, 0, 0, NULL, NULL);
+       if (!ret)
+               return 0;
+       /* Failure, rollback. */
+       priv->rss = 0;
+       priv->rxqs_n = tmp;
+       assert(ret > 0);
+       return ret;
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative errno value on failure.
+ */
+int
+mlx5_dev_configure(struct rte_eth_dev *dev)
+{
+       struct priv *priv = dev->data->dev_private;
+       int ret;
+
+       priv_lock(priv);
+       ret = dev_configure(dev);
+       assert(ret >= 0);
+       priv_unlock(priv);
+       return -ret;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+void
+mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int max;
+       char ifname[IF_NAMESIZE];
+
+       priv_lock(priv);
+       /* FIXME: we should ask the device for these values. */
+       info->min_rx_bufsize = 32;
+       info->max_rx_pktlen = 65536;
+       /*
+        * Since we need one CQ per QP, the limit is the minimum number
+        * between the two values.
+        */
+       max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ?
+              priv->device_attr.max_qp : priv->device_attr.max_cq);
+       /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */
+       if (max >= 65535)
+               max = 65535;
+       info->max_rx_queues = max;
+       info->max_tx_queues = max;
+       /* Last array entry is reserved for broadcast. */
+       info->max_mac_addrs = (RTE_DIM(priv->mac) - 1);
+       info->rx_offload_capa =
+               (priv->hw_csum ?
+                (DEV_RX_OFFLOAD_IPV4_CKSUM |
+                 DEV_RX_OFFLOAD_UDP_CKSUM |
+                 DEV_RX_OFFLOAD_TCP_CKSUM) :
+                0);
+       info->tx_offload_capa =
+               (priv->hw_csum ?
+                (DEV_TX_OFFLOAD_IPV4_CKSUM |
+                 DEV_TX_OFFLOAD_UDP_CKSUM |
+                 DEV_TX_OFFLOAD_TCP_CKSUM) :
+                0);
+       if (priv_get_ifname(priv, &ifname) == 0)
+               info->if_index = if_nametoindex(ifname);
+       priv_unlock(priv);
+}
+
 /**
  * Get PCI information from struct ibv_device.
  *
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
new file mode 100644 (file)
index 0000000..f5d965f
--- /dev/null
@@ -0,0 +1,146 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 6WIND S.A.
+ *   Copyright 2015 Mellanox.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* DPDK headers don't like -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-pedantic"
+#endif
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-pedantic"
+#endif
+
+#include "mlx5.h"
+#include "mlx5_rxtx.h"
+#include "mlx5_utils.h"
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Simulate device start by attaching all configured flows.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative errno value on failure.
+ */
+int
+mlx5_dev_start(struct rte_eth_dev *dev)
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int i = 0;
+       unsigned int r;
+       struct rxq *rxq;
+
+       priv_lock(priv);
+       if (priv->started) {
+               priv_unlock(priv);
+               return 0;
+       }
+       DEBUG("%p: attaching configured flows to all RX queues", (void *)dev);
+       priv->started = 1;
+       if (priv->rss) {
+               rxq = &priv->rxq_parent;
+               r = 1;
+       } else {
+               rxq = (*priv->rxqs)[0];
+               r = priv->rxqs_n;
+       }
+       /* Iterate only once when RSS is enabled. */
+       do {
+               int ret;
+
+               /* Ignore nonexistent RX queues. */
+               if (rxq == NULL)
+                       continue;
+               ret = rxq_mac_addrs_add(rxq);
+               if (!ret)
+                       continue;
+               WARN("%p: QP flow attachment failed: %s",
+                    (void *)dev, strerror(ret));
+               /* Rollback. */
+               while (i != 0) {
+                       rxq = (*priv->rxqs)[--i];
+                       if (rxq != NULL) {
+                               rxq_mac_addrs_del(rxq);
+                       }
+               }
+               priv->started = 0;
+               priv_unlock(priv);
+               return -ret;
+       } while ((--r) && ((rxq = (*priv->rxqs)[++i]), i));
+       priv_unlock(priv);
+       return 0;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Simulate device stop by detaching all configured flows.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+mlx5_dev_stop(struct rte_eth_dev *dev)
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int i = 0;
+       unsigned int r;
+       struct rxq *rxq;
+
+       priv_lock(priv);
+       if (!priv->started) {
+               priv_unlock(priv);
+               return;
+       }
+       DEBUG("%p: detaching flows from all RX queues", (void *)dev);
+       priv->started = 0;
+       if (priv->rss) {
+               rxq = &priv->rxq_parent;
+               r = 1;
+       } else {
+               rxq = (*priv->rxqs)[0];
+               r = priv->rxqs_n;
+       }
+       /* Iterate only once when RSS is enabled. */
+       do {
+               /* Ignore nonexistent RX queues. */
+               if (rxq == NULL)
+                       continue;
+               rxq_mac_addrs_del(rxq);
+       } while ((--r) && ((rxq = (*priv->rxqs)[++i]), i));
+       priv_unlock(priv);
+}