Current IOMMUNotifiers dedicate to IOTLB related notifications, ie. MAP/UNMAP. We plan to introduce new types of notifiers, for instance to notify vIOMMU configuration changes. Those new notifiers may not be characterized by any associated address space range.
So let's create a specialized IOMMUIOLTBNotifier datatype. The base IOMMUNotifier will be able to encapsulate either of the notifier types, including looming IOMMUConfigNotifier. We also rename: - IOMMU_NOTIFIER_* into IOMMU_NOTIFIER_IOTLB_* - *_notify_* into *iotlb_notify_* All calling sites are updated. Signed-off-by: Eric Auger <eric.au...@redhat.com> --- exec.c | 12 ++++----- hw/arm/smmu-common.c | 10 ++++--- hw/arm/smmuv3.c | 8 +++--- hw/i386/amd_iommu.c | 2 +- hw/i386/intel_iommu.c | 25 ++++++++++-------- hw/misc/tz-mpc.c | 8 +++--- hw/ppc/spapr_iommu.c | 2 +- hw/s390x/s390-pci-inst.c | 4 +-- hw/vfio/common.c | 13 ++++----- hw/virtio/vhost.c | 14 +++++----- include/exec/memory.h | 57 +++++++++++++++++++++++++--------------- memory.c | 32 ++++++++++++---------- 12 files changed, 107 insertions(+), 80 deletions(-) diff --git a/exec.c b/exec.c index 4e734770c2..ed4c5149ac 100644 --- a/exec.c +++ b/exec.c @@ -686,12 +686,12 @@ static void tcg_register_iommu_notifier(CPUState *cpu, * just register interest in the whole thing, on the assumption * that iommu reconfiguration will be rare. */ - iommu_notifier_init(¬ifier->n, - tcg_iommu_unmap_notify, - IOMMU_NOTIFIER_UNMAP, - 0, - HWADDR_MAX, - iommu_idx); + iommu_iotlb_notifier_init(¬ifier->n, + tcg_iommu_unmap_notify, + IOMMU_NOTIFIER_IOTLB_UNMAP, + 0, + HWADDR_MAX, + iommu_idx); memory_region_register_iommu_notifier(notifier->mr, ¬ifier->n); } diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index e94be6db6c..ee81038fc0 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -391,11 +391,11 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n) IOMMUTLBEntry entry; entry.target_as = &address_space_memory; - entry.iova = n->start; + entry.iova = n->iotlb_notifier.start; entry.perm = IOMMU_NONE; - entry.addr_mask = n->end - n->start; + entry.addr_mask = n->iotlb_notifier.end - n->iotlb_notifier.start; - memory_region_notify_one(n, &entry); + memory_region_iotlb_notify_one(n, &entry); } /* Unmap all notifiers attached to @mr */ @@ -405,7 +405,9 @@ inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr) trace_smmu_inv_notifiers_mr(mr->parent_obj.name); IOMMU_NOTIFIER_FOREACH(n, mr) { - smmu_unmap_notifier_range(n); + if (n->notifier_flags & IOMMU_NOTIFIER_IOTLB_UNMAP) { + smmu_unmap_notifier_range(n); + } } } diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 761d722395..1744874e72 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -822,7 +822,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, entry.addr_mask = (1 << tt->granule_sz) - 1; entry.perm = IOMMU_NONE; - memory_region_notify_one(n, &entry); + memory_region_iotlb_notify_one(n, &entry); } /* invalidate an asid/iova tuple in all mr's */ @@ -837,7 +837,9 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova) trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova); IOMMU_NOTIFIER_FOREACH(n, mr) { - smmuv3_notify_iova(mr, n, asid, iova); + if (n->notifier_flags & IOMMU_NOTIFIER_IOTLB_UNMAP) { + smmuv3_notify_iova(mr, n, asid, iova); + } } } } @@ -1473,7 +1475,7 @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, SMMUv3State *s3 = sdev->smmu; SMMUState *s = &(s3->smmu_state); - if (new & IOMMU_NOTIFIER_MAP) { + if (new & IOMMU_NOTIFIER_IOTLB_MAP) { int bus_num = pci_bus_num(sdev->bus); PCIDevice *pcidev = pci_find_device(sdev->bus, bus_num, sdev->devfn); diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 4a4e2c7fd4..7479e74a5c 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1470,7 +1470,7 @@ static void amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, { AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); - if (new & IOMMU_NOTIFIER_MAP) { + if (new & IOMMU_NOTIFIER_IOTLB_MAP) { error_report("device %02x.%02x.%x requires iommu notifier which is not " "currently supported", as->bus_num, PCI_SLOT(as->devfn), PCI_FUNC(as->devfn)); diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 44b1231157..dff90ed3fa 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -174,7 +174,7 @@ static void vtd_update_scalable_state(IntelIOMMUState *s) /* Whether the address space needs to notify new mappings */ static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as) { - return as->notifier_flags & IOMMU_NOTIFIER_MAP; + return as->notifier_flags & IOMMU_NOTIFIER_IOTLB_MAP; } /* GHashTable functions */ @@ -1361,7 +1361,7 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num, static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry, void *private) { - memory_region_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry); + memory_region_iotlb_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry); return 0; } @@ -1928,7 +1928,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, .addr_mask = size - 1, .perm = IOMMU_NONE, }; - memory_region_notify_iommu(&vtd_as->iommu, 0, entry); + memory_region_iotlb_notify_iommu(&vtd_as->iommu, 0, entry); } } } @@ -2393,7 +2393,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, entry.iova = addr; entry.perm = IOMMU_NONE; entry.translated_addr = 0; - memory_region_notify_iommu(&vtd_dev_as->iommu, 0, entry); + memory_region_iotlb_notify_iommu(&vtd_dev_as->iommu, 0, entry); done: return true; @@ -2925,7 +2925,7 @@ static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); IntelIOMMUState *s = vtd_as->iommu_state; - if (!s->caching_mode && new & IOMMU_NOTIFIER_MAP) { + if (!s->caching_mode && new & IOMMU_NOTIFIER_IOTLB_MAP) { error_report("We need to set caching-mode=on for intel-iommu to enable " "device assignment with IOMMU protection."); exit(1); @@ -3368,8 +3368,9 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) { IOMMUTLBEntry entry; hwaddr size; - hwaddr start = n->start; - hwaddr end = n->end; + + hwaddr start = n->iotlb_notifier.start; + hwaddr end = n->iotlb_notifier.end; IntelIOMMUState *s = as->iommu_state; DMAMap map; @@ -3405,7 +3406,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) entry.target_as = &address_space_memory; /* Adjust iova for the size */ - entry.iova = n->start & ~(size - 1); + entry.iova = n->iotlb_notifier.start & ~(size - 1); /* This field is meaningless for unmap */ entry.translated_addr = 0; entry.perm = IOMMU_NONE; @@ -3420,7 +3421,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) map.size = entry.addr_mask; iova_tree_remove(as->iova_tree, &map); - memory_region_notify_one(n, &entry); + memory_region_iotlb_notify_one(n, &entry); } static void vtd_address_space_unmap_all(IntelIOMMUState *s) @@ -3430,7 +3431,9 @@ static void vtd_address_space_unmap_all(IntelIOMMUState *s) QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) { - vtd_address_space_unmap(vtd_as, n); + if (n->notifier_flags & IOMMU_NOTIFIER_IOTLB_UNMAP) { + vtd_address_space_unmap(vtd_as, n); + } } } } @@ -3443,7 +3446,7 @@ static void vtd_address_space_refresh_all(IntelIOMMUState *s) static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) { - memory_region_notify_one((IOMMUNotifier *)private, entry); + memory_region_iotlb_notify_one((IOMMUNotifier *)private, entry); return 0; } diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c index 9a84be75ed..f735d60e0f 100644 --- a/hw/misc/tz-mpc.c +++ b/hw/misc/tz-mpc.c @@ -100,8 +100,8 @@ static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx, entry.translated_addr = addr; entry.perm = IOMMU_NONE; - memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); - memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); + memory_region_iotlb_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); + memory_region_iotlb_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); entry.perm = IOMMU_RW; if (block_is_ns) { @@ -109,13 +109,13 @@ static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx, } else { entry.target_as = &s->downstream_as; } - memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); + memory_region_iotlb_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); if (block_is_ns) { entry.target_as = &s->downstream_as; } else { entry.target_as = &s->blocked_io_as; } - memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); + memory_region_iotlb_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); } } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 5aff4d5a05..91da0dfb9c 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -459,7 +459,7 @@ static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba, entry.translated_addr = tce & page_mask; entry.addr_mask = ~page_mask; entry.perm = spapr_tce_iommu_access_flags(tce); - memory_region_notify_iommu(&tcet->iommu, 0, entry); + memory_region_iotlb_notify_iommu(&tcet->iommu, 0, entry); return H_SUCCESS; } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index be2896232d..63bb23accd 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -594,7 +594,7 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry) } notify.perm = IOMMU_NONE; - memory_region_notify_iommu(&iommu->iommu_mr, 0, notify); + memory_region_iotlb_notify_iommu(&iommu->iommu_mr, 0, notify); notify.perm = entry->perm; } @@ -606,7 +606,7 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry) g_hash_table_replace(iommu->iotlb, &cache->iova, cache); } - memory_region_notify_iommu(&iommu->iommu_mr, 0, notify); + memory_region_iotlb_notify_iommu(&iommu->iommu_mr, 0, notify); } int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 99ade21056..4183772618 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -623,11 +623,11 @@ static void vfio_listener_region_add(MemoryListener *listener, llend = int128_sub(llend, int128_one()); iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr, MEMTXATTRS_UNSPECIFIED); - iommu_notifier_init(&giommu->n, vfio_iommu_map_notify, - IOMMU_NOTIFIER_ALL, - section->offset_within_region, - int128_get64(llend), - iommu_idx); + iommu_iotlb_notifier_init(&giommu->n, vfio_iommu_map_notify, + IOMMU_NOTIFIER_IOTLB_ALL, + section->offset_within_region, + int128_get64(llend), + iommu_idx); QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); memory_region_register_iommu_notifier(section->mr, &giommu->n); @@ -721,7 +721,8 @@ static void vfio_listener_region_del(MemoryListener *listener, QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { if (MEMORY_REGION(giommu->iommu) == section->mr && - giommu->n.start == section->offset_within_region) { + is_iommu_iotlb_notifier(&giommu->n) && + giommu->n.iotlb_notifier.start == section->offset_within_region) { memory_region_unregister_iommu_notifier(section->mr, &giommu->n); QLIST_REMOVE(giommu, giommu_next); diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 7f61018f2a..263a45d05b 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -677,11 +677,11 @@ static void vhost_iommu_region_add(MemoryListener *listener, end = int128_sub(end, int128_one()); iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr, MEMTXATTRS_UNSPECIFIED); - iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify, - IOMMU_NOTIFIER_UNMAP, - section->offset_within_region, - int128_get64(end), - iommu_idx); + iommu_iotlb_notifier_init(&iommu->n, vhost_iommu_unmap_notify, + IOMMU_NOTIFIER_IOTLB_UNMAP, + section->offset_within_region, + int128_get64(end), + iommu_idx); iommu->mr = section->mr; iommu->iommu_offset = section->offset_within_address_space - section->offset_within_region; @@ -703,8 +703,8 @@ static void vhost_iommu_region_del(MemoryListener *listener, } QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) { - if (iommu->mr == section->mr && - iommu->n.start == section->offset_within_region) { + if (iommu->mr == section->mr && is_iommu_iotlb_notifier(&iommu->n) && + iommu->n.iotlb_notifier.start == section->offset_within_region) { memory_region_unregister_iommu_notifier(iommu->mr, &iommu->n); QLIST_REMOVE(iommu, iommu_next); diff --git a/include/exec/memory.h b/include/exec/memory.h index 146a6096da..42d10b29ef 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -81,23 +81,29 @@ struct IOMMUTLBEntry { typedef enum { IOMMU_NOTIFIER_NONE = 0, /* Notify cache invalidations */ - IOMMU_NOTIFIER_UNMAP = 0x1, + IOMMU_NOTIFIER_IOTLB_UNMAP = 0x1, /* Notify entry changes (newly created entries) */ - IOMMU_NOTIFIER_MAP = 0x2, + IOMMU_NOTIFIER_IOTLB_MAP = 0x2, } IOMMUNotifierFlag; -#define IOMMU_NOTIFIER_ALL (IOMMU_NOTIFIER_MAP | IOMMU_NOTIFIER_UNMAP) +#define IOMMU_NOTIFIER_IOTLB_ALL (IOMMU_NOTIFIER_IOTLB_MAP | IOMMU_NOTIFIER_IOTLB_UNMAP) struct IOMMUNotifier; typedef void (*IOMMUNotify)(struct IOMMUNotifier *notifier, IOMMUTLBEntry *data); -struct IOMMUNotifier { +typedef struct IOMMUIOLTBNotifier { IOMMUNotify notify; - IOMMUNotifierFlag notifier_flags; /* Notify for address space range start <= addr <= end */ hwaddr start; hwaddr end; +} IOMMUIOLTBNotifier; + +struct IOMMUNotifier { + IOMMUNotifierFlag notifier_flags; + union { + IOMMUIOLTBNotifier iotlb_notifier; + }; int iommu_idx; QLIST_ENTRY(IOMMUNotifier) node; }; @@ -126,15 +132,18 @@ typedef struct IOMMUNotifier IOMMUNotifier; /* RAM is a persistent kind memory */ #define RAM_PMEM (1 << 5) -static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, - IOMMUNotifierFlag flags, - hwaddr start, hwaddr end, - int iommu_idx) +static inline void iommu_iotlb_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, + IOMMUNotifierFlag flags, + hwaddr start, hwaddr end, + int iommu_idx) { - n->notify = fn; + assert(flags & IOMMU_NOTIFIER_IOTLB_MAP || + flags & IOMMU_NOTIFIER_IOTLB_UNMAP); + assert(start < end); n->notifier_flags = flags; - n->start = start; - n->end = end; + n->iotlb_notifier.notify = fn; + n->iotlb_notifier.start = start; + n->iotlb_notifier.end = end; n->iommu_idx = iommu_idx; } @@ -633,6 +642,11 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, uint64_t length, void *host), Error **errp); + +static inline bool is_iommu_iotlb_notifier(IOMMUNotifier *n) +{ + return n->notifier_flags & IOMMU_NOTIFIER_IOTLB_ALL; +} #ifdef CONFIG_POSIX /** @@ -1018,7 +1032,8 @@ static inline IOMMUMemoryRegionClass *memory_region_get_iommu_class_nocheck( uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr); /** - * memory_region_notify_iommu: notify a change in an IOMMU translation entry. + * memory_region_iotlb_notify_iommu: notify a change in an IOMMU translation + * entry. * * The notification type will be decided by entry.perm bits: * @@ -1035,15 +1050,15 @@ uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr); * replaces all old entries for the same virtual I/O address range. * Deleted entries have .@perm == 0. */ -void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - int iommu_idx, - IOMMUTLBEntry entry); +void memory_region_iotlb_notify_iommu(IOMMUMemoryRegion *iommu_mr, + int iommu_idx, + IOMMUTLBEntry entry); /** - * memory_region_notify_one: notify a change in an IOMMU translation - * entry to a single notifier + * memory_region_iotlb_notify_one: notify a change in an IOMMU translation + * entry to a single notifier * - * This works just like memory_region_notify_iommu(), but it only + * This works just like memory_region_iotlb_notify_iommu(), but it only * notifies a specific notifier, not all of them. * * @notifier: the notifier to be notified @@ -1051,8 +1066,8 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, * replaces all old entries for the same virtual I/O address range. * Deleted entries have .@perm == 0. */ -void memory_region_notify_one(IOMMUNotifier *notifier, - IOMMUTLBEntry *entry); +void memory_region_iotlb_notify_one(IOMMUNotifier *notifier, + IOMMUTLBEntry *entry); /** * memory_region_register_iommu_notifier: register a notifier for changes to diff --git a/memory.c b/memory.c index 3071c4bdad..924396a3ce 100644 --- a/memory.c +++ b/memory.c @@ -1863,7 +1863,9 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, /* We need to register for at least one bitfield */ iommu_mr = IOMMU_MEMORY_REGION(mr); assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); - assert(n->start <= n->end); + if (is_iommu_iotlb_notifier(n)) { + assert(n->iotlb_notifier.start <= n->iotlb_notifier.end); + } assert(n->iommu_idx >= 0 && n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr)); @@ -1899,7 +1901,7 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) for (addr = 0; addr < memory_region_size(mr); addr += granularity) { iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx); if (iotlb.perm != IOMMU_NONE) { - n->notify(n, &iotlb); + n->iotlb_notifier.notify(n, &iotlb); } /* if (2^64 - MR size) < granularity, it's possible to get an @@ -1933,42 +1935,44 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, memory_region_update_iommu_notify_flags(iommu_mr); } -void memory_region_notify_one(IOMMUNotifier *notifier, - IOMMUTLBEntry *entry) +void memory_region_iotlb_notify_one(IOMMUNotifier *notifier, + IOMMUTLBEntry *entry) { IOMMUNotifierFlag request_flags; + assert(is_iommu_iotlb_notifier(notifier)); /* * Skip the notification if the notification does not overlap * with registered range. */ - if (notifier->start > entry->iova + entry->addr_mask || - notifier->end < entry->iova) { + if (notifier->iotlb_notifier.start > entry->iova + entry->addr_mask || + notifier->iotlb_notifier.end < entry->iova) { return; } if (entry->perm & IOMMU_RW) { - request_flags = IOMMU_NOTIFIER_MAP; + request_flags = IOMMU_NOTIFIER_IOTLB_MAP; } else { - request_flags = IOMMU_NOTIFIER_UNMAP; + request_flags = IOMMU_NOTIFIER_IOTLB_UNMAP; } if (notifier->notifier_flags & request_flags) { - notifier->notify(notifier, entry); + notifier->iotlb_notifier.notify(notifier, entry); } } -void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - int iommu_idx, - IOMMUTLBEntry entry) +void memory_region_iotlb_notify_iommu(IOMMUMemoryRegion *iommu_mr, + int iommu_idx, + IOMMUTLBEntry entry) { IOMMUNotifier *iommu_notifier; assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr))); IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) { - if (iommu_notifier->iommu_idx == iommu_idx) { - memory_region_notify_one(iommu_notifier, &entry); + if (iommu_notifier->iommu_idx == iommu_idx && + is_iommu_iotlb_notifier(iommu_notifier)) { + memory_region_iotlb_notify_one(iommu_notifier, &entry); } } } -- 2.20.1