Commit 77fa2fbe authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtio updates from Michael Tsirkin:
 "vhost,virtio,vdpa: features, fixes, cleanups.

  vdpa/mlx5:
   - VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK
   - new maintainer

  vdpa:
   - support for vq descriptor mappings
   - decouple reset of iotlb mapping from device reset

  and fixes, cleanups all over the place"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (34 commits)
  vdpa_sim: implement .reset_map support
  vdpa/mlx5: implement .reset_map driver op
  vhost-vdpa: clean iotlb map during reset for older userspace
  vdpa: introduce .compat_reset operation callback
  vhost-vdpa: introduce IOTLB_PERSIST backend feature bit
  vhost-vdpa: reset vendor specific mapping to initial state in .release
  vdpa: introduce .reset_map operation callback
  virtio_pci: add check for common cfg size
  virtio-blk: fix implicit overflow on virtio_max_dma_size
  virtio_pci: add build offset check for the new common cfg items
  virtio: add definition of VIRTIO_F_NOTIF_CONFIG_DATA feature bit
  vduse: make vduse_class constant
  vhost-scsi: Spelling s/preceeding/preceding/g
  virtio: kdoc for struct virtio_pci_modern_device
  vdpa: Update sysfs ABI documentation
  MAINTAINERS: Add myself as mlx5_vdpa driver
  virtio-balloon: correct the comment of virtballoon_migratepage()
  mlx5_vdpa: offer VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK
  vdpa/mlx5: Update cvq iotlb mapping on ASID change
  vdpa/mlx5: Make iotlb helper functions more generic
  ...
parents 1cfb7511 86f6c224
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
What:		/sys/bus/vdpa/driver_autoprobe
What:		/sys/bus/vdpa/drivers_autoprobe
Date:		March 2020
Contact:	virtualization@lists.linux-foundation.org
Description:
@@ -17,7 +17,7 @@ Description:
		Writing a device name to this file will cause the kernel binds
		devices to a compatible driver.

		This can be useful when /sys/bus/vdpa/driver_autoprobe is
		This can be useful when /sys/bus/vdpa/drivers_autoprobe is
		disabled.

What:		/sys/bus/vdpa/drivers/.../bind
+6 −0
Original line number Diff line number Diff line
@@ -13790,6 +13790,12 @@ F: drivers/infiniband/hw/mlx5/
F:	include/linux/mlx5/
F:	include/uapi/rdma/mlx5-abi.h
MELLANOX MLX5 VDPA DRIVER
M:	Dragos Tatulea <dtatulea@nvidia.com>
L:	virtualization@lists.linux-foundation.org
S:	Supported
F:	drivers/vdpa/mlx5/
MELLANOX MLXCPLD I2C AND MUX DRIVER
M:	Vadim Pasternak <vadimp@nvidia.com>
M:	Michael Shych <michaelsh@nvidia.com>
+3 −1
Original line number Diff line number Diff line
@@ -1311,6 +1311,7 @@ static int virtblk_probe(struct virtio_device *vdev)
	u16 min_io_size;
	u8 physical_block_exp, alignment_offset;
	unsigned int queue_depth;
	size_t max_dma_size;

	if (!vdev->config->get) {
		dev_err(&vdev->dev, "%s failure: config access disabled\n",
@@ -1409,7 +1410,8 @@ static int virtblk_probe(struct virtio_device *vdev)
	/* No real sector limit. */
	blk_queue_max_hw_sectors(q, UINT_MAX);

	max_size = virtio_max_dma_size(vdev);
	max_dma_size = virtio_max_dma_size(vdev);
	max_size = max_dma_size > U32_MAX ? U32_MAX : max_dma_size;

	/* Host can optionally specify maximum segment size and number of
	 * segments. */
+20 −12
Original line number Diff line number Diff line
@@ -31,11 +31,9 @@ struct mlx5_vdpa_mr {
	struct list_head head;
	unsigned long num_directs;
	unsigned long num_klms;
	/* state of dvq mr */
	bool initialized;

	/* serialize mkey creation and destruction */
	struct mutex mkey_mtx;
	struct vhost_iotlb *iotlb;

	bool user_mr;
};

@@ -74,11 +72,12 @@ struct mlx5_vdpa_wq_ent {
enum {
	MLX5_VDPA_DATAVQ_GROUP,
	MLX5_VDPA_CVQ_GROUP,
	MLX5_VDPA_DATAVQ_DESC_GROUP,
	MLX5_VDPA_NUMVQ_GROUPS
};

enum {
	MLX5_VDPA_NUM_AS = MLX5_VDPA_NUMVQ_GROUPS
	MLX5_VDPA_NUM_AS = 2
};

struct mlx5_vdpa_dev {
@@ -93,7 +92,9 @@ struct mlx5_vdpa_dev {
	u16 max_idx;
	u32 generation;

	struct mlx5_vdpa_mr mr;
	struct mlx5_vdpa_mr *mr[MLX5_VDPA_NUM_AS];
	/* serialize mr access */
	struct mutex mr_mtx;
	struct mlx5_control_vq cvq;
	struct workqueue_struct *wq;
	unsigned int group2asid[MLX5_VDPA_NUMVQ_GROUPS];
@@ -114,12 +115,19 @@ void mlx5_vdpa_free_resources(struct mlx5_vdpa_dev *mvdev);
int mlx5_vdpa_create_mkey(struct mlx5_vdpa_dev *mvdev, u32 *mkey, u32 *in,
			  int inlen);
int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey);
int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
			     bool *change_map, unsigned int asid);
int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
					 struct vhost_iotlb *iotlb);
void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev);
void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev,
			  struct mlx5_vdpa_mr *mr);
