summaryrefslogtreecommitdiff
path: root/memory.c
diff options
context:
space:
mode:
authorPeter Xu <peterx@redhat.com>2016-09-23 13:02:26 +0800
committerPaolo Bonzini <pbonzini@redhat.com>2016-09-27 08:59:16 +0200
commitcdb3081269347fd9271fd1b7a9df312e2953bdd9 (patch)
treeb9eb019b24ce2ebd5c849f513975960ed4c2abfd /memory.c
parent7cfdc02dae0d2ff58c897496cfdbbafc0eda0f3f (diff)
downloadqemu-cdb3081269347fd9271fd1b7a9df312e2953bdd9.tar.gz
memory: introduce IOMMUNotifier and its caps
IOMMU Notifier list is used for notifying IO address mapping changes. Currently VFIO is the only user. However it is possible that future consumer like vhost would like to only listen to part of its notifications (e.g., cache invalidations). This patch introduced IOMMUNotifier and IOMMUNotfierFlag bits for a finer grained control of it. IOMMUNotifier contains a bitfield for the notify consumer describing what kind of notification it is interested in. Currently two kinds of notifications are defined: - IOMMU_NOTIFIER_MAP: for newly mapped entries (additions) - IOMMU_NOTIFIER_UNMAP: for entries to be removed (cache invalidates) When registering the IOMMU notifier, we need to specify one or multiple types of messages to listen to. When notifications are triggered, its type will be checked against the notifier's type bits, and only notifiers with registered bits will be notified. (For any IOMMU implementation, an in-place mapping change should be notified with an UNMAP followed by a MAP.) Signed-off-by: Peter Xu <peterx@redhat.com> Message-Id: <1474606948-14391-2-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'memory.c')
-rw-r--r--memory.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/memory.c b/memory.c
index 1a1baf574c..69d9d9ab7f 100644
--- a/memory.c
+++ b/memory.c
@@ -1413,7 +1413,7 @@ void memory_region_init_iommu(MemoryRegion *mr,
memory_region_init(mr, owner, name, size);
mr->iommu_ops = ops,
mr->terminates = true; /* then re-forwards */
- notifier_list_init(&mr->iommu_notify);
+ QLIST_INIT(&mr->iommu_notify);
}
static void memory_region_finalize(Object *obj)
@@ -1508,13 +1508,16 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client)
return memory_region_get_dirty_log_mask(mr) & (1 << client);
}
-void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n)
+void memory_region_register_iommu_notifier(MemoryRegion *mr,
+ IOMMUNotifier *n)
{
+ /* We need to register for at least one bitfield */
+ assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
if (mr->iommu_ops->notify_started &&
- QLIST_EMPTY(&mr->iommu_notify.notifiers)) {
+ QLIST_EMPTY(&mr->iommu_notify)) {
mr->iommu_ops->notify_started(mr);
}
- notifier_list_add(&mr->iommu_notify, n);
+ QLIST_INSERT_HEAD(&mr->iommu_notify, n, node);
}
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr)
@@ -1526,7 +1529,8 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr)
return TARGET_PAGE_SIZE;
}
-void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write)
+void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n,
+ bool is_write)
{
hwaddr addr, granularity;
IOMMUTLBEntry iotlb;
@@ -1547,11 +1551,12 @@ void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write)
}
}
-void memory_region_unregister_iommu_notifier(MemoryRegion *mr, Notifier *n)
+void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
+ IOMMUNotifier *n)
{
- notifier_remove(n);
+ QLIST_REMOVE(n, node);
if (mr->iommu_ops->notify_stopped &&
- QLIST_EMPTY(&mr->iommu_notify.notifiers)) {
+ QLIST_EMPTY(&mr->iommu_notify)) {
mr->iommu_ops->notify_stopped(mr);
}
}
@@ -1559,8 +1564,22 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, Notifier *n)
void memory_region_notify_iommu(MemoryRegion *mr,
IOMMUTLBEntry entry)
{
+ IOMMUNotifier *iommu_notifier;
+ IOMMUNotifierFlag request_flags;
+
assert(memory_region_is_iommu(mr));
- notifier_list_notify(&mr->iommu_notify, &entry);
+
+ if (entry.perm & IOMMU_RW) {
+ request_flags = IOMMU_NOTIFIER_MAP;
+ } else {
+ request_flags = IOMMU_NOTIFIER_UNMAP;
+ }
+
+ QLIST_FOREACH(iommu_notifier, &mr->iommu_notify, node) {
+ if (iommu_notifier->notifier_flags & request_flags) {
+ iommu_notifier->notify(iommu_notifier, &entry);
+ }
+ }
}
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)