memory: introduce memory_region_notify_one()

Generalizing the notify logic in memory_region_notify_iommu() into a
single function. This can be further used in customized replay()
functions for IOMMUs.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: \"Michael S. Tsirkin\" <mst@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <1491562755-23867-5-git-send-email-peterx@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
This commit is contained in:
Peter Xu 2017-04-07 18:59:10 +08:00 committed by Eduardo Habkost
parent de472e4a92
commit bd2bfa4c52
2 changed files with 39 additions and 16 deletions

View file

@ -687,6 +687,21 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
void memory_region_notify_iommu(MemoryRegion *mr,
IOMMUTLBEntry entry);
/**
* memory_region_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
* notifies a specific notifier, not all of them.
*
* @notifier: the notifier to be notified
* @entry: the new entry in the IOMMU translation table. The entry
* 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);
/**
* memory_region_register_iommu_notifier: register a notifier for changes to
* IOMMU translation entries.

View file

@ -1662,32 +1662,40 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
memory_region_update_iommu_notify_flags(mr);
}
void memory_region_notify_iommu(MemoryRegion *mr,
IOMMUTLBEntry entry)
void memory_region_notify_one(IOMMUNotifier *notifier,
IOMMUTLBEntry *entry)
{
IOMMUNotifier *iommu_notifier;
IOMMUNotifierFlag request_flags;
assert(memory_region_is_iommu(mr));
/*
* Skip the notification if the notification does not overlap
* with registered range.
*/
if (notifier->start > entry->iova + entry->addr_mask + 1 ||
notifier->end < entry->iova) {
return;
}
if (entry.perm & IOMMU_RW) {
if (entry->perm & IOMMU_RW) {
request_flags = IOMMU_NOTIFIER_MAP;
} else {
request_flags = IOMMU_NOTIFIER_UNMAP;
}
if (notifier->notifier_flags & request_flags) {
notifier->notify(notifier, entry);
}
}
void memory_region_notify_iommu(MemoryRegion *mr,
IOMMUTLBEntry entry)
{
IOMMUNotifier *iommu_notifier;
assert(memory_region_is_iommu(mr));
IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) {
/*
* Skip the notification if the notification does not overlap
* with registered range.
*/
if (iommu_notifier->start > entry.iova + entry.addr_mask + 1 ||
iommu_notifier->end < entry.iova) {
continue;
}
if (iommu_notifier->notifier_flags & request_flags) {
iommu_notifier->notify(iommu_notifier, &entry);
}
memory_region_notify_one(iommu_notifier, &entry);
}
}