aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorEric Auger <eric.auger@redhat.com>2023-10-19 15:45:16 +0200
committerCédric Le Goater <clg@redhat.com>2023-11-03 09:20:31 +0100
commit30d40e39bdcb50e67f7cca7bee8bf59234c4ec12 (patch)
treefabee07059fe8d66ab287c339367ab64ad6602b3 /hw
parent09b4c3d6a2f098e64cc25aa63f388ea943990279 (diff)
downloadqemu-30d40e39bdcb50e67f7cca7bee8bf59234c4ec12.zip
qemu-30d40e39bdcb50e67f7cca7bee8bf59234c4ec12.tar.gz
qemu-30d40e39bdcb50e67f7cca7bee8bf59234c4ec12.tar.bz2
virtio-iommu: Implement set_iova_ranges() callback
The implementation populates the array of per IOMMUDevice host reserved ranges. It is forbidden to have conflicting sets of host IOVA ranges to be applied onto the same IOMMU MR (implied by different host devices). In case the callback is called after the probe request has been issues by the driver, a warning is issued. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: "Michael S. Tsirkin" <mst@redhat.com> Tested-by: Yanghang Liu <yanghliu@redhat.com> Signed-off-by: Cédric Le Goater <clg@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/virtio/virtio-iommu.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 13c3c08..15aadd6 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/iov.h"
+#include "qemu/range.h"
#include "exec/target_page.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio.h"
@@ -1155,6 +1156,71 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
return 0;
}
+/**
+ * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
+ *
+ * The function turns those into reserved ranges. Once some
+ * reserved ranges have been set, new reserved regions cannot be
+ * added outside of the original ones.
+ *
+ * @mr: IOMMU MR
+ * @iova_ranges: list of usable IOVA ranges
+ * @errp: error handle
+ */
+static int virtio_iommu_set_iova_ranges(IOMMUMemoryRegion *mr,
+ GList *iova_ranges,
+ Error **errp)
+{
+ IOMMUDevice *sdev = container_of(mr, IOMMUDevice, iommu_mr);
+ GList *current_ranges = sdev->host_resv_ranges;
+ GList *l, *tmp, *new_ranges = NULL;
+ int ret = -EINVAL;
+
+ /* check that each new resv region is included in an existing one */
+ if (sdev->host_resv_ranges) {
+ range_inverse_array(iova_ranges,
+ &new_ranges,
+ 0, UINT64_MAX);
+
+ for (tmp = new_ranges; tmp; tmp = tmp->next) {
+ Range *newr = (Range *)tmp->data;
+ bool included = false;
+
+ for (l = current_ranges; l; l = l->next) {
+ Range * r = (Range *)l->data;
+
+ if (range_contains_range(r, newr)) {
+ included = true;
+ break;
+ }
+ }
+ if (!included) {
+ goto error;
+ }
+ }
+ /* all new reserved ranges are included in existing ones */
+ ret = 0;
+ goto out;
+ }
+
+ if (sdev->probe_done) {
+ warn_report("%s: Notified about new host reserved regions after probe",
+ mr->parent_obj.name);
+ }
+
+ range_inverse_array(iova_ranges,
+ &sdev->host_resv_ranges,
+ 0, UINT64_MAX);
+
+ return 0;
+error:
+ error_setg(errp, "IOMMU mr=%s Conflicting host reserved ranges set!",
+ mr->parent_obj.name);
+out:
+ g_list_free_full(new_ranges, g_free);
+ return ret;
+}
+
static void virtio_iommu_system_reset(void *opaque)
{
VirtIOIOMMU *s = opaque;
@@ -1450,6 +1516,7 @@ static void virtio_iommu_memory_region_class_init(ObjectClass *klass,
imrc->replay = virtio_iommu_replay;
imrc->notify_flag_changed = virtio_iommu_notify_flag_changed;
imrc->iommu_set_page_size_mask = virtio_iommu_set_page_size_mask;
+ imrc->iommu_set_iova_ranges = virtio_iommu_set_iova_ranges;
}
static const TypeInfo virtio_iommu_info = {