]> git.droids-corp.org - dpdk.git/commitdiff
vdpa/mlx5: cache and reuse hardware resources
authorXueming Li <xuemingl@nvidia.com>
Sun, 8 May 2022 14:25:52 +0000 (17:25 +0300)
committerMaxime Coquelin <maxime.coquelin@redhat.com>
Mon, 9 May 2022 19:39:58 +0000 (21:39 +0200)
During device suspend and resume, resources are not changed normally.
When huge resources were allocated to VM, like huge memory size or lots
of queues, time spent on release and recreate became significant.

To speed up, this patch reuses resources like VM MR and VirtQ memory if
not changed.

Signed-off-by: Xueming Li <xuemingl@nvidia.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
drivers/vdpa/mlx5/mlx5_vdpa.c
drivers/vdpa/mlx5/mlx5_vdpa.h
drivers/vdpa/mlx5/mlx5_vdpa_mem.c
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c

index 4408aeccfbd9041671bb9c27b03c55fe1ec98c97..fb5d9276621c89660af6f6ea0f0fac44413b9d6f 100644 (file)
@@ -241,6 +241,13 @@ mlx5_vdpa_mtu_set(struct mlx5_vdpa_priv *priv)
        return kern_mtu == vhost_mtu ? 0 : -1;
 }
 
+static void
+mlx5_vdpa_dev_cache_clean(struct mlx5_vdpa_priv *priv)
+{
+       mlx5_vdpa_virtqs_cleanup(priv);
+       mlx5_vdpa_mem_dereg(priv);
+}
+
 static int
 mlx5_vdpa_dev_close(int vid)
 {
@@ -260,7 +267,8 @@ mlx5_vdpa_dev_close(int vid)
        }
        mlx5_vdpa_steer_unset(priv);
        mlx5_vdpa_virtqs_release(priv);
-       mlx5_vdpa_mem_dereg(priv);
+       if (priv->lm_mr.addr)
+               mlx5_os_wrapped_mkey_destroy(&priv->lm_mr);
        priv->state = MLX5_VDPA_STATE_PROBED;
        priv->vid = 0;
        /* The mutex may stay locked after event thread cancel - initiate it. */
@@ -663,6 +671,7 @@ mlx5_vdpa_release_dev_resources(struct mlx5_vdpa_priv *priv)
 {
        uint32_t i;
 
+       mlx5_vdpa_dev_cache_clean(priv);
        mlx5_vdpa_event_qp_global_release(priv);
        mlx5_vdpa_err_event_unset(priv);
        if (priv->steer.tbl)
index e0ba20b953c7b053e1dbfd033f3a7771477768c4..540bf87a3520952d8a19c3dddd8a8b3c4922c2ce 100644 (file)
@@ -289,13 +289,21 @@ int mlx5_vdpa_err_event_setup(struct mlx5_vdpa_priv *priv);
 void mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv);
 
 /**
- * Release a virtq and all its related resources.
+ * Release virtqs and resources except that to be reused.
  *
  * @param[in] priv
  *   The vdpa driver private structure.
  */
 void mlx5_vdpa_virtqs_release(struct mlx5_vdpa_priv *priv);
 
+/**
+ * Cleanup cached resources of all virtqs.
+ *
+ * @param[in] priv
+ *   The vdpa driver private structure.
+ */
+void mlx5_vdpa_virtqs_cleanup(struct mlx5_vdpa_priv *priv);
+
 /**
  * Create all the HW virtqs resources and all their related resources.
  *
@@ -323,7 +331,7 @@ int mlx5_vdpa_virtqs_prepare(struct mlx5_vdpa_priv *priv);
 int mlx5_vdpa_virtq_enable(struct mlx5_vdpa_priv *priv, int index, int enable);
 
 /**
- * Unset steering and release all its related resources- stop traffic.
+ * Unset steering - stop traffic.
  *
  * @param[in] priv
  *   The vdpa driver private structure.
index 62f5530e91daf3422b1ddf2fd58a830a81339342..d6e3dd664b5b3c68e11dda8a61a787aaffa96a78 100644 (file)
@@ -32,8 +32,6 @@ mlx5_vdpa_mem_dereg(struct mlx5_vdpa_priv *priv)
                entry = next;
        }
        SLIST_INIT(&priv->mr_list);
-       if (priv->lm_mr.addr)
-               mlx5_os_wrapped_mkey_destroy(&priv->lm_mr);
        if (priv->vmem) {
                free(priv->vmem);
                priv->vmem = NULL;
@@ -149,6 +147,23 @@ mlx5_vdpa_vhost_mem_regions_prepare(int vid, uint8_t *mode, uint64_t *mem_size,
        return mem;
 }
 
+static int
+mlx5_vdpa_mem_cmp(struct rte_vhost_memory *mem1, struct rte_vhost_memory *mem2)
+{
+       uint32_t i;
+
+       if (mem1->nregions != mem2->nregions)
+               return -1;
+       for (i = 0; i < mem1->nregions; i++) {
+               if (mem1->regions[i].guest_phys_addr !=
+                   mem2->regions[i].guest_phys_addr)
+                       return -1;
+               if (mem1->regions[i].size != mem2->regions[i].size)
+                       return -1;
+       }
+       return 0;
+}
+
 #define KLM_SIZE_MAX_ALIGN(sz) ((sz) > MLX5_MAX_KLM_BYTE_COUNT ? \
                                MLX5_MAX_KLM_BYTE_COUNT : (sz))
 
@@ -191,6 +206,14 @@ mlx5_vdpa_mem_register(struct mlx5_vdpa_priv *priv)
 
        if (!mem)
                return -rte_errno;
+       if (priv->vmem != NULL) {
+               if (mlx5_vdpa_mem_cmp(mem, priv->vmem) == 0) {
+                       /* VM memory not changed, reuse resources. */
+                       free(mem);
+                       return 0;
+               }
+               mlx5_vdpa_mem_dereg(priv);
+       }
        priv->vmem = mem;
        for (i = 0; i < mem->nregions; i++) {
                reg = &mem->regions[i];
index 5ab63930ce826cd28ca139e2e4eb1942048c178f..0dfeb8fce24af263c86c7bb1c0a135e0a11fd135 100644 (file)
@@ -66,10 +66,33 @@ mlx5_vdpa_virtq_kick_handler(void *cb_arg)
        DRV_LOG(DEBUG, "Ring virtq %u doorbell.", virtq->index);
 }
 