void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
			 struct mlx5_vdpa_mr *mr,
			 unsigned int asid);
int mlx5_vdpa_update_cvq_iotlb(struct mlx5_vdpa_dev *mvdev,
				struct vhost_iotlb *iotlb,
				unsigned int asid);
void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev);
void mlx5_vdpa_destroy_mr_asid(struct mlx5_vdpa_dev *mvdev, unsigned int asid);
int mlx5_vdpa_create_dma_mr(struct mlx5_vdpa_dev *mvdev);
int mlx5_vdpa_reset_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid);

#define mlx5_vdpa_warn(__dev, format, ...)                                                         \
	dev_warn((__dev)->mdev->device, "%s:%d:(pid %d) warning: " format, __func__, __LINE__,     \
+126 −83
Original line number Diff line number Diff line
@@ -301,10 +301,13 @@ static void unmap_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct
	sg_free_table(&mr->sg_head);
}

static int add_direct_chain(struct mlx5_vdpa_dev *mvdev, u64 start, u64 size, u8 perm,
static int add_direct_chain(struct mlx5_vdpa_dev *mvdev,
			    struct mlx5_vdpa_mr *mr,
			    u64 start,
			    u64 size,
			    u8 perm,
			    struct vhost_iotlb *iotlb)
{
	struct mlx5_vdpa_mr *mr = &mvdev->mr;
	struct mlx5_vdpa_direct_mr *dmr;
	struct mlx5_vdpa_direct_mr *n;
	LIST_HEAD(tmp);
@@ -354,9 +357,10 @@ static int add_direct_chain(struct mlx5_vdpa_dev *mvdev, u64 start, u64 size, u8
 * indirect memory key that provides access to the enitre address space given
 * by iotlb.
 */
static int create_user_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
static int create_user_mr(struct mlx5_vdpa_dev *mvdev,
			  struct mlx5_vdpa_mr *mr,
			  struct vhost_iotlb *iotlb)
{
	struct mlx5_vdpa_mr *mr = &mvdev->mr;
	struct mlx5_vdpa_direct_mr *dmr;
	struct mlx5_vdpa_direct_mr *n;
	struct vhost_iotlb_map *map;
@@ -384,7 +388,7 @@ static int create_user_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb
								       LOG_MAX_KLM_SIZE);
					mr->num_klms += nnuls;
				}
				err = add_direct_chain(mvdev, ps, pe - ps, pperm, iotlb);
				err = add_direct_chain(mvdev, mr, ps, pe - ps, pperm, iotlb);
				if (err)
					goto err_chain;
			}
@@ -393,7 +397,7 @@ static int create_user_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb
			pperm = map->perm;
		}
	}
	err = add_direct_chain(mvdev, ps, pe - ps, pperm, iotlb);
	err = add_direct_chain(mvdev, mr, ps, pe - ps, pperm, iotlb);
	if (err)
		goto err_chain;

