memory: introduce IOMMUOps.notify_flag_changed

The new interface can be used to replace the old notify_started() and
notify_stopped(). Meanwhile it provides explicit flags so that IOMMUs
can know what kind of notifications it is requested for.

Acked-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <1474606948-14391-3-git-send-email-peterx@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Peter Xu 2016-09-23 13:02:27 +08:00 committed by Paolo Bonzini
parent cdb3081269
commit 5bf3d31903
5 changed files with 44 additions and 24 deletions

View File

@ -1066,7 +1066,9 @@ static const MemoryRegionOps mmio_mem_ops = {
} }
}; };
static void amdvi_iommu_notify_started(MemoryRegion *iommu) static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{ {
AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
@ -1080,7 +1082,7 @@ static void amdvi_init(AMDVIState *s)
amdvi_iotlb_reset(s); amdvi_iotlb_reset(s);
s->iommu_ops.translate = amdvi_translate; s->iommu_ops.translate = amdvi_translate;
s->iommu_ops.notify_started = amdvi_iommu_notify_started; s->iommu_ops.notify_flag_changed = amdvi_iommu_notify_flag_changed;
s->devtab_len = 0; s->devtab_len = 0;
s->cmdbuf_len = 0; s->cmdbuf_len = 0;
s->cmdbuf_head = 0; s->cmdbuf_head = 0;

View File

@ -1974,7 +1974,9 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
return ret; return ret;
} }
static void vtd_iommu_notify_started(MemoryRegion *iommu) static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{ {
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
@ -2348,7 +2350,7 @@ static void vtd_init(IntelIOMMUState *s)
memset(s->womask, 0, DMAR_REG_SIZE); memset(s->womask, 0, DMAR_REG_SIZE);
s->iommu_ops.translate = vtd_iommu_translate; s->iommu_ops.translate = vtd_iommu_translate;
s->iommu_ops.notify_started = vtd_iommu_notify_started; s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed;
s->root = 0; s->root = 0;
s->root_extended = false; s->root_extended = false;
s->dmar_enabled = false; s->dmar_enabled = false;

View File

@ -156,14 +156,17 @@ static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu)
return 1ULL << tcet->page_shift; return 1ULL << tcet->page_shift;
} }
static void spapr_tce_notify_started(MemoryRegion *iommu) static void spapr_tce_notify_flag_changed(MemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{ {
spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), true); struct sPAPRTCETable *tbl = container_of(iommu, sPAPRTCETable, iommu);
}
static void spapr_tce_notify_stopped(MemoryRegion *iommu) if (old == IOMMU_NOTIFIER_NONE && new != IOMMU_NOTIFIER_NONE) {
{ spapr_tce_set_need_vfio(tbl, true);
spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), false); } else if (old != IOMMU_NOTIFIER_NONE && new == IOMMU_NOTIFIER_NONE) {
spapr_tce_set_need_vfio(tbl, false);
}
} }
static int spapr_tce_table_post_load(void *opaque, int version_id) static int spapr_tce_table_post_load(void *opaque, int version_id)
@ -246,8 +249,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
static MemoryRegionIOMMUOps spapr_iommu_ops = { static MemoryRegionIOMMUOps spapr_iommu_ops = {
.translate = spapr_tce_translate_iommu, .translate = spapr_tce_translate_iommu,
.get_min_page_size = spapr_tce_get_min_page_size, .get_min_page_size = spapr_tce_get_min_page_size,
.notify_started = spapr_tce_notify_started, .notify_flag_changed = spapr_tce_notify_flag_changed,
.notify_stopped = spapr_tce_notify_stopped,
}; };
static int spapr_tce_table_realize(DeviceState *dev) static int spapr_tce_table_realize(DeviceState *dev)

View File

@ -174,10 +174,10 @@ struct MemoryRegionIOMMUOps {
IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, bool is_write); IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, bool is_write);
/* Returns minimum supported page size */ /* Returns minimum supported page size */
uint64_t (*get_min_page_size)(MemoryRegion *iommu); uint64_t (*get_min_page_size)(MemoryRegion *iommu);
/* Called when the first notifier is set */ /* Called when IOMMU Notifier flag changed */
void (*notify_started)(MemoryRegion *iommu); void (*notify_flag_changed)(MemoryRegion *iommu,
/* Called when the last notifier is removed */ IOMMUNotifierFlag old_flags,
void (*notify_stopped)(MemoryRegion *iommu); IOMMUNotifierFlag new_flags);
}; };
typedef struct CoalescedMemoryRange CoalescedMemoryRange; typedef struct CoalescedMemoryRange CoalescedMemoryRange;
@ -223,6 +223,7 @@ struct MemoryRegion {
unsigned ioeventfd_nb; unsigned ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds; MemoryRegionIoeventfd *ioeventfds;
QLIST_HEAD(, IOMMUNotifier) iommu_notify; QLIST_HEAD(, IOMMUNotifier) iommu_notify;
IOMMUNotifierFlag iommu_notify_flags;
}; };
/** /**

View File

@ -1414,6 +1414,7 @@ void memory_region_init_iommu(MemoryRegion *mr,
mr->iommu_ops = ops, mr->iommu_ops = ops,
mr->terminates = true; /* then re-forwards */ mr->terminates = true; /* then re-forwards */
QLIST_INIT(&mr->iommu_notify); QLIST_INIT(&mr->iommu_notify);
mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
} }
static void memory_region_finalize(Object *obj) static void memory_region_finalize(Object *obj)
@ -1508,16 +1509,31 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client)
return memory_region_get_dirty_log_mask(mr) & (1 << client); return memory_region_get_dirty_log_mask(mr) & (1 << client);
} }
static void memory_region_update_iommu_notify_flags(MemoryRegion *mr)
{
IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE;
IOMMUNotifier *iommu_notifier;
QLIST_FOREACH(iommu_notifier, &mr->iommu_notify, node) {
flags |= iommu_notifier->notifier_flags;
}
if (flags != mr->iommu_notify_flags &&
mr->iommu_ops->notify_flag_changed) {
mr->iommu_ops->notify_flag_changed(mr, mr->iommu_notify_flags,
flags);
}
mr->iommu_notify_flags = flags;
}
void memory_region_register_iommu_notifier(MemoryRegion *mr, void memory_region_register_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n) IOMMUNotifier *n)
{ {
/* We need to register for at least one bitfield */ /* We need to register for at least one bitfield */
assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
if (mr->iommu_ops->notify_started &&
QLIST_EMPTY(&mr->iommu_notify)) {
mr->iommu_ops->notify_started(mr);
}
QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); QLIST_INSERT_HEAD(&mr->iommu_notify, n, node);
memory_region_update_iommu_notify_flags(mr);
} }
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr) uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr)
@ -1555,10 +1571,7 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n) IOMMUNotifier *n)
{ {
QLIST_REMOVE(n, node); QLIST_REMOVE(n, node);
if (mr->iommu_ops->notify_stopped && memory_region_update_iommu_notify_flags(mr);
QLIST_EMPTY(&mr->iommu_notify)) {
mr->iommu_ops->notify_stopped(mr);
}
} }
void memory_region_notify_iommu(MemoryRegion *mr, void memory_region_notify_iommu(MemoryRegion *mr,