+/* Release cached VQ resources. */
+void
+mlx5_vdpa_virtqs_cleanup(struct mlx5_vdpa_priv *priv)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < priv->caps.max_num_virtio_queues * 2; i++) {
+               struct mlx5_vdpa_virtq *virtq = &priv->virtqs[i];
+
+               for (j = 0; j < RTE_DIM(virtq->umems); ++j) {
+                       if (virtq->umems[j].obj) {
+                               claim_zero(mlx5_glue->devx_umem_dereg
+                                                       (virtq->umems[j].obj));
+                               virtq->umems[j].obj = NULL;
+                       }
+                       if (virtq->umems[j].buf) {
+                               rte_free(virtq->umems[j].buf);
+                               virtq->umems[j].buf = NULL;
+                       }
+                       virtq->umems[j].size = 0;
+               }
+       }
+}
+
 static int
 mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq)
 {
-       unsigned int i;
        int ret = -EAGAIN;
 
        if (rte_intr_fd_get(virtq->intr_handle) >= 0) {
@@ -94,13 +117,6 @@ mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq)
                claim_zero(mlx5_devx_cmd_destroy(virtq->virtq));
        }
        virtq->virtq = NULL;
-       for (i = 0; i < RTE_DIM(virtq->umems); ++i) {
-               if (virtq->umems[i].obj)
-                       claim_zero(mlx5_glue->devx_umem_dereg
-                                                        (virtq->umems[i].obj));
-               rte_free(virtq->umems[i].buf);
-       }
-       memset(&virtq->umems, 0, sizeof(virtq->umems));
        if (virtq->eqp.fw_qp)
                mlx5_vdpa_event_qp_destroy(&virtq->eqp);
        virtq->notifier_state = MLX5_VDPA_NOTIFIER_STATE_DISABLED;
@@ -120,7 +136,6 @@ mlx5_vdpa_virtqs_release(struct mlx5_vdpa_priv *priv)
                        claim_zero(mlx5_devx_cmd_destroy(virtq->counters));
        }
        priv->features = 0;
-       memset(priv->virtqs, 0, sizeof(*virtq) * priv->nr_virtqs);
        priv->nr_virtqs = 0;
 }
 
@@ -215,6 +230,8 @@ mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv, int index)
        ret = rte_vhost_get_vhost_vring(priv->vid, index, &vq);
        if (ret)
                return -1;
+       if (vq.size == 0)
+               return 0;
        virtq->index = index;
        virtq->vq_size = vq.size;
        attr.tso_ipv4 = !!(priv->features & (1ULL << VIRTIO_NET_F_HOST_TSO4));
@@ -259,24 +276,42 @@ mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv, int index)
        }
        /* Setup 3 UMEMs for each virtq. */
        for (i = 0; i < RTE_DIM(virtq->umems); ++i) {
-               virtq->umems[i].size = priv->caps.umems[i].a * vq.size +
-                                                         priv->caps.umems[i].b;
-               virtq->umems[i].buf = rte_zmalloc(__func__,
-                                                 virtq->umems[i].size, 4096);
-               if (!virtq->umems[i].buf) {
+               uint32_t size;
+               void *buf;
+               struct mlx5dv_devx_umem *obj;
+
+               size = priv->caps.umems[i].a * vq.size + priv->caps.umems[i].b;
+               if (virtq->umems[i].size == size &&
+                   virtq->umems[i].obj != NULL) {
+                       /* Reuse registered memory. */
+                       memset(virtq->umems[i].buf, 0, size);
+                       goto reuse;
+               }
+               if (virtq->umems[i].obj)
+                       claim_zero(mlx5_glue->devx_umem_dereg
+                                  (virtq->umems[i].obj));
+               if (virtq->umems[i].buf)
+                       rte_free(virtq->umems[i].buf);
+               virtq->umems[i].size = 0;
+               virtq->umems[i].obj = NULL;
+               virtq->umems[i].buf = NULL;
+               buf = rte_zmalloc(__func__, size, 4096);
+               if (buf == NULL) {
                        DRV_LOG(ERR, "Cannot allocate umem %d memory for virtq"
                                " %u.", i, index);
                        goto error;
                }
-               virtq->umems[i].obj = mlx5_glue->devx_umem_reg(priv->cdev->ctx,
-                                                       virtq->umems[i].buf,
-                                                       virtq->umems[i].size,
-                                                       IBV_ACCESS_LOCAL_WRITE);
-               if (!virtq->umems[i].obj) {
+               obj = mlx5_glue->devx_umem_reg(priv->cdev->ctx, buf, size,
+                                              IBV_ACCESS_LOCAL_WRITE);
+               if (obj == NULL) {
                        DRV_LOG(ERR, "Failed to register umem %d for virtq %u.",
                                i, index);
                        goto error;
                }
+               virtq->umems[i].size = size;
+               virtq->umems[i].buf = buf;
+               virtq->umems[i].obj = obj;
+reuse:
                attr.umems[i].id = virtq->umems[i].obj->umem_id;
                attr.umems[i].offset = 0;
                attr.umems[i].size = virtq->umems[i].size;