Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[linux-2.6-microblaze.git] / drivers / vdpa / mlx5 / core / mr.c
index e59135f..ff010c6 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 /* Copyright (c) 2020 Mellanox Technologies Ltd. */
 
+#include <linux/vhost_types.h>
 #include <linux/vdpa.h>
 #include <linux/gcd.h>
 #include <linux/string.h>
@@ -451,33 +452,30 @@ static void destroy_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
        mlx5_vdpa_destroy_mkey(mvdev, &mr->mkey);
 }
 
-static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+static int dup_iotlb(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *src)
 {
-       struct mlx5_vdpa_mr *mr = &mvdev->mr;
+       struct vhost_iotlb_map *map;
+       u64 start = 0, last = ULLONG_MAX;
        int err;
 
-       if (mr->initialized)
-               return 0;
-
-       if (iotlb)
-               err = create_user_mr(mvdev, iotlb);
-       else
-               err = create_dma_mr(mvdev, mr);
-
-       if (!err)
-               mr->initialized = true;
+       if (!src) {
+               err = vhost_iotlb_add_range(mvdev->cvq.iotlb, start, last, start, VHOST_ACCESS_RW);
+               return err;
+       }
 
-       return err;
+       for (map = vhost_iotlb_itree_first(src, start, last); map;
+               map = vhost_iotlb_itree_next(map, start, last)) {
+               err = vhost_iotlb_add_range(mvdev->cvq.iotlb, map->start, map->last,
+                                           map->addr, map->perm);
+               if (err)
+                       return err;
+       }
+       return 0;
 }
 
-int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+static void prune_iotlb(struct mlx5_vdpa_dev *mvdev)
 {
-       int err;
-
-       mutex_lock(&mvdev->mr.mkey_mtx);
-       err = _mlx5_vdpa_create_mr(mvdev, iotlb);
-       mutex_unlock(&mvdev->mr.mkey_mtx);
-       return err;
+       vhost_iotlb_del_range(mvdev->cvq.iotlb, 0, ULLONG_MAX);
 }
 
 static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
@@ -501,6 +499,7 @@ void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
        if (!mr->initialized)
                goto out;
 
+       prune_iotlb(mvdev);
        if (mr->user_mr)
                destroy_user_mr(mvdev, mr);
        else
@@ -512,6 +511,48 @@ out:
        mutex_unlock(&mr->mkey_mtx);
 }
 
+static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+{
+       struct mlx5_vdpa_mr *mr = &mvdev->mr;
+       int err;
+
+       if (mr->initialized)
+               return 0;
+
+       if (iotlb)
+               err = create_user_mr(mvdev, iotlb);
+       else
+               err = create_dma_mr(mvdev, mr);
+
+       if (err)
+               return err;
+
+       err = dup_iotlb(mvdev, iotlb);
+       if (err)
+               goto out_err;
+
+       mr->initialized = true;
+       return 0;
+
+out_err:
+       if (iotlb)
+               destroy_user_mr(mvdev, mr);
+       else
+               destroy_dma_mr(mvdev, mr);
+
+       return err;
+}
+
+int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+{
+       int err;
+
+       mutex_lock(&mvdev->mr.mkey_mtx);
+       err = _mlx5_vdpa_create_mr(mvdev, iotlb);
+       mutex_unlock(&mvdev->mr.mkey_mtx);
+       return err;
+}
+
 int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
                             bool *change_map)
 {