Commit bd2bfa4c authored by Peter Xu's avatar Peter Xu Committed by Eduardo Habkost
Browse files

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: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Reviewed-by: default avatarEric Auger <eric.auger@redhat.com>
Reviewed-by: default avatar\"Michael S. Tsirkin\" <mst@redhat.com>
Signed-off-by: default avatarPeter Xu <peterx@redhat.com>
Message-Id: <1491562755-23867-5-git-send-email-peterx@redhat.com>
Signed-off-by: default avatarEduardo Habkost <ehabkost@redhat.com>
parent de472e4a
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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.
+24 −16
Original line number Diff line number Diff line
@@ -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;
    }

    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 (notifier->notifier_flags & request_flags) {
        notifier->notify(notifier, entry);
    }
        if (iommu_notifier->notifier_flags & request_flags) {
            iommu_notifier->notify(iommu_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) {
        memory_region_notify_one(iommu_notifier, &entry);
    }
}