iommu-notifier are called when a device is attached or detached to as address-space. This is needed for VFIO.
Signed-off-by: Bharat Bhushan <bbhush...@marvell.com> --- hw/virtio/virtio-iommu.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index bd464d4fb3..88849aa7b9 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -49,6 +49,7 @@ typedef struct VirtIOIOMMUEndpoint { uint32_t id; VirtIOIOMMUDomain *domain; QLIST_ENTRY(VirtIOIOMMUEndpoint) next; + VirtIOIOMMU *viommu; } VirtIOIOMMUEndpoint; typedef struct VirtIOIOMMUInterval { @@ -155,11 +156,48 @@ static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr iova, memory_region_notify_iommu(mr, 0, entry); } +static gboolean virtio_iommu_mapping_unmap(gpointer key, gpointer value, + gpointer data) +{ + VirtIOIOMMUInterval *interval = (VirtIOIOMMUInterval *) key; + IOMMUMemoryRegion *mr = (IOMMUMemoryRegion *) data; + + virtio_iommu_notify_unmap(mr, interval->low, + interval->high - interval->low + 1); + + return false; +} + +static gboolean virtio_iommu_mapping_map(gpointer key, gpointer value, + gpointer data) +{ + VirtIOIOMMUMapping *mapping = (VirtIOIOMMUMapping *) value; + VirtIOIOMMUInterval *interval = (VirtIOIOMMUInterval *) key; + IOMMUMemoryRegion *mr = (IOMMUMemoryRegion *) data; + + virtio_iommu_notify_map(mr, interval->low, mapping->phys_addr, + interval->high - interval->low + 1); + + return false; +} + static void virtio_iommu_detach_endpoint_from_domain(VirtIOIOMMUEndpoint *ep) { + VirtIOIOMMU *s = ep->viommu; + VirtIOIOMMUDomain *domain = ep->domain; + IOMMUDevice *sdev; + if (!ep->domain) { return; } + + QLIST_FOREACH(sdev, &s->notifiers_list, next) { + if (ep->id == sdev->devfn) { + g_tree_foreach(domain->mappings, virtio_iommu_mapping_unmap, + &sdev->iommu_mr); + } + } + QLIST_REMOVE(ep, next); ep->domain = NULL; } @@ -178,6 +216,7 @@ static VirtIOIOMMUEndpoint *virtio_iommu_get_endpoint(VirtIOIOMMU *s, } ep = g_malloc0(sizeof(*ep)); ep->id = ep_id; + ep->viommu = s; trace_virtio_iommu_get_endpoint(ep_id); g_tree_insert(s->endpoints, GUINT_TO_POINTER(ep_id), ep); return ep; @@ -274,6 +313,7 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, uint32_t ep_id = le32_to_cpu(req->endpoint); VirtIOIOMMUDomain *domain; VirtIOIOMMUEndpoint *ep; + IOMMUDevice *sdev; trace_virtio_iommu_attach(domain_id, ep_id); @@ -299,6 +339,14 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, ep->domain = domain; + /* Replay domain mappings on the associated memory region */ + QLIST_FOREACH(sdev, &s->notifiers_list, next) { + if (ep_id == sdev->devfn) { + g_tree_foreach(domain->mappings, virtio_iommu_mapping_map, + &sdev->iommu_mr); + } + } + return VIRTIO_IOMMU_S_OK; } @@ -872,6 +920,7 @@ static gboolean reconstruct_endpoints(gpointer key, gpointer value, QLIST_FOREACH(iter, &d->endpoint_list, next) { iter->domain = d; + iter->viommu = s; g_tree_insert(s->endpoints, GUINT_TO_POINTER(iter->id), iter); } return false; /* continue the domain traversal */ -- 2.17.1