With VFIO MSI-X, each doorbell raises its own vector. Vector 0 is
signalled on the PCI device interrupt handle while the others are
signalled on the eventfds created by rte_intr_efd_enable(), but the
interrupt handler was only registered on the device interrupt handle.
As a result, doorbells other than DB0 were only noticed when DB0 fired
at the same time. In particular, the DB1 rung by the peer in its
dev_stop was never handled, the peer never got the DB2 answer and had
to wait for the 1s timeout.
Register the interrupt handler on each doorbell eventfd as well.
Fixes: 62012a76811e ("raw/ntb: add handshake process")
Cc: [email protected]
Signed-off-by: Raghavendra Ningoji <[email protected]>
---
drivers/raw/ntb/ntb.c | 77 ++++++++++++++++++++++++++++++++++++++++++-
drivers/raw/ntb/ntb.h | 4 +++
2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c
index af3fcd832b..a1993121dd 100644
--- a/drivers/raw/ntb/ntb.c
+++ b/drivers/raw/ntb/ntb.c
@@ -11,6 +11,7 @@
#include <rte_lcore.h>
#include <rte_cycles.h>
#include <rte_eal.h>
+#include <rte_errno.h>
#include <rte_log.h>
#include <rte_pci.h>
#include <rte_mbuf.h>
@@ -124,6 +125,74 @@ ntb_dev_intr_handler(void *param)
(*hw->ntb_ops->handle_hw_event)(dev);
}
+static void
+ntb_db_intr_unregister(struct rte_rawdev *dev)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ struct rte_intr_handle *handle;
+ uint16_t i;
+
+ for (i = 0; i < hw->nb_db_intr_handles; i++) {
+ handle = hw->db_intr_handles[i];
+ rte_intr_callback_unregister_sync(handle,
+ ntb_dev_intr_handler, dev);
+ /* The eventfd is owned by the PCI device interrupt handle. */
+ rte_intr_fd_set(handle, -1);
+ rte_intr_instance_free(handle);
+ }
+ rte_free(hw->db_intr_handles);
+ hw->db_intr_handles = NULL;
+ hw->nb_db_intr_handles = 0;
+}
+
+/*
+ * With MSI-X, only vector 0 is serviced through the PCI device interrupt
+ * handle. Each other doorbell raises its own vector, signalled on the
+ * eventfds created by rte_intr_efd_enable(): register the handler on them.
+ */
+static int
+ntb_db_intr_register(struct rte_rawdev *dev,
+ struct rte_intr_handle *intr_handle)
+{
+ struct ntb_hw *hw = dev->dev_private;
+ int nb_efd = rte_intr_nb_efd_get(intr_handle);
+ struct rte_intr_handle *handle;
+ int i, ret;
+
+ hw->db_intr_handles = rte_zmalloc("ntb_db_intr",
+ nb_efd * sizeof(*hw->db_intr_handles), 0);
+ if (hw->db_intr_handles == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < nb_efd; i++) {
+ handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ hw->db_intr_handles[hw->nb_db_intr_handles++] = handle;
+
+ if (rte_intr_type_set(handle, RTE_INTR_HANDLE_VFIO_MSIX) ||
+ rte_intr_fd_set(handle,
+ rte_intr_efds_index_get(intr_handle, i))) {
+ ret = -rte_errno;
+ goto err;
+ }
+
+ ret = rte_intr_callback_register(handle,
+ ntb_dev_intr_handler, dev);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ NTB_LOG(ERR, "Failed to register doorbell interrupt %d.", i + 1);
+ ntb_db_intr_unregister(dev);
+ return ret;
+}
+
static int
ntb_queue_conf_get(struct rte_rawdev *dev,
uint16_t queue_id,
@@ -905,6 +974,8 @@ ntb_dev_close(struct rte_rawdev *dev)
!rte_intr_max_intr_get(intr_handle))
return 0;
+ ntb_db_intr_unregister(dev);
+
/* Clean datapath event and vec mapping */
rte_intr_efd_disable(intr_handle);
rte_intr_vec_list_free(intr_handle);
@@ -1308,7 +1379,11 @@ ntb_init_hw(struct rte_rawdev *dev, struct
rte_pci_device *pci_dev)
* by default for intel gen3. They are mapped to msix vec 1-32,
* and hardware intr is mapped to 0. Map all to 0 for uio.
*/
- if (!rte_intr_cap_multiple(intr_handle)) {
+ if (rte_intr_cap_multiple(intr_handle)) {
+ ret = ntb_db_intr_register(dev, intr_handle);
+ if (ret)
+ return ret;
+ } else {
for (i = 0; i < hw->db_cnt; i++) {
ret = (*hw->ntb_ops->vector_bind)(dev, i, 0);
if (ret)
diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h
index 0181bec5c9..2787883160 100644
--- a/drivers/raw/ntb/ntb.h
+++ b/drivers/raw/ntb/ntb.h
@@ -219,6 +219,10 @@ struct ntb_hw {
struct rte_pci_device *pci_dev;
char *hw_addr;
+ /* Interrupt handles for the MSI-X doorbell vectors besides vector 0. */
+ struct rte_intr_handle **db_intr_handles;
+ uint16_t nb_db_intr_handles;
+
uint8_t peer_dev_up;
uint64_t *mw_size;
/* remote mem base addr */
--
2.34.1