@@ -685,12 +685,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);
}
@@ -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);
+ }
}
}
@@ -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);
@@ -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));
@@ -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;
}
@@ -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);
}
}
@@ -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;
}
@@ -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)
@@ -606,11 +606,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);
@@ -704,7 +704,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);
@@ -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);
@@ -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
@@ -1862,7 +1862,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));
@@ -1898,7 +1900,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
@@ -1932,42 +1934,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);
}
}
}
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.auger@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(-)