From: Long Li <lon...@microsoft.com>

MANA supports PCI hot plug events. Add this interrupt to DPDK core so its
parent PMD can detect device removal during Azure servicing or live
migration.
Signed-off-by: Long Li <lon...@microsoft.com>
---
 doc/guides/nics/features/mana.ini |  1 +
 drivers/net/mana/mana.c           | 97 +++++++++++++++++++++++++++++++
 drivers/net/mana/mana.h           |  1 +
 3 files changed, 99 insertions(+)

diff --git a/doc/guides/nics/features/mana.ini 
b/doc/guides/nics/features/mana.ini
index 62554b0a0a..8043e11f99 100644
--- a/doc/guides/nics/features/mana.ini
+++ b/doc/guides/nics/features/mana.ini
@@ -7,5 +7,6 @@
 Link status          = P
 Linux                = Y
 Multiprocess aware   = Y
+Removal event        = Y
 Usage doc            = Y
 x86-64               = Y
diff --git a/drivers/net/mana/mana.c b/drivers/net/mana/mana.c
index 8c6491f045..e15ecb8ea6 100644
--- a/drivers/net/mana/mana.c
+++ b/drivers/net/mana/mana.c
@@ -95,12 +95,18 @@ static int mana_dev_configure(struct rte_eth_dev *dev)
        return 0;
 }
 
+static int mana_intr_uninstall(struct mana_priv *priv);
+
 static int
 mana_dev_close(struct rte_eth_dev *dev)
 {
        struct mana_priv *priv = dev->data->dev_private;
        int ret;
 
+       ret = mana_intr_uninstall(priv);
+       if (ret)
+               return ret;
+
        ret = ibv_close_device(priv->ib_ctx);
        if (ret) {
                ret = errno;
@@ -327,6 +333,90 @@ static int mana_ibv_device_to_pci_addr(const struct 
ibv_device *device,
        return 0;
 }
 
+static void mana_intr_handler(void *arg)
+{
+       struct mana_priv *priv = arg;
+       struct ibv_context *ctx = priv->ib_ctx;
+       struct ibv_async_event event;
+
+       /* Read and ack all messages from IB device */
+       while (true) {
+               if (ibv_get_async_event(ctx, &event))
+                       break;
+
+               if (event.event_type == IBV_EVENT_DEVICE_FATAL) {
+                       struct rte_eth_dev *dev;
+
+                       dev = &rte_eth_devices[priv->port_id];
+                       if (dev->data->dev_conf.intr_conf.rmv)
+                               rte_eth_dev_callback_process(dev,
+                                       RTE_ETH_EVENT_INTR_RMV, NULL);
+               }
+
+               ibv_ack_async_event(&event);
+       }
+}
+
+static int mana_intr_uninstall(struct mana_priv *priv)
+{
+       int ret;
+
+       ret = rte_intr_callback_unregister(priv->intr_handle,
+                                          mana_intr_handler, priv);
+       if (ret <= 0) {
+               DRV_LOG(ERR, "Failed to unregister intr callback ret %d", ret);
+               return ret;
+       }
+
+       rte_intr_instance_free(priv->intr_handle);
+
+       return 0;
+}
+
+static int mana_intr_install(struct mana_priv *priv)
+{
+       int ret, flags;
+       struct ibv_context *ctx = priv->ib_ctx;
+
+       priv->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
+       if (!priv->intr_handle) {
+               DRV_LOG(ERR, "Failed to allocate intr_handle");
+               rte_errno = ENOMEM;
+               return -ENOMEM;
+       }
+
+       rte_intr_fd_set(priv->intr_handle, -1);
+
+       flags = fcntl(ctx->async_fd, F_GETFL);
+       ret = fcntl(ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
+       if (ret) {
+               DRV_LOG(ERR, "Failed to change async_fd to NONBLOCK");
+               goto free_intr;
+       }
+
+       rte_intr_fd_set(priv->intr_handle, ctx->async_fd);
+       rte_intr_type_set(priv->intr_handle, RTE_INTR_HANDLE_EXT);
+
+       ret = rte_intr_callback_register(priv->intr_handle,
+                                        mana_intr_handler, priv);
+       if (ret) {
+               DRV_LOG(ERR, "Failed to register intr callback");
+               rte_intr_fd_set(priv->intr_handle, -1);
+               goto restore_fd;
+       }
+
+       return 0;
+
+restore_fd:
+       fcntl(ctx->async_fd, F_SETFL, flags);
+
+free_intr:
+       rte_intr_instance_free(priv->intr_handle);
+       priv->intr_handle = NULL;
+
+       return ret;
+}
+
 static int mana_proc_priv_init(struct rte_eth_dev *dev)
 {
        struct mana_process_priv *priv;
@@ -640,6 +730,13 @@ static int mana_pci_probe_mac(struct rte_pci_driver 
*pci_drv __rte_unused,
                                name, priv->max_rx_queues, priv->max_rx_desc,
                                priv->max_send_sge);
 
+                       /* Create async interrupt handler */
+                       ret = mana_intr_install(priv);
+                       if (ret) {
+                               DRV_LOG(ERR, "Failed to install intr handler");
+                               goto failed;
+                       }
+
                        rte_spinlock_lock(&mana_shared_data->lock);
                        mana_shared_data->primary_cnt++;
                        rte_spinlock_unlock(&mana_shared_data->lock);
diff --git a/drivers/net/mana/mana.h b/drivers/net/mana/mana.h
index c433940022..f97eed2e81 100644
--- a/drivers/net/mana/mana.h
+++ b/drivers/net/mana/mana.h
@@ -72,6 +72,7 @@ struct mana_priv {
        uint8_t ind_table_key[40];
        struct ibv_qp *rwq_qp;
        void *db_page;
+       struct rte_intr_handle *intr_handle;
        int max_rx_queues;
        int max_tx_queues;
        int max_rx_desc;
-- 
2.17.1

Reply via email to