memory/iommu: QOM'fy IOMMU MemoryRegion

This defines new QOM object - IOMMUMemoryRegion - with MemoryRegion
as a parent.

This moves IOMMU-related fields from MR to IOMMU MR. However to avoid
dymanic QOM casting in fast path (address_space_translate, etc),
this adds an @is_iommu boolean flag to MR and provides new helper to
do simple cast to IOMMU MR - memory_region_get_iommu. The flag
is set in the instance init callback. This defines
memory_region_is_iommu as memory_region_get_iommu()!=NULL.

This switches MemoryRegion to IOMMUMemoryRegion in most places except
the ones where MemoryRegion may be an alias.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20170711035620.4232-2-aik@ozlabs.ru>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Alexey Kardashevskiy 2017-07-11 13:56:19 +10:00 committed by Paolo Bonzini
parent 98fab4c163
commit 3df9d74806
20 changed files with 170 additions and 109 deletions

View file

@ -35,6 +35,10 @@
#define MEMORY_REGION(obj) \
OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION)
#define TYPE_IOMMU_MEMORY_REGION "qemu:iommu-memory-region"
#define IOMMU_MEMORY_REGION(obj) \
OBJECT_CHECK(IOMMUMemoryRegion, (obj), TYPE_IOMMU_MEMORY_REGION)
typedef struct MemoryRegionOps MemoryRegionOps;
typedef struct MemoryRegionMmio MemoryRegionMmio;
@ -198,16 +202,16 @@ struct MemoryRegionIOMMUOps {
* set flag to IOMMU_NONE to mean that we don't need any
* read/write permission checks, like, when for region replay.
*/
IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr,
IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag);
/* Returns minimum supported page size */
uint64_t (*get_min_page_size)(MemoryRegion *iommu);
uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
/* Called when IOMMU Notifier flag changed */
void (*notify_flag_changed)(MemoryRegion *iommu,
void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old_flags,
IOMMUNotifierFlag new_flags);
/* Set this up to provide customized IOMMU replay function */
void (*replay)(MemoryRegion *iommu, IOMMUNotifier *notifier);
void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
};
typedef struct CoalescedMemoryRange CoalescedMemoryRange;
@ -227,9 +231,9 @@ struct MemoryRegion {
bool flush_coalesced_mmio;
bool global_locking;
uint8_t dirty_log_mask;
bool is_iommu;
RAMBlock *ram_block;
Object *owner;
const MemoryRegionIOMMUOps *iommu_ops;
const MemoryRegionOps *ops;
void *opaque;
@ -252,6 +256,12 @@ struct MemoryRegion {
const char *name;
unsigned ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds;
};
struct IOMMUMemoryRegion {
MemoryRegion parent_obj;
const MemoryRegionIOMMUOps *iommu_ops;
QLIST_HEAD(, IOMMUNotifier) iommu_notify;
IOMMUNotifierFlag iommu_notify_flags;
};
@ -618,13 +628,13 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
* An IOMMU region translates addresses and forwards accesses to a target
* memory region.
*
* @mr: the #MemoryRegion to be initialized
* @iommu_mr: the #IOMMUMemoryRegion to be initialized
* @owner: the object that tracks the region's reference count
* @ops: a function that translates addresses into the @target region
* @name: used for debugging; not visible to the user or ABI
* @size: size of the region.
*/
void memory_region_init_iommu(MemoryRegion *mr,
void memory_region_init_iommu(IOMMUMemoryRegion *iommu_mr,
struct Object *owner,
const MemoryRegionIOMMUOps *ops,
const char *name,
@ -679,20 +689,25 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
}
/**
* memory_region_is_iommu: check whether a memory region is an iommu
* memory_region_get_iommu: check whether a memory region is an iommu
*
* Returns %true is a memory region is an iommu.
* Returns pointer to IOMMUMemoryRegion if a memory region is an iommu,
* otherwise NULL.
*
* @mr: the memory region being queried
*/
static inline bool memory_region_is_iommu(MemoryRegion *mr)
static inline IOMMUMemoryRegion *memory_region_get_iommu(MemoryRegion *mr)
{
if (mr->alias) {
return memory_region_is_iommu(mr->alias);
return memory_region_get_iommu(mr->alias);
}
return mr->iommu_ops;
if (mr->is_iommu) {
return (IOMMUMemoryRegion *) mr;
}
return NULL;
}
#define memory_region_is_iommu(mr) (memory_region_get_iommu(mr) != NULL)
/**
* memory_region_iommu_get_min_page_size: get minimum supported page size
@ -700,9 +715,9 @@ static inline bool memory_region_is_iommu(MemoryRegion *mr)
*
* Returns minimum supported page size for an iommu.
*
* @mr: the memory region being queried
* @iommu_mr: the memory region being queried
*/
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr);
/**
* memory_region_notify_iommu: notify a change in an IOMMU translation entry.
@ -716,12 +731,12 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
* Note: for any IOMMU implementation, an in-place mapping change
* should be notified with an UNMAP followed by a MAP.
*
* @mr: the memory region that was changed
* @iommu_mr: the memory region that was changed
* @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_iommu(MemoryRegion *mr,
void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry);
/**
@ -756,18 +771,18 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
* a notifier with the minimum page granularity returned by
* mr->iommu_ops->get_page_size().
*
* @mr: the memory region to observe
* @iommu_mr: the memory region to observe
* @n: the notifier to which to replay iommu mappings
*/
void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n);
void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
/**
* memory_region_iommu_replay_all: replay existing IOMMU translations
* to all the notifiers registered.
*
* @mr: the memory region to observe
* @iommu_mr: the memory region to observe
*/
void memory_region_iommu_replay_all(MemoryRegion *mr);
void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
/**
* memory_region_unregister_iommu_notifier: unregister a notifier for