]> git.droids-corp.org - dpdk.git/commitdiff
net/mlx5: fix interrupt installation timing
authorSuanming Mou <suanmingm@mellanox.com>
Thu, 28 May 2020 09:22:09 +0000 (17:22 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 2 Jun 2020 14:06:24 +0000 (16:06 +0200)
Currently, the DevX counter query works asynchronously with Devx
interrupt handler return the query result. When port closes, the
interrupt handler will be uninstalled and the Devx comp obj will
also be destroyed. Meanwhile the query is still not cancelled.

In this case, counter query may use the invalid Devx comp which
has been destroyed, and query failure with invalid FD will be
reported.

Adjust the shared interrupt install and uninstall timing to make
the counter asynchronous query stop before interrupt uninstall.

Fixes: f15db67df09c ("net/mlx5: accelerate DV flow counter query")
Cc: stable@dpdk.org
Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
Acked-by: Matan Azrad <matan@mellanox.com>
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_ethdev.c
drivers/net/mlx5/mlx5_trigger.c

index 81102631aa219fd58eee256ee5f591c21898ea93..469ff7368cbfa8ea31b5ce8a4ec41aee2d0cb077 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <net/if.h>
+#include <fcntl.h>
 #include <sys/mman.h>
 #include <linux/rtnetlink.h>
 
@@ -655,6 +656,85 @@ mlx5_restore_doorbell_mapping_env(int value)
                setenv(MLX5_SHUT_UP_BF, value ? "1" : "0", 1);
 }
 
