Skip to content

Commit

Permalink
vhost: register and change IOMMU flag depending on Device-TLB state
Browse files Browse the repository at this point in the history
The guest can disable or never enable Device-TLB. In these cases,
it can't be used even if enabled in QEMU. So, check Device-TLB state
before registering IOMMU notifier and select unmap flag depending on
that. Also, implement a way to change IOMMU notifier flag if Device-TLB
state is changed.

Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2001312
Signed-off-by: Viktor Prutyanov <viktor@daynix.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20230626091258.24453-2-viktor@daynix.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit ee071f6)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
  • Loading branch information
viktor-prutyanov authored and Michael Tokarev committed Jul 25, 2023
1 parent 93c257a commit 9a1e32d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 12 deletions.
4 changes: 4 additions & 0 deletions hw/virtio/vhost-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
void vhost_user_cleanup(VhostUserState *user)
{
}

void vhost_toggle_device_iotlb(VirtIODevice *vdev)
{
}
38 changes: 26 additions & 12 deletions hw/virtio/vhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,6 @@ static void vhost_iommu_region_add(MemoryListener *listener,
Int128 end;
int iommu_idx;
IOMMUMemoryRegion *iommu_mr;
int ret;

if (!memory_region_is_iommu(section->mr)) {
return;
Expand All @@ -796,24 +795,18 @@ static void vhost_iommu_region_add(MemoryListener *listener,
iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr,
MEMTXATTRS_UNSPECIFIED);
iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify,
IOMMU_NOTIFIER_DEVIOTLB_UNMAP,
dev->vdev->device_iotlb_enabled ?
IOMMU_NOTIFIER_DEVIOTLB_UNMAP :
IOMMU_NOTIFIER_UNMAP,
section->offset_within_region,
int128_get64(end),
iommu_idx);
iommu->mr = section->mr;
iommu->iommu_offset = section->offset_within_address_space -
section->offset_within_region;
iommu->hdev = dev;
ret = memory_region_register_iommu_notifier(section->mr, &iommu->n, NULL);
if (ret) {
/*
* Some vIOMMUs do not support dev-iotlb yet. If so, try to use the
* UNMAP legacy message
*/
iommu->n.notifier_flags = IOMMU_NOTIFIER_UNMAP;
memory_region_register_iommu_notifier(section->mr, &iommu->n,
&error_fatal);
}
memory_region_register_iommu_notifier(section->mr, &iommu->n,
&error_fatal);
QLIST_INSERT_HEAD(&dev->iommu_list, iommu, iommu_next);
/* TODO: can replay help performance here? */
}
Expand Down Expand Up @@ -841,6 +834,27 @@ static void vhost_iommu_region_del(MemoryListener *listener,
}
}

void vhost_toggle_device_iotlb(VirtIODevice *vdev)
{
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
struct vhost_dev *dev;
struct vhost_iommu *iommu;

if (vdev->vhost_started) {
dev = vdc->get_vhost(vdev);
} else {
return;
}

QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) {
memory_region_unregister_iommu_notifier(iommu->mr, &iommu->n);
iommu->n.notifier_flags = vdev->device_iotlb_enabled ?
IOMMU_NOTIFIER_DEVIOTLB_UNMAP : IOMMU_NOTIFIER_UNMAP;
memory_region_register_iommu_notifier(iommu->mr, &iommu->n,
&error_fatal);
}
}

static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
struct vhost_virtqueue *vq,
unsigned idx, bool enable_log)
Expand Down
1 change: 1 addition & 0 deletions include/hw/virtio/vhost.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ bool vhost_has_free_slot(void);
int vhost_net_set_backend(struct vhost_dev *hdev,
struct vhost_vring_file *file);

void vhost_toggle_device_iotlb(VirtIODevice *vdev);
int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write);

int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev,
Expand Down

0 comments on commit 9a1e32d

Please sign in to comment.