[v2,10/13] vdpa/mlx5: map doorbell

Message ID 1580292549-27439-11-git-send-email-matan@mellanox.com (mailing list archive)
State Superseded, archived
Delegated to: Maxime Coquelin
Headers
Series Introduce mlx5 vDPA driver |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail apply issues

Commit Message

Matan Azrad Jan. 29, 2020, 10:09 a.m. UTC
The HW supports only 4 bytes doorbell writing detection.
The virtio device set only 2 bytes when it rings the doorbell.

Map the virtio doorbell detected by the virtio queue kickfd to the HW
VAR space when it expects to get the virtio emulation doorbell.

Use the EAL interrupt mechanism to get notification when a new event
appears in kickfd by the guest and write 4 bytes to the HW doorbell space
in the notification callback.

Signed-off-by: Matan Azrad <matan@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
---
 drivers/vdpa/mlx5/mlx5_vdpa.h       |  3 ++
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c | 82 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 84 insertions(+), 1 deletion(-)
  

Comments

Maxime Coquelin Jan. 31, 2020, 3:40 p.m. UTC | #1
On 1/29/20 11:09 AM, Matan Azrad wrote:
> The HW supports only 4 bytes doorbell writing detection.
> The virtio device set only 2 bytes when it rings the doorbell.
> 
> Map the virtio doorbell detected by the virtio queue kickfd to the HW
> VAR space when it expects to get the virtio emulation doorbell.
> 
> Use the EAL interrupt mechanism to get notification when a new event
> appears in kickfd by the guest and write 4 bytes to the HW doorbell space
> in the notification callback.
> 
> Signed-off-by: Matan Azrad <matan@mellanox.com>
> Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> ---
>  drivers/vdpa/mlx5/mlx5_vdpa.h       |  3 ++
>  drivers/vdpa/mlx5/mlx5_vdpa_virtq.c | 82 ++++++++++++++++++++++++++++++++++++-
>  2 files changed, 84 insertions(+), 1 deletion(-)

Acked-by: Maxime Coquelin <maxime.coquelin@redhat.com>

Thanks,
Maxime
  

Patch

diff --git a/drivers/vdpa/mlx5/mlx5_vdpa.h b/drivers/vdpa/mlx5/mlx5_vdpa.h
index 383a33e..af78ea1 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa.h
+++ b/drivers/vdpa/mlx5/mlx5_vdpa.h
@@ -75,6 +75,7 @@  struct mlx5_vdpa_virtq {
 		void *buf;
 		uint32_t size;
 	} umems[3];
+	struct rte_intr_handle intr_handle;
 };
 
 struct mlx5_vdpa_steer {
@@ -112,6 +113,8 @@  struct mlx5_vdpa_priv {
 	uint16_t log_max_rqt_size;
 	SLIST_HEAD(virtq_list, mlx5_vdpa_virtq) virtq_list;
 	struct mlx5_vdpa_steer steer;
+	struct mlx5dv_var *var;
+	void *virtq_db_addr;
 	SLIST_HEAD(mr_list, mlx5_vdpa_query_mr) mr_list;
 };
 
diff --git a/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c b/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c
index 60aa040..91347e9 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c
+++ b/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c
@@ -2,9 +2,12 @@ 
  * Copyright 2019 Mellanox Technologies, Ltd
  */
 #include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
 
 #include <rte_malloc.h>
 #include <rte_errno.h>
+#include <rte_io.h>
 
 #include <mlx5_common.h>
 
@@ -12,11 +15,52 @@ 
 #include "mlx5_vdpa.h"
 
 
+static void
+mlx5_vdpa_virtq_handler(void *cb_arg)
+{
+	struct mlx5_vdpa_virtq *virtq = cb_arg;
+	struct mlx5_vdpa_priv *priv = virtq->priv;
+	uint64_t buf;
+	int nbytes;
+
+	do {
+		nbytes = read(virtq->intr_handle.fd, &buf, 8);
+		if (nbytes < 0) {
+			if (errno == EINTR ||
+			    errno == EWOULDBLOCK ||
+			    errno == EAGAIN)
+				continue;
+			DRV_LOG(ERR,  "Failed to read kickfd of virtq %d: %s",
+				virtq->index, strerror(errno));
+		}
+		break;
+	} while (1);
+	rte_write32(virtq->index, priv->virtq_db_addr);
+	DRV_LOG(DEBUG, "Ring virtq %u doorbell.", virtq->index);
+}
+
 static int
 mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq)
 {
-	unsigned int;
+	unsigned int i;
+	int retries = MLX5_VDPA_INTR_RETRIES;
+	int ret = -EAGAIN;
 
+	if (virtq->intr_handle.fd) {
+		while (retries-- && ret == -EAGAIN) {
+			ret = rte_intr_callback_unregister(&virtq->intr_handle,
+							mlx5_vdpa_virtq_handler,
+							virtq);
+			if (ret == -EAGAIN) {
+				DRV_LOG(DEBUG, "Try again to unregister fd %d "
+					"of virtq %d interrupt, retries = %d.",
+					virtq->intr_handle.fd,
+					(int)virtq->index, retries);
+				usleep(MLX5_VDPA_INTR_RETRIES_USEC);
+			}
+		}
+		memset(&virtq->intr_handle, 0, sizeof(virtq->intr_handle));
+	}
 	if (virtq->virtq) {
 		claim_zero(mlx5_devx_cmd_destroy(virtq->virtq));
 		virtq->virtq = NULL;
@@ -57,6 +101,14 @@ 
 		claim_zero(mlx5_devx_cmd_destroy(priv->td));
 		priv->td = NULL;
 	}
+	if (priv->virtq_db_addr) {
+		claim_zero(munmap(priv->virtq_db_addr, priv->var->length));
+		priv->virtq_db_addr = NULL;
+	}
+	if (priv->var) {
+		mlx5_glue->dv_free_var(priv->var);
+		priv->var = NULL;
+	}
 	priv->features = 0;
 }
 
@@ -201,6 +253,17 @@ 
 	if (mlx5_vdpa_virtq_modify(virtq, 1))
 		goto error;
 	virtq->enable = 1;
+	virtq->intr_handle.fd = vq.kickfd;
+	virtq->intr_handle.type = RTE_INTR_HANDLE_EXT;
+	if (rte_intr_callback_register(&virtq->intr_handle,
+				       mlx5_vdpa_virtq_handler, virtq)) {
+		virtq->intr_handle.fd = 0;
+		DRV_LOG(ERR, "Failed to register virtq %d interrupt.", index);
+		goto error;
+	} else {
+		DRV_LOG(DEBUG, "Register fd %d interrupt for virtq %d.",
+			virtq->intr_handle.fd, index);
+	}
 	return 0;
 error:
 	mlx5_vdpa_virtq_unset(virtq);
@@ -275,6 +338,23 @@ 
 		DRV_LOG(ERR, "Failed to configure negotiated features.");
 		return -1;
 	}
+	priv->var = mlx5_glue->dv_alloc_var(priv->ctx, 0);
+	if (!priv->var) {
+		DRV_LOG(ERR, "Failed to allocate VAR %u.\n", errno);
+		return -1;
+	}
+	/* Always map the entire page. */
+	priv->virtq_db_addr = mmap(NULL, priv->var->length, PROT_READ |
+				   PROT_WRITE, MAP_SHARED, priv->ctx->cmd_fd,
+				   priv->var->mmap_off);
+	if (priv->virtq_db_addr == MAP_FAILED) {
+		DRV_LOG(ERR, "Failed to map doorbell page %u.", errno);
+		priv->virtq_db_addr = NULL;
+		goto error;
+	} else {
+		DRV_LOG(DEBUG, "VAR address of doorbell mapping is %p.",
+			priv->virtq_db_addr);
+	}
 	priv->td = mlx5_devx_cmd_create_td(priv->ctx);
 	if (!priv->td) {
 		DRV_LOG(ERR, "Failed to create transport domain.");