+/**
+ * Install shared asynchronous device events handler.
+ * This function is implemented to support event sharing
+ * between multiple ports of single IB device.
+ *
+ * @param sh
+ *   Pointer to mlx5_ibv_shared object.
+ */
+static void
+mlx5_dev_shared_handler_install(struct mlx5_ibv_shared *sh)
+{
+       int ret;
+       int flags;
+
+       sh->intr_handle.fd = -1;
+       flags = fcntl(sh->ctx->async_fd, F_GETFL);
+       ret = fcntl(sh->ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
+       if (ret) {
+               DRV_LOG(INFO, "failed to change file descriptor async event"
+                       " queue");
+       } else {
+               sh->intr_handle.fd = sh->ctx->async_fd;
+               sh->intr_handle.type = RTE_INTR_HANDLE_EXT;
+               if (rte_intr_callback_register(&sh->intr_handle,
+                                       mlx5_dev_interrupt_handler, sh)) {
+                       DRV_LOG(INFO, "Fail to install the shared interrupt.");
+                       sh->intr_handle.fd = -1;
+               }
+       }
+       if (sh->devx) {
+#ifdef HAVE_IBV_DEVX_ASYNC
+               sh->intr_handle_devx.fd = -1;
+               sh->devx_comp = mlx5_glue->devx_create_cmd_comp(sh->ctx);
+               if (!sh->devx_comp) {
+                       DRV_LOG(INFO, "failed to allocate devx_comp.");
+                       return;
+               }
+               flags = fcntl(sh->devx_comp->fd, F_GETFL);
+               ret = fcntl(sh->devx_comp->fd, F_SETFL, flags | O_NONBLOCK);
+               if (ret) {
+                       DRV_LOG(INFO, "failed to change file descriptor"
+                               " devx comp");
+                       return;
+               }
+               sh->intr_handle_devx.fd = sh->devx_comp->fd;
+               sh->intr_handle_devx.type = RTE_INTR_HANDLE_EXT;
+               if (rte_intr_callback_register(&sh->intr_handle_devx,
+                                       mlx5_dev_interrupt_handler_devx, sh)) {
+                       DRV_LOG(INFO, "Fail to install the devx shared"
+                               " interrupt.");
+                       sh->intr_handle_devx.fd = -1;
+               }
+#endif /* HAVE_IBV_DEVX_ASYNC */
+       }
+}
+
+/**
+ * Uninstall shared asynchronous device events handler.
+ * This function is implemented to support event sharing
+ * between multiple ports of single IB device.
+ *
+ * @param dev
+ *   Pointer to mlx5_ibv_shared object.
+ */
+static void
+mlx5_dev_shared_handler_uninstall(struct mlx5_ibv_shared *sh)
+{
+       if (sh->intr_handle.fd >= 0)
+               mlx5_intr_callback_unregister(&sh->intr_handle,
+                                             mlx5_dev_interrupt_handler, sh);
+#ifdef HAVE_IBV_DEVX_ASYNC
+       if (sh->intr_handle_devx.fd >= 0)
+               rte_intr_callback_unregister(&sh->intr_handle_devx,
+                                 mlx5_dev_interrupt_handler_devx, sh);
+       if (sh->devx_comp)
+               mlx5_glue->devx_destroy_cmd_comp(sh->devx_comp);
+#endif
+}
+
 /**
  * Allocate shared IB device context. If there is multiport device the
  * master and representors will share this context, if there is single
@@ -749,7 +829,6 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn,
                sizeof(sh->ibdev_name));
        strncpy(sh->ibdev_path, sh->ctx->device->ibdev_path,
                sizeof(sh->ibdev_path));
-       pthread_mutex_init(&sh->intr_mutex, NULL);
        /*
         * Setting port_id to max unallowed value means
         * there is no interrupt subhandler installed for
@@ -810,6 +889,7 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn,
                err = rte_errno;
                goto error;
        }
+       mlx5_dev_shared_handler_install(sh);
        mlx5_flow_aging_init(sh);
        mlx5_flow_counters_mng_init(sh);
        mlx5_flow_ipool_create(sh, config);
@@ -886,20 +966,7 @@ mlx5_free_shared_ibctx(struct mlx5_ibv_shared *sh)
         **/
        mlx5_flow_counters_mng_close(sh);
        mlx5_flow_ipool_destroy(sh);
-       MLX5_ASSERT(!sh->intr_cnt);
-       if (sh->intr_cnt)
-               mlx5_intr_callback_unregister
-                       (&sh->intr_handle, mlx5_dev_interrupt_handler, sh);
-#ifdef HAVE_MLX5_DEVX_ASYNC_SUPPORT
-       if (sh->devx_intr_cnt) {
-               if (sh->intr_handle_devx.fd)
-                       rte_intr_callback_unregister(&sh->intr_handle_devx,
-                                         mlx5_dev_interrupt_handler_devx, sh);
-               if (sh->devx_comp)
-                       mlx5dv_devx_destroy_cmd_comp(sh->devx_comp);
-       }
-#endif
-       pthread_mutex_destroy(&sh->intr_mutex);
+       mlx5_dev_shared_handler_uninstall(sh);
        if (sh->pd)
                claim_zero(mlx5_glue->dealloc_pd(sh->pd));
        if (sh->tis)
@@ -1437,9 +1504,6 @@ mlx5_dev_close(struct rte_eth_dev *dev)
        DRV_LOG(DEBUG, "port %u closing device \"%s\"",
                dev->data->port_id,
                ((priv->sh->ctx != NULL) ? priv->sh->ctx->device->name : ""));
-       /* In case mlx5_dev_stop() has not been called. */
-       mlx5_dev_interrupt_handler_uninstall(dev);
-       mlx5_dev_interrupt_handler_devx_uninstall(dev);
        /*
         * If default mreg copy action is removed at the stop stage,
         * the search will return none and nothing will be done anymore.
@@ -3624,7 +3688,6 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
                rte_eth_copy_pci_info(list[i].eth_dev, pci_dev);
                /* Restore non-PCI flags cleared by the above call. */
                list[i].eth_dev->data->dev_flags |= restore;
-               mlx5_dev_interrupt_handler_devx_install(list[i].eth_dev);
                rte_eth_dev_probing_finish(list[i].eth_dev);
        }
        if (i != ns) {
index d9f5d816f9a68e5c7de3513e970407f5bc81d9c8..2908c8b8deb81ff723b8c49913c6e880e2c851b2 100644 (file)
@@ -512,10 +512,7 @@ struct mlx5_ibv_shared {
        struct mlx5_indexed_pool *ipool[MLX5_IPOOL_MAX];
        /* Memory Pool for mlx5 flow resources. */
        /* Shared interrupt handler section. */
-       pthread_mutex_t intr_mutex; /* Interrupt config mutex. */
-       uint32_t intr_cnt; /* Interrupt handler reference counter. */
        struct rte_intr_handle intr_handle; /* Interrupt handler for device. */
-       uint32_t devx_intr_cnt; /* Devx interrupt handler reference counter. */
        struct rte_intr_handle intr_handle_devx; /* DEVX interrupt handler. */
        struct mlx5dv_devx_cmd_comp *devx_comp; /* DEVX async comp obj. */
        struct mlx5_devx_obj *tis; /* TIS object. */
@@ -671,8 +668,6 @@ void mlx5_dev_interrupt_handler(void *arg);
 void mlx5_dev_interrupt_handler_devx(void *arg);
 void mlx5_dev_interrupt_handler_uninstall(struct rte_eth_dev *dev);
 void mlx5_dev_interrupt_handler_install(struct rte_eth_dev *dev);
-void mlx5_dev_interrupt_handler_devx_uninstall(struct rte_eth_dev *dev);
-void mlx5_dev_interrupt_handler_devx_install(struct rte_eth_dev *dev);
 int mlx5_set_link_down(struct rte_eth_dev *dev);
 int mlx5_set_link_up(struct rte_eth_dev *dev);
 int mlx5_is_removed(struct rte_eth_dev *dev);
index 47f11b963040aaf0cc2b8910048f45c752039882..b837ce63685b45768334d8ce7f5552e8e1bfa933 100644 (file)
@@ -1444,249 +1444,6 @@ mlx5_dev_interrupt_handler_devx(void *cb_arg)
 #endif /* HAVE_IBV_DEVX_ASYNC */
 }
 
-/**
- * Uninstall shared asynchronous device events handler.
- * This function is implemented to support event sharing
- * between multiple ports of single IB device.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-static void
-mlx5_dev_shared_handler_uninstall(struct rte_eth_dev *dev)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_ibv_shared *sh = priv->sh;
-
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
-               return;
-       pthread_mutex_lock(&sh->intr_mutex);
-       MLX5_ASSERT(priv->ibv_port);
-       MLX5_ASSERT(priv->ibv_port <= sh->max_port);
-       MLX5_ASSERT(dev->data->port_id < RTE_MAX_ETHPORTS);
-       if (sh->port[priv->ibv_port - 1].ih_port_id >= RTE_MAX_ETHPORTS)
-               goto exit;
-       MLX5_ASSERT(sh->port[priv->ibv_port - 1].ih_port_id ==
-                                       (uint32_t)dev->data->port_id);
-       MLX5_ASSERT(sh->intr_cnt);
-       sh->port[priv->ibv_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
-       if (!sh->intr_cnt || --sh->intr_cnt)
-               goto exit;
-       mlx5_intr_callback_unregister(&sh->intr_handle,
-                                    mlx5_dev_interrupt_handler, sh);
-       sh->intr_handle.fd = 0;
-       sh->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
-exit:
-       pthread_mutex_unlock(&sh->intr_mutex);
-}
-
-/**
- * Uninstall devx shared asynchronous device events handler.
- * This function is implemeted to support event sharing
- * between multiple ports of single IB device.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-static void
-mlx5_dev_shared_handler_devx_uninstall(struct rte_eth_dev *dev)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_ibv_shared *sh = priv->sh;
-
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
-               return;
-       pthread_mutex_lock(&sh->intr_mutex);
-       MLX5_ASSERT(priv->ibv_port);
-       MLX5_ASSERT(priv->ibv_port <= sh->max_port);
-       MLX5_ASSERT(dev->data->port_id < RTE_MAX_ETHPORTS);
-       if (sh->port[priv->ibv_port - 1].devx_ih_port_id >= RTE_MAX_ETHPORTS)
-               goto exit;
-       MLX5_ASSERT(sh->port[priv->ibv_port - 1].devx_ih_port_id ==
-                   (uint32_t)dev->data->port_id);
-       sh->port[priv->ibv_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
-       if (!sh->devx_intr_cnt || --sh->devx_intr_cnt)
-               goto exit;
-       if (sh->intr_handle_devx.fd) {
-               rte_intr_callback_unregister(&sh->intr_handle_devx,
-                                            mlx5_dev_interrupt_handler_devx,
-                                            sh);
-               sh->intr_handle_devx.fd = 0;
-               sh->intr_handle_devx.type = RTE_INTR_HANDLE_UNKNOWN;
-       }
-       if (sh->devx_comp) {
-               mlx5_glue->devx_destroy_cmd_comp(sh->devx_comp);
-               sh->devx_comp = NULL;
-       }
-exit:
-       pthread_mutex_unlock(&sh->intr_mutex);
-}
-
-/**
- * Install shared asynchronous device events handler.
- * This function is implemented to support event sharing
- * between multiple ports of single IB device.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-static void
-mlx5_dev_shared_handler_install(struct rte_eth_dev *dev)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_ibv_shared *sh = priv->sh;
-       int ret;
-       int flags;
-
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
-               return;
-       pthread_mutex_lock(&sh->intr_mutex);
-       MLX5_ASSERT(priv->ibv_port);
-       MLX5_ASSERT(priv->ibv_port <= sh->max_port);
-       MLX5_ASSERT(dev->data->port_id < RTE_MAX_ETHPORTS);
-       if (sh->port[priv->ibv_port - 1].ih_port_id < RTE_MAX_ETHPORTS) {
-               /* The handler is already installed for this port. */
-               MLX5_ASSERT(sh->intr_cnt);
-               goto exit;
-       }
-       if (sh->intr_cnt) {
-               sh->port[priv->ibv_port - 1].ih_port_id =
-                                               (uint32_t)dev->data->port_id;
-               sh->intr_cnt++;
-               goto exit;
-       }
-       /* No shared handler installed. */
-       MLX5_ASSERT(sh->ctx->async_fd > 0);
-       flags = fcntl(sh->ctx->async_fd, F_GETFL);
-       ret = fcntl(sh->ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
-       if (ret) {
-               DRV_LOG(INFO, "failed to change file descriptor async event"
-                       " queue");
-               /* Indicate there will be no interrupts. */
-               dev->data->dev_conf.intr_conf.lsc = 0;
-               dev->data->dev_conf.intr_conf.rmv = 0;
-       } else {
-               sh->intr_handle.fd = sh->ctx->async_fd;
-               sh->intr_handle.type = RTE_INTR_HANDLE_EXT;
-               rte_intr_callback_register(&sh->intr_handle,
-                                          mlx5_dev_interrupt_handler, sh);
-               sh->intr_cnt++;
-               sh->port[priv->ibv_port - 1].ih_port_id =
-                                               (uint32_t)dev->data->port_id;
-       }
-exit:
-       pthread_mutex_unlock(&sh->intr_mutex);
-}
-
-/**
- * Install devx shared asyncronous device events handler.
- * This function is implemeted to support event sharing
- * between multiple ports of single IB device.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-static void
-mlx5_dev_shared_handler_devx_install(struct rte_eth_dev *dev)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_ibv_shared *sh = priv->sh;
-
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
-               return;
-       pthread_mutex_lock(&sh->intr_mutex);
-       MLX5_ASSERT(priv->ibv_port);
-       MLX5_ASSERT(priv->ibv_port <= sh->max_port);
-       MLX5_ASSERT(dev->data->port_id < RTE_MAX_ETHPORTS);
-       if (sh->port[priv->ibv_port - 1].devx_ih_port_id < RTE_MAX_ETHPORTS) {
-               /* The handler is already installed for this port. */
-               MLX5_ASSERT(sh->devx_intr_cnt);
-               goto exit;
-       }
-       if (sh->devx_intr_cnt) {
-               sh->devx_intr_cnt++;
-               sh->port[priv->ibv_port - 1].devx_ih_port_id =
-                                       (uint32_t)dev->data->port_id;
-               goto exit;
-       }
-       if (priv->config.devx) {
-#ifndef HAVE_IBV_DEVX_ASYNC
-               goto exit;
-#else
-               sh->devx_comp = mlx5_glue->devx_create_cmd_comp(sh->ctx);
-               if (sh->devx_comp) {
-                       int flags = fcntl(sh->devx_comp->fd, F_GETFL);
-                       int ret = fcntl(sh->devx_comp->fd, F_SETFL,
-                                   flags | O_NONBLOCK);
-
-                       if (ret) {
-                               DRV_LOG(INFO, "failed to change file descriptor"
-                                       " devx async event queue");
-                       } else {
-                               sh->intr_handle_devx.fd = sh->devx_comp->fd;
-                               sh->intr_handle_devx.type = RTE_INTR_HANDLE_EXT;
-                               rte_intr_callback_register
-                                       (&sh->intr_handle_devx,
-                                        mlx5_dev_interrupt_handler_devx, sh);
-                               sh->devx_intr_cnt++;
-                               sh->port[priv->ibv_port - 1].devx_ih_port_id =
-                                               (uint32_t)dev->data->port_id;
-                       }
-               }
-#endif /* HAVE_IBV_DEVX_ASYNC */
-       }
-exit:
-       pthread_mutex_unlock(&sh->intr_mutex);
-}
-
-/**
- * Uninstall interrupt handler.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-void
-mlx5_dev_interrupt_handler_uninstall(struct rte_eth_dev *dev)
-{
-       mlx5_dev_shared_handler_uninstall(dev);
-}
-
-/**
- * Install interrupt handler.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-void
-mlx5_dev_interrupt_handler_install(struct rte_eth_dev *dev)
-{
-       mlx5_dev_shared_handler_install(dev);
-}
-
-/**
- * Devx uninstall interrupt handler.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-void
-mlx5_dev_interrupt_handler_devx_uninstall(struct rte_eth_dev *dev)
-{
-       mlx5_dev_shared_handler_devx_uninstall(dev);
-}
-
-/**
- * Devx install interrupt handler.
- *
- * @param dev
- *   Pointer to Ethernet device.
- */
-void
-mlx5_dev_interrupt_handler_devx_install(struct rte_eth_dev *dev)
-{
-       mlx5_dev_shared_handler_devx_install(dev);
-}
-
 /**
  * DPDK callback to bring the link DOWN.
  *
index 8106598ff67f7a5999a7711545f1a952211684ba..f1231937630d378948df482cce079691c484a7a5 100644 (file)
@@ -269,6 +269,7 @@ error:
 int
 mlx5_dev_start(struct rte_eth_dev *dev)
 {
+       struct mlx5_priv *priv = dev->data->dev_private;
        int ret;
        int fine_inline;
 
@@ -340,7 +341,18 @@ mlx5_dev_start(struct rte_eth_dev *dev)
        dev->rx_pkt_burst = mlx5_select_rx_function(dev);
        /* Enable datapath on secondary process. */
        mlx5_mp_req_start_rxtx(dev);