@@ -450,20 +454,23 @@ static void destroy_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
	mlx5_vdpa_destroy_mkey(mvdev, mr->mkey);
}

static int dup_iotlb(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *src)
static int dup_iotlb(struct vhost_iotlb *dst, struct vhost_iotlb *src)
{
	struct vhost_iotlb_map *map;
	u64 start = 0, last = ULLONG_MAX;
	int err;

	if (dst == src)
		return -EINVAL;

	if (!src) {
		err = vhost_iotlb_add_range(mvdev->cvq.iotlb, start, last, start, VHOST_ACCESS_RW);
		err = vhost_iotlb_add_range(dst, start, last, start, VHOST_ACCESS_RW);
		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,
		err = vhost_iotlb_add_range(dst, map->start, map->last,
					    map->addr, map->perm);
		if (err)
			return err;
@@ -471,9 +478,9 @@ static int dup_iotlb(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *src)
	return 0;
}

static void prune_iotlb(struct mlx5_vdpa_dev *mvdev)
static void prune_iotlb(struct vhost_iotlb *iotlb)
{
	vhost_iotlb_del_range(mvdev->cvq.iotlb, 0, ULLONG_MAX);
	vhost_iotlb_del_range(iotlb, 0, ULLONG_MAX);
}

static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
@@ -489,133 +496,169 @@ static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr
	}
}

static void _mlx5_vdpa_destroy_cvq_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
{
	if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] != asid)
		return;

	prune_iotlb(mvdev);
}

static void _mlx5_vdpa_destroy_dvq_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
static void _mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
{
	struct mlx5_vdpa_mr *mr = &mvdev->mr;

	if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] != asid)
		return;

	if (!mr->initialized)
		return;

	if (mr->user_mr)
		destroy_user_mr(mvdev, mr);
	else
		destroy_dma_mr(mvdev, mr);

	mr->initialized = false;
	vhost_iotlb_free(mr->iotlb);
}

void mlx5_vdpa_destroy_mr_asid(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev,
			  struct mlx5_vdpa_mr *mr)
{
	struct mlx5_vdpa_mr *mr = &mvdev->mr;
	if (!mr)
		return;

	mutex_lock(&mr->mkey_mtx);
	mutex_lock(&mvdev->mr_mtx);

	_mlx5_vdpa_destroy_dvq_mr(mvdev, asid);
	_mlx5_vdpa_destroy_cvq_mr(mvdev, asid);
	_mlx5_vdpa_destroy_mr(mvdev, mr);

	mutex_unlock(&mr->mkey_mtx);
	for (int i = 0; i < MLX5_VDPA_NUM_AS; i++) {
		if (mvdev->mr[i] == mr)
			mvdev->mr[i] = NULL;
	}

void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
{
	mlx5_vdpa_destroy_mr_asid(mvdev, mvdev->group2asid[MLX5_VDPA_CVQ_GROUP]);
	mlx5_vdpa_destroy_mr_asid(mvdev, mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]);
	mutex_unlock(&mvdev->mr_mtx);

	kfree(mr);
}

static int _mlx5_vdpa_create_cvq_mr(struct mlx5_vdpa_dev *mvdev,
				    struct vhost_iotlb *iotlb,
void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
			 struct mlx5_vdpa_mr *new_mr,
			 unsigned int asid)
{
	if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] != asid)
		return 0;
	struct mlx5_vdpa_mr *old_mr = mvdev->mr[asid];

	mutex_lock(&mvdev->mr_mtx);

	return dup_iotlb(mvdev, iotlb);
	mvdev->mr[asid] = new_mr;
	if (old_mr) {
		_mlx5_vdpa_destroy_mr(mvdev, old_mr);
		kfree(old_mr);
	}

static int _mlx5_vdpa_create_dvq_mr(struct mlx5_vdpa_dev *mvdev,
				    struct vhost_iotlb *iotlb,
				    unsigned int asid)
	mutex_unlock(&mvdev->mr_mtx);

}

void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev)
{
	struct mlx5_vdpa_mr *mr = &mvdev->mr;
	int err;
	for (int i = 0; i < MLX5_VDPA_NUM_AS; i++)
		mlx5_vdpa_destroy_mr(mvdev, mvdev->mr[i]);

	if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] != asid)
		return 0;
	prune_iotlb(mvdev->cvq.iotlb);
}

	if (mr->initialized)
		return 0;
