Commit 0b7359cc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtio updates from Michael Tsirkin:

 - vdpa/mlx5: support for resumable vqs

 - virtio_scsi: mq_poll support

 - 3virtio_pmem: support SHMEM_REGION

 - virtio_balloon: stay awake while adjusting balloon

 - virtio: support for no-reset virtio PCI PM

 - Fixes, cleanups

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  vdpa/mlx5: Add mkey leak detection
  vdpa/mlx5: Introduce reference counting to mrs
  vdpa/mlx5: Use vq suspend/resume during .set_map
  vdpa/mlx5: Mark vq state for modification in hw vq
  vdpa/mlx5: Mark vq addrs for modification in hw vq
  vdpa/mlx5: Introduce per vq and device resume
  vdpa/mlx5: Allow modifying multiple vq fields in one modify command
  vdpa/mlx5: Expose resumable vq capability
  vdpa: Block vq property changes in DRIVER_OK
  vdpa: Track device suspended state
  scsi: virtio_scsi: Add mq_poll support
  virtio_pmem: support feature SHMEM_REGION
  virtio_balloon: stay awake while adjusting balloon
  vdpa: Remove usage of the deprecated ida_simple_xx() API
  virtio: Add support for no-reset virtio PCI PM
  virtio_net: fix missing dma unmap for resize
  vhost-vdpa: account iommu allocations
  vdpa: Fix an error handling path in eni_vdpa_probe()
parents da3c45c7 f16d6512
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -29,12 +29,27 @@ static int init_vq(struct virtio_pmem *vpmem)
	return 0;
};

static int virtio_pmem_validate(struct virtio_device *vdev)
{
	struct virtio_shm_region shm_reg;

	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION) &&
		!virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID)
	) {
		dev_notice(&vdev->dev, "failed to get shared memory region %d\n",
				VIRTIO_PMEM_SHMEM_REGION_ID);
		__virtio_clear_bit(vdev, VIRTIO_PMEM_F_SHMEM_REGION);
	}
	return 0;
}

static int virtio_pmem_probe(struct virtio_device *vdev)
{
	struct nd_region_desc ndr_desc = {};
	struct nd_region *nd_region;
	struct virtio_pmem *vpmem;
	struct resource res;
	struct virtio_shm_region shm_reg;
	int err = 0;

	if (!vdev->config->get) {
@@ -57,10 +72,16 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
		goto out_err;
	}

	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
		virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
		vpmem->start = shm_reg.addr;
		vpmem->size = shm_reg.len;
	} else {
		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
				start, &vpmem->start);
		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
				size, &vpmem->size);
	}

	res.start = vpmem->start;
	res.end   = vpmem->start + vpmem->size - 1;
@@ -122,10 +143,17 @@ static void virtio_pmem_remove(struct virtio_device *vdev)
	virtio_reset_device(vdev);
}

static unsigned int features[] = {
	VIRTIO_PMEM_F_SHMEM_REGION,
};

static struct virtio_driver virtio_pmem_driver = {
	.feature_table		= features,
	.feature_table_size	= ARRAY_SIZE(features),
	.driver.name		= KBUILD_MODNAME,
	.driver.owner		= THIS_MODULE,
	.id_table		= id_table,
	.validate		= virtio_pmem_validate,
	.probe			= virtio_pmem_probe,
	.remove			= virtio_pmem_remove,
};
+73 −5
Original line number Diff line number Diff line
@@ -37,6 +37,11 @@
#define VIRTIO_SCSI_EVENT_LEN 8
#define VIRTIO_SCSI_VQ_BASE 2

static unsigned int virtscsi_poll_queues;
module_param(virtscsi_poll_queues, uint, 0644);
MODULE_PARM_DESC(virtscsi_poll_queues,
		 "The number of dedicated virtqueues for polling I/O");

/* Command queue element */
struct virtio_scsi_cmd {
	struct scsi_cmnd *sc;
@@ -76,6 +81,7 @@ struct virtio_scsi {
	struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN];

	u32 num_queues;
	int io_queues[HCTX_MAX_TYPES];