-       mlx5_dev_interrupt_handler_install(dev);
+       if (priv->sh->intr_handle.fd >= 0) {
+               priv->sh->port[priv->ibv_port - 1].ih_port_id =
+                                       (uint32_t)dev->data->port_id;
+       } else {
+               DRV_LOG(INFO, "port %u starts without LSC and RMV interrupts.",
+                       dev->data->port_id);
+               dev->data->dev_conf.intr_conf.lsc = 0;
+               dev->data->dev_conf.intr_conf.rmv = 0;
+       }
+       if (priv->sh->intr_handle_devx.fd >= 0)
+               priv->sh->port[priv->ibv_port - 1].devx_ih_port_id =
+                                       (uint32_t)dev->data->port_id;
        return 0;
 error:
        ret = rte_errno; /* Save rte_errno before cleanup. */
@@ -382,7 +394,8 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
        /* All RX queue flags will be cleared in the flush interface. */
        mlx5_flow_list_flush(dev, &priv->flows, true);
        mlx5_rx_intr_vec_disable(dev);
-       mlx5_dev_interrupt_handler_uninstall(dev);
+       priv->sh->port[priv->ibv_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
+       priv->sh->port[priv->ibv_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
        mlx5_txq_stop(dev);
        mlx5_rxq_stop(dev);
 }