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>
---
hw/virtio/vhost.c | 38 ++++++++++++++++++++++++++------------
include/hw/virtio/vhost.h | 1 +
2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 23da579ce2..e48507b5a1 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -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;
@@ -796,7 +795,9 @@ 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);
@@ -804,16 +805,8 @@ static void vhost_iommu_region_add(MemoryListener *listener,
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? */
}
@@ -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)
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index f7f10c8fb7..6a173cb9fa 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -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,
--
2.21.0
On Thu, May 25, 2023 at 8:58 PM Viktor Prutyanov <viktor@daynix.com> wrote: > > 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> Thanks > --- > hw/virtio/vhost.c | 38 ++++++++++++++++++++++++++------------ > include/hw/virtio/vhost.h | 1 + > 2 files changed, 27 insertions(+), 12 deletions(-) > > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c > index 23da579ce2..e48507b5a1 100644 > --- a/hw/virtio/vhost.c > +++ b/hw/virtio/vhost.c > @@ -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; > @@ -796,7 +795,9 @@ 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); > @@ -804,16 +805,8 @@ static void vhost_iommu_region_add(MemoryListener *listener, > 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? */ > } > @@ -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) > diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h > index f7f10c8fb7..6a173cb9fa 100644 > --- a/include/hw/virtio/vhost.h > +++ b/include/hw/virtio/vhost.h > @@ -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, > -- > 2.21.0 >
© 2016 - 2024 Red Hat, Inc.