	struct hlist_node node;

@@ -722,9 +728,49 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
static void virtscsi_map_queues(struct Scsi_Host *shost)
{
	struct virtio_scsi *vscsi = shost_priv(shost);
	struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
	int i, qoff;

	for (i = 0, qoff = 0; i < shost->nr_maps; i++) {
		struct blk_mq_queue_map *map = &shost->tag_set.map[i];

		map->nr_queues = vscsi->io_queues[i];
		map->queue_offset = qoff;
		qoff += map->nr_queues;

		if (map->nr_queues == 0)
			continue;

		/*
		 * Regular queues have interrupts and hence CPU affinity is
		 * defined by the core virtio code, but polling queues have
		 * no interrupts so we let the block layer assign CPU affinity.
		 */
		if (i == HCTX_TYPE_POLL)
			blk_mq_map_queues(map);
		else
			blk_mq_virtio_map_queues(map, vscsi->vdev, 2);
	}
}

static int virtscsi_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
{
	struct virtio_scsi *vscsi = shost_priv(shost);
	struct virtio_scsi_vq *virtscsi_vq = &vscsi->req_vqs[queue_num];
	unsigned long flags;
	unsigned int len;
	int found = 0;
	void *buf;

	spin_lock_irqsave(&virtscsi_vq->vq_lock, flags);

	blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2);
	while ((buf = virtqueue_get_buf(virtscsi_vq->vq, &len)) != NULL) {
		virtscsi_complete_cmd(vscsi, buf);
		found++;
	}

	spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);

	return found;
}

static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
@@ -751,6 +797,7 @@ static const struct scsi_host_template virtscsi_host_template = {
	.this_id = -1,
	.cmd_size = sizeof(struct virtio_scsi_cmd),
	.queuecommand = virtscsi_queuecommand,
	.mq_poll = virtscsi_mq_poll,
	.commit_rqs = virtscsi_commit_rqs,
	.change_queue_depth = virtscsi_change_queue_depth,
	.eh_abort_handler = virtscsi_abort,
@@ -795,13 +842,14 @@ static int virtscsi_init(struct virtio_device *vdev,
{
	int err;
	u32 i;
	u32 num_vqs;
	u32 num_vqs, num_poll_vqs, num_req_vqs;
	vq_callback_t **callbacks;
	const char **names;
	struct virtqueue **vqs;
	struct irq_affinity desc = { .pre_vectors = 2 };

	num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE;
	num_req_vqs = vscsi->num_queues;
	num_vqs = num_req_vqs + VIRTIO_SCSI_VQ_BASE;
	vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL);
	callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *),
				  GFP_KERNEL);
@@ -812,15 +860,31 @@ static int virtscsi_init(struct virtio_device *vdev,
		goto out;
	}

	num_poll_vqs = min_t(unsigned int, virtscsi_poll_queues,
			     num_req_vqs - 1);
	vscsi->io_queues[HCTX_TYPE_DEFAULT] = num_req_vqs - num_poll_vqs;
	vscsi->io_queues[HCTX_TYPE_READ] = 0;
	vscsi->io_queues[HCTX_TYPE_POLL] = num_poll_vqs;

	dev_info(&vdev->dev, "%d/%d/%d default/read/poll queues\n",
		 vscsi->io_queues[HCTX_TYPE_DEFAULT],
		 vscsi->io_queues[HCTX_TYPE_READ],
		 vscsi->io_queues[HCTX_TYPE_POLL]);

	callbacks[0] = virtscsi_ctrl_done;
	callbacks[1] = virtscsi_event_done;
	names[0] = "control";
	names[1] = "event";
	for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs; i++) {
	for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs - num_poll_vqs; i++) {
		callbacks[i] = virtscsi_req_done;
		names[i] = "request";
	}

	for (; i < num_vqs; i++) {
		callbacks[i] = NULL;
		names[i] = "request_poll";
	}

	/* Discover virtqueues and write information to configuration.  */
	err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
	if (err)
@@ -874,6 +938,7 @@ static int virtscsi_probe(struct virtio_device *vdev)

	sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
	shost->sg_tablesize = sg_elems;
	shost->nr_maps = 1;
	vscsi = shost_priv(shost);
	vscsi->vdev = vdev;
	vscsi->num_queues = num_queues;
@@ -883,6 +948,9 @@ static int virtscsi_probe(struct virtio_device *vdev)
	if (err)
		goto virtscsi_init_failed;

	if (vscsi->io_queues[HCTX_TYPE_POLL])
		shost->nr_maps = HCTX_TYPE_POLL + 1;

	shost->can_queue = virtqueue_get_vring_size(vscsi->req_vqs[0].vq);

	cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
+4 −2
Original line number Diff line number Diff line
@@ -497,7 +497,7 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	if (!eni_vdpa->vring) {
		ret = -ENOMEM;
		ENI_ERR(pdev, "failed to allocate virtqueues\n");
		goto err;
		goto err_remove_vp_legacy;
	}

	for (i = 0; i < eni_vdpa->queues; i++) {
@@ -509,11 +509,13 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	ret = vdpa_register_device(&eni_vdpa->vdpa, eni_vdpa->queues);
	if (ret) {
		ENI_ERR(pdev, "failed to register to vdpa bus\n");
		goto err;
		goto err_remove_vp_legacy;
	}

	return 0;

err_remove_vp_legacy:
	vp_legacy_remove(&eni_vdpa->ldev);
err:
	put_device(&eni_vdpa->vdpa.dev);
	return ret;
+8 −2
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ struct mlx5_vdpa_mr {
	struct vhost_iotlb *iotlb;

	bool user_mr;

	refcount_t refcount;
	struct list_head mr_list;
};

struct mlx5_vdpa_resources {
@@ -93,6 +96,7 @@ struct mlx5_vdpa_dev {
	u32 generation;

	struct mlx5_vdpa_mr *mr[MLX5_VDPA_NUM_AS];
	struct list_head mr_list_head;
	/* serialize mr access */
	struct mutex mr_mtx;
	struct mlx5_control_vq cvq;
@@ -118,7 +122,9 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey);
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,
void mlx5_vdpa_get_mr(struct mlx5_vdpa_dev *mvdev,
		      struct mlx5_vdpa_mr *mr);
void mlx5_vdpa_put_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,
+55 −14
Original line number Diff line number Diff line
@@ -498,32 +498,54 @@ static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr

static void _mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
{
	if (WARN_ON(!mr))
		return;

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

	vhost_iotlb_free(mr->iotlb);

	list_del(&mr->mr_list);

	kfree(mr);
}

void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev,
static void _mlx5_vdpa_put_mr(struct mlx5_vdpa_dev *mvdev,
			      struct mlx5_vdpa_mr *mr)
{
	if (!mr)
		return;

	if (refcount_dec_and_test(&mr->refcount))
		_mlx5_vdpa_destroy_mr(mvdev, mr);
}

void mlx5_vdpa_put_mr(struct mlx5_vdpa_dev *mvdev,
		      struct mlx5_vdpa_mr *mr)
{
	mutex_lock(&mvdev->mr_mtx);
	_mlx5_vdpa_put_mr(mvdev, mr);
	mutex_unlock(&mvdev->mr_mtx);
}

	_mlx5_vdpa_destroy_mr(mvdev, mr);
static void _mlx5_vdpa_get_mr(struct mlx5_vdpa_dev *mvdev,
			      struct mlx5_vdpa_mr *mr)
{
	if (!mr)
		return;

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

void mlx5_vdpa_get_mr(struct mlx5_vdpa_dev *mvdev,
		      struct mlx5_vdpa_mr *mr)
{
	mutex_lock(&mvdev->mr_mtx);
	_mlx5_vdpa_get_mr(mvdev, mr);
	mutex_unlock(&mvdev->mr_mtx);

	kfree(mr);
}

void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
@@ -534,10 +556,23 @@ void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,

	mutex_lock(&mvdev->mr_mtx);

	_mlx5_vdpa_put_mr(mvdev, old_mr);
	mvdev->mr[asid] = new_mr;
	if (old_mr) {
		_mlx5_vdpa_destroy_mr(mvdev, old_mr);
		kfree(old_mr);

	mutex_unlock(&mvdev->mr_mtx);
}

static void mlx5_vdpa_show_mr_leaks(struct mlx5_vdpa_dev *mvdev)
{
	struct mlx5_vdpa_mr *mr;

	mutex_lock(&mvdev->mr_mtx);

	list_for_each_entry(mr, &mvdev->mr_list_head, mr_list) {

		mlx5_vdpa_warn(mvdev, "mkey still alive after resource delete: "
				      "mr: %p, mkey: 0x%x, refcount: %u\n",
				       mr, mr->mkey, refcount_read(&mr->refcount));
	}

	mutex_unlock(&mvdev->mr_mtx);
@@ -547,9 +582,11 @@ void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev)
{
	for (int i = 0; i < MLX5_VDPA_NUM_AS; i++)
		mlx5_vdpa_destroy_mr(mvdev, mvdev->mr[i]);
		mlx5_vdpa_update_mr(mvdev, NULL, i);

	prune_iotlb(mvdev->cvq.iotlb);

	mlx5_vdpa_show_mr_leaks(mvdev);
}

static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
@@ -576,6 +613,8 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
	if (err)
		goto err_iotlb;

	list_add_tail(&mr->mr_list, &mvdev->mr_list_head);

	return 0;

err_iotlb:
@@ -607,6 +646,8 @@ struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
	if (err)
		goto out_err;

	refcount_set(&mr->refcount, 1);

	return mr;

out_err:
@@ -651,7 +692,7 @@ 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]);
	mlx5_vdpa_update_mr(mvdev, NULL, asid);

	if (asid == 0 && MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
		if (mlx5_vdpa_create_dma_mr(mvdev))
Loading