Commit 0b7359cc authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

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
...@@ -29,12 +29,27 @@ static int init_vq(struct virtio_pmem *vpmem) ...@@ -29,12 +29,27 @@ static int init_vq(struct virtio_pmem *vpmem)
return 0; 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) static int virtio_pmem_probe(struct virtio_device *vdev)
{ {
struct nd_region_desc ndr_desc = {}; struct nd_region_desc ndr_desc = {};
struct nd_region *nd_region; struct nd_region *nd_region;
struct virtio_pmem *vpmem; struct virtio_pmem *vpmem;
struct resource res; struct resource res;
struct virtio_shm_region shm_reg;
int err = 0; int err = 0;
if (!vdev->config->get) { if (!vdev->config->get) {
...@@ -57,10 +72,16 @@ static int virtio_pmem_probe(struct virtio_device *vdev) ...@@ -57,10 +72,16 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
goto out_err; goto out_err;
} }
virtio_cread_le(vpmem->vdev, struct virtio_pmem_config, if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
start, &vpmem->start); virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
virtio_cread_le(vpmem->vdev, struct virtio_pmem_config, vpmem->start = shm_reg.addr;
size, &vpmem->size); 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.start = vpmem->start;
res.end = vpmem->start + vpmem->size - 1; res.end = vpmem->start + vpmem->size - 1;
...@@ -122,10 +143,17 @@ static void virtio_pmem_remove(struct virtio_device *vdev) ...@@ -122,10 +143,17 @@ static void virtio_pmem_remove(struct virtio_device *vdev)
virtio_reset_device(vdev); virtio_reset_device(vdev);
} }
static unsigned int features[] = {
VIRTIO_PMEM_F_SHMEM_REGION,
};
static struct virtio_driver virtio_pmem_driver = { static struct virtio_driver virtio_pmem_driver = {
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME, .driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE, .driver.owner = THIS_MODULE,
.id_table = id_table, .id_table = id_table,
.validate = virtio_pmem_validate,
.probe = virtio_pmem_probe, .probe = virtio_pmem_probe,
.remove = virtio_pmem_remove, .remove = virtio_pmem_remove,
}; };
......
...@@ -37,6 +37,11 @@ ...@@ -37,6 +37,11 @@
#define VIRTIO_SCSI_EVENT_LEN 8 #define VIRTIO_SCSI_EVENT_LEN 8
#define VIRTIO_SCSI_VQ_BASE 2 #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 */ /* Command queue element */
struct virtio_scsi_cmd { struct virtio_scsi_cmd {
struct scsi_cmnd *sc; struct scsi_cmnd *sc;
...@@ -76,6 +81,7 @@ struct virtio_scsi { ...@@ -76,6 +81,7 @@ struct virtio_scsi {
struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN]; struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN];
u32 num_queues; u32 num_queues;
int io_queues[HCTX_MAX_TYPES];
struct hlist_node node; struct hlist_node node;
...@@ -722,9 +728,49 @@ static int virtscsi_abort(struct scsi_cmnd *sc) ...@@ -722,9 +728,49 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
static void virtscsi_map_queues(struct Scsi_Host *shost) static void virtscsi_map_queues(struct Scsi_Host *shost)
{ {
struct virtio_scsi *vscsi = shost_priv(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);
while ((buf = virtqueue_get_buf(virtscsi_vq->vq, &len)) != NULL) {
virtscsi_complete_cmd(vscsi, buf);
found++;
}
spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2); return found;
} }
static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq) static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
...@@ -751,6 +797,7 @@ static const struct scsi_host_template virtscsi_host_template = { ...@@ -751,6 +797,7 @@ static const struct scsi_host_template virtscsi_host_template = {
.this_id = -1, .this_id = -1,
.cmd_size = sizeof(struct virtio_scsi_cmd), .cmd_size = sizeof(struct virtio_scsi_cmd),
.queuecommand = virtscsi_queuecommand, .queuecommand = virtscsi_queuecommand,
.mq_poll = virtscsi_mq_poll,
.commit_rqs = virtscsi_commit_rqs, .commit_rqs = virtscsi_commit_rqs,
.change_queue_depth = virtscsi_change_queue_depth, .change_queue_depth = virtscsi_change_queue_depth,
.eh_abort_handler = virtscsi_abort, .eh_abort_handler = virtscsi_abort,
...@@ -795,13 +842,14 @@ static int virtscsi_init(struct virtio_device *vdev, ...@@ -795,13 +842,14 @@ static int virtscsi_init(struct virtio_device *vdev,
{ {
int err; int err;
u32 i; u32 i;
u32 num_vqs; u32 num_vqs, num_poll_vqs, num_req_vqs;
vq_callback_t **callbacks; vq_callback_t **callbacks;
const char **names; const char **names;
struct virtqueue **vqs; struct virtqueue **vqs;
struct irq_affinity desc = { .pre_vectors = 2 }; 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); vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL);
callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *), callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *),
GFP_KERNEL); GFP_KERNEL);
...@@ -812,15 +860,31 @@ static int virtscsi_init(struct virtio_device *vdev, ...@@ -812,15 +860,31 @@ static int virtscsi_init(struct virtio_device *vdev,
goto out; 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[0] = virtscsi_ctrl_done;
callbacks[1] = virtscsi_event_done; callbacks[1] = virtscsi_event_done;
names[0] = "control"; names[0] = "control";
names[1] = "event"; 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; callbacks[i] = virtscsi_req_done;
names[i] = "request"; names[i] = "request";
} }
for (; i < num_vqs; i++) {
callbacks[i] = NULL;
names[i] = "request_poll";
}
/* Discover virtqueues and write information to configuration. */ /* Discover virtqueues and write information to configuration. */
err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc); err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
if (err) if (err)
...@@ -874,6 +938,7 @@ static int virtscsi_probe(struct virtio_device *vdev) ...@@ -874,6 +938,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1; sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
shost->sg_tablesize = sg_elems; shost->sg_tablesize = sg_elems;
shost->nr_maps = 1;
vscsi = shost_priv(shost); vscsi = shost_priv(shost);
vscsi->vdev = vdev; vscsi->vdev = vdev;
vscsi->num_queues = num_queues; vscsi->num_queues = num_queues;
...@@ -883,6 +948,9 @@ static int virtscsi_probe(struct virtio_device *vdev) ...@@ -883,6 +948,9 @@ static int virtscsi_probe(struct virtio_device *vdev)
if (err) if (err)
goto virtscsi_init_failed; 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); shost->can_queue = virtqueue_get_vring_size(vscsi->req_vqs[0].vq);
cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1; cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
......
...@@ -497,7 +497,7 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -497,7 +497,7 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!eni_vdpa->vring) { if (!eni_vdpa->vring) {
ret = -ENOMEM; ret = -ENOMEM;
ENI_ERR(pdev, "failed to allocate virtqueues\n"); ENI_ERR(pdev, "failed to allocate virtqueues\n");
goto err; goto err_remove_vp_legacy;
} }
for (i = 0; i < eni_vdpa->queues; i++) { 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) ...@@ -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); ret = vdpa_register_device(&eni_vdpa->vdpa, eni_vdpa->queues);
if (ret) { if (ret) {
ENI_ERR(pdev, "failed to register to vdpa bus\n"); ENI_ERR(pdev, "failed to register to vdpa bus\n");
goto err; goto err_remove_vp_legacy;
} }
return 0; return 0;
err_remove_vp_legacy:
vp_legacy_remove(&eni_vdpa->ldev);
err: err:
put_device(&eni_vdpa->vdpa.dev); put_device(&eni_vdpa->vdpa.dev);
return ret; return ret;
......
...@@ -35,6 +35,9 @@ struct mlx5_vdpa_mr { ...@@ -35,6 +35,9 @@ struct mlx5_vdpa_mr {
struct vhost_iotlb *iotlb; struct vhost_iotlb *iotlb;
bool user_mr; bool user_mr;
refcount_t refcount;
struct list_head mr_list;
}; };
struct mlx5_vdpa_resources { struct mlx5_vdpa_resources {
...@@ -93,6 +96,7 @@ struct mlx5_vdpa_dev { ...@@ -93,6 +96,7 @@ struct mlx5_vdpa_dev {
u32 generation; u32 generation;
struct mlx5_vdpa_mr *mr[MLX5_VDPA_NUM_AS]; struct mlx5_vdpa_mr *mr[MLX5_VDPA_NUM_AS];
struct list_head mr_list_head;
/* serialize mr access */ /* serialize mr access */
struct mutex mr_mtx; struct mutex mr_mtx;
struct mlx5_control_vq cvq; struct mlx5_control_vq cvq;
...@@ -118,8 +122,10 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey); ...@@ -118,8 +122,10 @@ 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 mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
struct vhost_iotlb *iotlb); struct vhost_iotlb *iotlb);
void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev); 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); 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, void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
struct mlx5_vdpa_mr *mr, struct mlx5_vdpa_mr *mr,
unsigned int asid); unsigned int asid);
......
...@@ -498,32 +498,54 @@ static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr ...@@ -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) 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) if (mr->user_mr)
destroy_user_mr(mvdev, mr); destroy_user_mr(mvdev, mr);
else else
destroy_dma_mr(mvdev, mr); destroy_dma_mr(mvdev, mr);
vhost_iotlb_free(mr->iotlb); 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) struct mlx5_vdpa_mr *mr)
{ {
if (!mr) if (!mr)
return; 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); 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++) { refcount_inc(&mr->refcount);
if (mvdev->mr[i] == mr) }
mvdev->mr[i] = NULL;
}
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); mutex_unlock(&mvdev->mr_mtx);
kfree(mr);
} }
void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev, void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
...@@ -534,10 +556,23 @@ 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); mutex_lock(&mvdev->mr_mtx);
_mlx5_vdpa_put_mr(mvdev, old_mr);
mvdev->mr[asid] = new_mr; mvdev->mr[asid] = new_mr;
if (old_mr) {
_mlx5_vdpa_destroy_mr(mvdev, old_mr); mutex_unlock(&mvdev->mr_mtx);
kfree(old_mr); }
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); mutex_unlock(&mvdev->mr_mtx);
...@@ -547,9 +582,11 @@ void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev, ...@@ -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) void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev)
{ {
for (int i = 0; i < MLX5_VDPA_NUM_AS; i++) 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); prune_iotlb(mvdev->cvq.iotlb);
mlx5_vdpa_show_mr_leaks(mvdev);
} }
static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *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, ...@@ -576,6 +613,8 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
if (err) if (err)
goto err_iotlb; goto err_iotlb;
list_add_tail(&mr->mr_list, &mvdev->mr_list_head);
return 0; return 0;
err_iotlb: err_iotlb:
...@@ -607,6 +646,8 @@ struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, ...@@ -607,6 +646,8 @@ struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
if (err) if (err)
goto out_err; goto out_err;
refcount_set(&mr->refcount, 1);
return mr; return mr;
out_err: out_err:
...@@ -651,7 +692,7 @@ int mlx5_vdpa_reset_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid) ...@@ -651,7 +692,7 @@ int mlx5_vdpa_reset_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
if (asid >= MLX5_VDPA_NUM_AS) if (asid >= MLX5_VDPA_NUM_AS)
return -EINVAL; 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 (asid == 0 && MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
if (mlx5_vdpa_create_dma_mr(mvdev)) if (mlx5_vdpa_create_dma_mr(mvdev))
......
This diff is collapsed.
...@@ -131,7 +131,7 @@ static void vdpa_release_dev(struct device *d) ...@@ -131,7 +131,7 @@ static void vdpa_release_dev(struct device *d)
if (ops->free) if (ops->free)
ops->free(vdev); ops->free(vdev);
ida_simple_remove(&vdpa_index_ida, vdev->index); ida_free(&vdpa_index_ida, vdev->index);
kfree(vdev->driver_override); kfree(vdev->driver_override);
kfree(vdev); kfree(vdev);
} }
...@@ -205,7 +205,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent, ...@@ -205,7 +205,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
return vdev; return vdev;
err_name: err_name:
ida_simple_remove(&vdpa_index_ida, vdev->index); ida_free(&vdpa_index_ida, vdev->index);
err_ida: err_ida:
kfree(vdev); kfree(vdev);
err: err:
......
...@@ -59,6 +59,7 @@ struct vhost_vdpa { ...@@ -59,6 +59,7 @@ struct vhost_vdpa {
int in_batch; int in_batch;
struct vdpa_iova_range range; struct vdpa_iova_range range;
u32 batch_asid; u32 batch_asid;
bool suspended;
}; };
static DEFINE_IDA(vhost_vdpa_ida); static DEFINE_IDA(vhost_vdpa_ida);
...@@ -232,6 +233,8 @@ static int _compat_vdpa_reset(struct vhost_vdpa *v) ...@@ -232,6 +233,8 @@ static int _compat_vdpa_reset(struct vhost_vdpa *v)
struct vdpa_device *vdpa = v->vdpa; struct vdpa_device *vdpa = v->vdpa;
u32 flags = 0; u32 flags = 0;
v->suspended = false;
if (v->vdev.vqs) { if (v->vdev.vqs) {
flags |= !vhost_backend_has_feature(v->vdev.vqs[0], flags |= !vhost_backend_has_feature(v->vdev.vqs[0],
VHOST_BACKEND_F_IOTLB_PERSIST) ? VHOST_BACKEND_F_IOTLB_PERSIST) ?
...@@ -590,11 +593,16 @@ static long vhost_vdpa_suspend(struct vhost_vdpa *v) ...@@ -590,11 +593,16 @@ static long vhost_vdpa_suspend(struct vhost_vdpa *v)
{ {
struct vdpa_device *vdpa = v->vdpa; struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config; const struct vdpa_config_ops *ops = vdpa->config;
int ret;
if (!ops->suspend) if (!ops->suspend)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ops->suspend(vdpa); ret = ops->suspend(vdpa);
if (!ret)
v->suspended = true;
return ret;
} }
/* After a successful return of this ioctl the device resumes processing /* After a successful return of this ioctl the device resumes processing
...@@ -605,11 +613,16 @@ static long vhost_vdpa_resume(struct vhost_vdpa *v) ...@@ -605,11 +613,16 @@ static long vhost_vdpa_resume(struct vhost_vdpa *v)
{ {
struct vdpa_device *vdpa = v->vdpa; struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config; const struct vdpa_config_ops *ops = vdpa->config;
int ret;
if (!ops->resume) if (!ops->resume)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ops->resume(vdpa); ret = ops->resume(vdpa);
if (!ret)
v->suspended = false;
return ret;
} }
static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
...@@ -690,6 +703,9 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, ...@@ -690,6 +703,9 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
switch (cmd) { switch (cmd) {
case VHOST_SET_VRING_ADDR: case VHOST_SET_VRING_ADDR:
if ((ops->get_status(vdpa) & VIRTIO_CONFIG_S_DRIVER_OK) && !v->suspended)
return -EINVAL;
if (ops->set_vq_address(vdpa, idx, if (ops->set_vq_address(vdpa, idx,
(u64)(uintptr_t)vq->desc, (u64)(uintptr_t)vq->desc,
(u64)(uintptr_t)vq->avail, (u64)(uintptr_t)vq->avail,
...@@ -698,6 +714,9 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, ...@@ -698,6 +714,9 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
break; break;
case VHOST_SET_VRING_BASE: case VHOST_SET_VRING_BASE:
if ((ops->get_status(vdpa) & VIRTIO_CONFIG_S_DRIVER_OK) && !v->suspended)
return -EINVAL;
if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) { if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) {
vq_state.packed.last_avail_idx = vq->last_avail_idx & 0x7fff; vq_state.packed.last_avail_idx = vq->last_avail_idx & 0x7fff;
vq_state.packed.last_avail_counter = !!(vq->last_avail_idx & 0x8000); vq_state.packed.last_avail_counter = !!(vq->last_avail_idx & 0x8000);
...@@ -968,7 +987,8 @@ static int vhost_vdpa_map(struct vhost_vdpa *v, struct vhost_iotlb *iotlb, ...@@ -968,7 +987,8 @@ static int vhost_vdpa_map(struct vhost_vdpa *v, struct vhost_iotlb *iotlb,
r = ops->set_map(vdpa, asid, iotlb); r = ops->set_map(vdpa, asid, iotlb);
} else { } else {
r = iommu_map(v->domain, iova, pa, size, r = iommu_map(v->domain, iova, pa, size,
perm_to_iommu_flags(perm), GFP_KERNEL); perm_to_iommu_flags(perm),
GFP_KERNEL_ACCOUNT);
} }
if (r) { if (r) {
vhost_iotlb_del_range(iotlb, iova, iova + size - 1); vhost_iotlb_del_range(iotlb, iova, iova + size - 1);
......
...@@ -119,6 +119,11 @@ struct virtio_balloon { ...@@ -119,6 +119,11 @@ struct virtio_balloon {
/* Free page reporting device */ /* Free page reporting device */
struct virtqueue *reporting_vq; struct virtqueue *reporting_vq;
struct page_reporting_dev_info pr_dev_info; struct page_reporting_dev_info pr_dev_info;
/* State for keeping the wakeup_source active while adjusting the balloon */
spinlock_t adjustment_lock;
bool adjustment_signal_pending;
bool adjustment_in_progress;
}; };
static const struct virtio_device_id id_table[] = { static const struct virtio_device_id id_table[] = {
...@@ -437,6 +442,31 @@ static void virtio_balloon_queue_free_page_work(struct virtio_balloon *vb) ...@@ -437,6 +442,31 @@ static void virtio_balloon_queue_free_page_work(struct virtio_balloon *vb)
queue_work(vb->balloon_wq, &vb->report_free_page_work); queue_work(vb->balloon_wq, &vb->report_free_page_work);
} }
static void start_update_balloon_size(struct virtio_balloon *vb)
{
unsigned long flags;
spin_lock_irqsave(&vb->adjustment_lock, flags);
vb->adjustment_signal_pending = true;
if (!vb->adjustment_in_progress) {
vb->adjustment_in_progress = true;
pm_stay_awake(vb->vdev->dev.parent);
}
spin_unlock_irqrestore(&vb->adjustment_lock, flags);
queue_work(system_freezable_wq, &vb->update_balloon_size_work);
}
static void end_update_balloon_size(struct virtio_balloon *vb)
{
spin_lock_irq(&vb->adjustment_lock);
if (!vb->adjustment_signal_pending && vb->adjustment_in_progress) {
vb->adjustment_in_progress = false;
pm_relax(vb->vdev->dev.parent);
}
spin_unlock_irq(&vb->adjustment_lock);
}
static void virtballoon_changed(struct virtio_device *vdev) static void virtballoon_changed(struct virtio_device *vdev)
{ {
struct virtio_balloon *vb = vdev->priv; struct virtio_balloon *vb = vdev->priv;
...@@ -444,8 +474,7 @@ static void virtballoon_changed(struct virtio_device *vdev) ...@@ -444,8 +474,7 @@ static void virtballoon_changed(struct virtio_device *vdev)
spin_lock_irqsave(&vb->stop_update_lock, flags); spin_lock_irqsave(&vb->stop_update_lock, flags);
if (!vb->stop_update) { if (!vb->stop_update) {
queue_work(system_freezable_wq, start_update_balloon_size(vb);
&vb->update_balloon_size_work);
virtio_balloon_queue_free_page_work(vb); virtio_balloon_queue_free_page_work(vb);
} }
spin_unlock_irqrestore(&vb->stop_update_lock, flags); spin_unlock_irqrestore(&vb->stop_update_lock, flags);
...@@ -476,19 +505,25 @@ static void update_balloon_size_func(struct work_struct *work) ...@@ -476,19 +505,25 @@ static void update_balloon_size_func(struct work_struct *work)
vb = container_of(work, struct virtio_balloon, vb = container_of(work, struct virtio_balloon,
update_balloon_size_work); update_balloon_size_work);
diff = towards_target(vb);
if (!diff) spin_lock_irq(&vb->adjustment_lock);
return; vb->adjustment_signal_pending = false;
spin_unlock_irq(&vb->adjustment_lock);
if (diff > 0) diff = towards_target(vb);
diff -= fill_balloon(vb, diff);
else if (diff) {
diff += leak_balloon(vb, -diff); if (diff > 0)
update_balloon_size(vb); diff -= fill_balloon(vb, diff);
else
diff += leak_balloon(vb, -diff);
update_balloon_size(vb);
}
if (diff) if (diff)
queue_work(system_freezable_wq, work); queue_work(system_freezable_wq, work);
else
end_update_balloon_size(vb);
} }
static int init_vqs(struct virtio_balloon *vb) static int init_vqs(struct virtio_balloon *vb)
...@@ -992,6 +1027,8 @@ static int virtballoon_probe(struct virtio_device *vdev) ...@@ -992,6 +1027,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
goto out_unregister_oom; goto out_unregister_oom;
} }
spin_lock_init(&vb->adjustment_lock);
virtio_device_ready(vdev); virtio_device_ready(vdev);
if (towards_target(vb)) if (towards_target(vb))
......
...@@ -495,8 +495,40 @@ static int virtio_pci_restore(struct device *dev) ...@@ -495,8 +495,40 @@ static int virtio_pci_restore(struct device *dev)
return virtio_device_restore(&vp_dev->vdev); return virtio_device_restore(&vp_dev->vdev);
} }
static bool vp_supports_pm_no_reset(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
u16 pmcsr;
if (!pci_dev->pm_cap)
return false;
pci_read_config_word(pci_dev, pci_dev->pm_cap + PCI_PM_CTRL, &pmcsr);
if (PCI_POSSIBLE_ERROR(pmcsr)) {
dev_err(dev, "Unable to query pmcsr");
return false;
}
return pmcsr & PCI_PM_CTRL_NO_SOFT_RESET;
}
static int virtio_pci_suspend(struct device *dev)
{
return vp_supports_pm_no_reset(dev) ? 0 : virtio_pci_freeze(dev);
}
static int virtio_pci_resume(struct device *dev)
{
return vp_supports_pm_no_reset(dev) ? 0 : virtio_pci_restore(dev);
}
static const struct dev_pm_ops virtio_pci_pm_ops = { static const struct dev_pm_ops virtio_pci_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore) .suspend = virtio_pci_suspend,
.resume = virtio_pci_resume,
.freeze = virtio_pci_freeze,
.thaw = virtio_pci_restore,
.poweroff = virtio_pci_freeze,
.restore = virtio_pci_restore,
}; };
#endif #endif
......
...@@ -1241,7 +1241,8 @@ struct mlx5_ifc_virtio_emulation_cap_bits { ...@@ -1241,7 +1241,8 @@ struct mlx5_ifc_virtio_emulation_cap_bits {
u8 reserved_at_c0[0x13]; u8 reserved_at_c0[0x13];
u8 desc_group_mkey_supported[0x1]; u8 desc_group_mkey_supported[0x1];
u8 reserved_at_d4[0xc]; u8 freeze_to_rdy_supported[0x1];
u8 reserved_at_d5[0xb];
u8 reserved_at_e0[0x20]; u8 reserved_at_e0[0x20];
......
...@@ -145,6 +145,10 @@ enum { ...@@ -145,6 +145,10 @@ enum {
MLX5_VIRTQ_MODIFY_MASK_STATE = (u64)1 << 0, MLX5_VIRTQ_MODIFY_MASK_STATE = (u64)1 << 0,
MLX5_VIRTQ_MODIFY_MASK_DIRTY_BITMAP_PARAMS = (u64)1 << 3, MLX5_VIRTQ_MODIFY_MASK_DIRTY_BITMAP_PARAMS = (u64)1 << 3,
MLX5_VIRTQ_MODIFY_MASK_DIRTY_BITMAP_DUMP_ENABLE = (u64)1 << 4, MLX5_VIRTQ_MODIFY_MASK_DIRTY_BITMAP_DUMP_ENABLE = (u64)1 << 4,
MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_ADDRS = (u64)1 << 6,
MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_AVAIL_IDX = (u64)1 << 7,
MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX = (u64)1 << 8,
MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY = (u64)1 << 11,
MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY = (u64)1 << 14, MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY = (u64)1 << 14,
}; };
......
...@@ -14,6 +14,13 @@ ...@@ -14,6 +14,13 @@
#include <linux/virtio_ids.h> #include <linux/virtio_ids.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* Feature bits */
/* guest physical address range will be indicated as shared memory region 0 */
#define VIRTIO_PMEM_F_SHMEM_REGION 0
/* shmid of the shared memory region corresponding to the pmem */
#define VIRTIO_PMEM_SHMEM_REGION_ID 0
struct virtio_pmem_config { struct virtio_pmem_config {
__le64 start; __le64 start;
__le64 size; __le64 size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment