On Mon, Jan 16, 2017 at 02:30:20PM +0800, Jason Wang wrote: > > > On 2017年01月13日 11:06, Peter Xu wrote: > >This patch is based on Aviv Ben-David (<bd.a...@gmail.com>)'s patch > >upstream: > > > > "IOMMU: enable intel_iommu map and unmap notifiers" > > https://lists.gnu.org/archive/html/qemu-devel/2016-11/msg01453.html > > > >However I removed/fixed some content, and added my own codes. > > > >Instead of translate() every page for iotlb invalidations (which is > >slower), we walk the pages when needed and notify in a hook function. > > > >This patch enables vfio devices for VT-d emulation. > > > >Signed-off-by: Peter Xu <pet...@redhat.com> > >--- > > hw/i386/intel_iommu.c | 68 > > +++++++++++++++++++++++++++++++++++++------ > > include/hw/i386/intel_iommu.h | 8 +++++ > > 2 files changed, 67 insertions(+), 9 deletions(-) > > > >diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c > >index 2596f11..104200b 100644 > >--- a/hw/i386/intel_iommu.c > >+++ b/hw/i386/intel_iommu.c > >@@ -839,7 +839,8 @@ next: > > * @private: private data for the hook function > > */ > > static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end, > >- vtd_page_walk_hook hook_fn, void *private) > >+ vtd_page_walk_hook hook_fn, void *private, > >+ bool notify_unmap) > > { > > dma_addr_t addr = vtd_get_slpt_base_from_context(ce); > > uint32_t level = vtd_get_level_from_context_entry(ce); > >@@ -858,7 +859,7 @@ static int vtd_page_walk(VTDContextEntry *ce, uint64_t > >start, uint64_t end, > > trace_vtd_page_walk(ce->hi, ce->lo, start, end); > > return vtd_page_walk_level(addr, start, end, hook_fn, private, > >- level, true, true, NULL, false); > >+ level, true, true, NULL, notify_unmap); > > } > > /* Map a device to its corresponding domain (context-entry) */ > >@@ -1212,6 +1213,34 @@ static void > >vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) > > &domain_id); > > } > >+static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry, > >+ void *private) > >+{ > >+ memory_region_notify_iommu((MemoryRegion *)private, *entry); > >+ return 0; > >+} > >+ > >+static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, > >+ uint16_t domain_id, hwaddr addr, > >+ uint8_t am) > >+{ > >+ IntelIOMMUNotifierNode *node; > >+ VTDContextEntry ce; > >+ int ret; > >+ > >+ QLIST_FOREACH(node, &(s->notifiers_list), next) { > >+ VTDAddressSpace *vtd_as = node->vtd_as; > >+ ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), > >+ vtd_as->devfn, &ce); > >+ if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { > >+ vtd_page_walk(&ce, addr, addr + (1 << am) * VTD_PAGE_SIZE, > >+ vtd_page_invalidate_notify_hook, > >+ (void *)&vtd_as->iommu, true); > >+ } > >+ } > >+} > >+ > >+ > > static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t > > domain_id, > > hwaddr addr, uint8_t am) > > { > >@@ -1222,6 +1251,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState > >*s, uint16_t domain_id, > > info.addr = addr; > > info.mask = ~((1 << am) - 1); > > g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info); > >+ vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am); > > Is the case of GLOBAL or DSI flush missed, or we don't care it at all?
IMHO we don't. For device assignment, since we are having CM=1 here, we should have explicit page invalidations even if guest sends global/domain invalidations. Thanks, -- peterx