diff mbox

[RFC,v4,20/20] intel_iommu: replay even with DSI/GLOBAL inv desc

Message ID 1484917736-32056-21-git-send-email-peterx@redhat.com
State New
Headers show

Commit Message

Peter Xu Jan. 20, 2017, 1:08 p.m. UTC
We were capturing context entry invalidations to trap IOMMU mapping
changes. This patch listens to domain/global invalidation requests too.

We need this for the sake that guest operating system might send one
domain/global invalidation instead of several PSIs in some cases. To
better survive with that, we'd better replay corresponding regions as
well for these invalidations, even if this will turn the performance
down a bit.

An example in Linux (4.10.0) Intel IOMMU driver:

    /*
     * Fallback to domain selective flush if no PSI support or the size is
     * too big.
     * PSI requires page size to be 2 ^ x, and the base address is naturally
     * aligned to the size
     */
    if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
        iommu->flush.flush_iotlb(iommu, did, 0, 0,
                        DMA_TLB_DSI_FLUSH);
    else
        iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
                        DMA_TLB_PSI_FLUSH);

If we don't have this, when above DSI FLUSH happens, we might have
unaligned mapping.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 hw/i386/intel_iommu.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
diff mbox

Patch

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index a038651..e958f53 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1196,14 +1196,33 @@  static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val)
 
 static void vtd_iotlb_global_invalidate(IntelIOMMUState *s)
 {
+    IntelIOMMUNotifierNode *node;
+
     trace_vtd_iotlb_reset("global invalidation recved");
     vtd_reset_iotlb(s);
+
+    QLIST_FOREACH(node, &s->notifiers_list, next) {
+        memory_region_iommu_replay_all(&node->vtd_as->iommu);
+    }
 }
 
 static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
 {
+    IntelIOMMUNotifierNode *node;
+    VTDContextEntry ce;
+    VTDAddressSpace *vtd_as;
+
     g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_domain,
                                 &domain_id);
+
+    QLIST_FOREACH(node, &s->notifiers_list, next) {
+        vtd_as = node->vtd_as;
+        if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
+                                      vtd_as->devfn, &ce) &&
+            domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) {
+            memory_region_iommu_replay_all(&vtd_as->iommu);
+        }
+    }
 }
 
 static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,