static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
				struct mlx5_vdpa_mr *mr,
				struct vhost_iotlb *iotlb)
{
	int err;

	if (iotlb)
		err = create_user_mr(mvdev, iotlb);
		err = create_user_mr(mvdev, mr, iotlb);
	else
		err = create_dma_mr(mvdev, mr);

	if (err)
		return err;

	mr->initialized = true;
	mr->iotlb = vhost_iotlb_alloc(0, 0);
	if (!mr->iotlb) {
		err = -ENOMEM;
		goto err_mr;
	}

	err = dup_iotlb(mr->iotlb, iotlb);
	if (err)
		goto err_iotlb;

	return 0;

err_iotlb:
	vhost_iotlb_free(mr->iotlb);

err_mr:
	if (iotlb)
		destroy_user_mr(mvdev, mr);
	else
		destroy_dma_mr(mvdev, mr);

	return err;
}

static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
				struct vhost_iotlb *iotlb, unsigned int asid)
struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
					 struct vhost_iotlb *iotlb)
{
	struct mlx5_vdpa_mr *mr;
	int err;

	err = _mlx5_vdpa_create_dvq_mr(mvdev, iotlb, asid);
	if (err)
		return err;
	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
	if (!mr)
		return ERR_PTR(-ENOMEM);

	mutex_lock(&mvdev->mr_mtx);
	err = _mlx5_vdpa_create_mr(mvdev, mr, iotlb);
	mutex_unlock(&mvdev->mr_mtx);

	err = _mlx5_vdpa_create_cvq_mr(mvdev, iotlb, asid);
	if (err)
		goto out_err;

	return 0;
	return mr;

out_err:
	_mlx5_vdpa_destroy_dvq_mr(mvdev, asid);

	return err;
	kfree(mr);
	return ERR_PTR(err);
}

int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
int mlx5_vdpa_update_cvq_iotlb(struct mlx5_vdpa_dev *mvdev,
				struct vhost_iotlb *iotlb,
				unsigned int asid)
{
	int err;

	mutex_lock(&mvdev->mr.mkey_mtx);
	err = _mlx5_vdpa_create_mr(mvdev, iotlb, asid);
	mutex_unlock(&mvdev->mr.mkey_mtx);
	if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] != asid)
		return 0;

	spin_lock(&mvdev->cvq.iommu_lock);

	prune_iotlb(mvdev->cvq.iotlb);
	err = dup_iotlb(mvdev->cvq.iotlb, iotlb);

	spin_unlock(&mvdev->cvq.iommu_lock);

	return err;
}

int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
			     bool *change_map, unsigned int asid)
int mlx5_vdpa_create_dma_mr(struct mlx5_vdpa_dev *mvdev)
{
	struct mlx5_vdpa_mr *mr = &mvdev->mr;
	int err = 0;
	struct mlx5_vdpa_mr *mr;

	mr = mlx5_vdpa_create_mr(mvdev, NULL);
	if (IS_ERR(mr))
		return PTR_ERR(mr);

	mlx5_vdpa_update_mr(mvdev, mr, 0);

	*change_map = false;
	mutex_lock(&mr->mkey_mtx);
	if (mr->initialized) {
		mlx5_vdpa_info(mvdev, "memory map update\n");
		*change_map = true;
	return mlx5_vdpa_update_cvq_iotlb(mvdev, NULL, 0);
}
	if (!*change_map)
		err = _mlx5_vdpa_create_mr(mvdev, iotlb, asid);
	mutex_unlock(&mr->mkey_mtx);

	return err;
int mlx5_vdpa_reset_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
{
	if (asid >= MLX5_VDPA_NUM_AS)
		return -EINVAL;

	mlx5_vdpa_destroy_mr(mvdev, mvdev->mr[asid]);

	if (asid == 0 && MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
		if (mlx5_vdpa_create_dma_mr(mvdev))
			mlx5_vdpa_warn(mvdev, "create DMA MR failed\n");
	} else {
		mlx5_vdpa_update_cvq_iotlb(mvdev, NULL, asid);
	}

	return 0;
}
Loading