提交 3df9d748 编写于 作者: A Alexey Kardashevskiy 提交者: Paolo Bonzini

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: NAlexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: NDavid Gibson <david@gibson.dropbear.id.au>
Message-Id: <20170711035620.4232-2-aik@ozlabs.ru>
Acked-by: NCornelia Huck <cohuck@redhat.com>
Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
上级 98fab4c1
...@@ -480,19 +480,19 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, ...@@ -480,19 +480,19 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as,
{ {
IOMMUTLBEntry iotlb; IOMMUTLBEntry iotlb;
MemoryRegionSection *section; MemoryRegionSection *section;
MemoryRegion *mr; IOMMUMemoryRegion *iommu_mr;
for (;;) { for (;;) {
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch); AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
section = address_space_translate_internal(d, addr, &addr, plen, is_mmio); section = address_space_translate_internal(d, addr, &addr, plen, is_mmio);
mr = section->mr;
if (!mr->iommu_ops) { iommu_mr = memory_region_get_iommu(section->mr);
if (!iommu_mr) {
break; break;
} }
iotlb = mr->iommu_ops->translate(mr, addr, is_write ? iotlb = iommu_mr->iommu_ops->translate(iommu_mr, addr, is_write ?
IOMMU_WO : IOMMU_RO); IOMMU_WO : IOMMU_RO);
addr = ((iotlb.translated_addr & ~iotlb.addr_mask) addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
| (addr & iotlb.addr_mask)); | (addr & iotlb.addr_mask));
*plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1); *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
...@@ -588,7 +588,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, ...@@ -588,7 +588,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
section = address_space_translate_internal(d, addr, xlat, plen, false); section = address_space_translate_internal(d, addr, xlat, plen, false);
assert(!section->mr->iommu_ops); assert(!memory_region_is_iommu(section->mr));
return section; return section;
} }
#endif #endif
......
...@@ -41,7 +41,7 @@ typedef struct TyphoonPchip { ...@@ -41,7 +41,7 @@ typedef struct TyphoonPchip {
MemoryRegion reg_conf; MemoryRegion reg_conf;
AddressSpace iommu_as; AddressSpace iommu_as;
MemoryRegion iommu; IOMMUMemoryRegion iommu;
uint64_t ctl; uint64_t ctl;
TyphoonWindow win[4]; TyphoonWindow win[4];
...@@ -663,7 +663,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr, ...@@ -663,7 +663,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
/* Handle PCI-to-system address translation. */ /* Handle PCI-to-system address translation. */
/* TODO: A translation failure here ought to set PCI error codes on the /* TODO: A translation failure here ought to set PCI error codes on the
Pchip and generate a machine check interrupt. */ Pchip and generate a machine check interrupt. */
static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu); TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
...@@ -893,7 +894,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, ...@@ -893,7 +894,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
/* Host memory as seen from the PCI side, via the IOMMU. */ /* Host memory as seen from the PCI side, via the IOMMU. */
memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops, memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
"iommu-typhoon", UINT64_MAX); "iommu-typhoon", UINT64_MAX);
address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci"); address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
"pchip0-pci");
pci_setup_iommu(b, typhoon_pci_dma_iommu, s); pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
......
...@@ -90,7 +90,7 @@ typedef struct rc4030State ...@@ -90,7 +90,7 @@ typedef struct rc4030State
qemu_irq jazz_bus_irq; qemu_irq jazz_bus_irq;
/* whole DMA memory region, root of DMA address space */ /* whole DMA memory region, root of DMA address space */
MemoryRegion dma_mr; IOMMUMemoryRegion dma_mr;
AddressSpace dma_as; AddressSpace dma_as;
MemoryRegion iomem_chipset; MemoryRegion iomem_chipset;
...@@ -488,7 +488,7 @@ static const MemoryRegionOps jazzio_ops = { ...@@ -488,7 +488,7 @@ static const MemoryRegionOps jazzio_ops = {
.endianness = DEVICE_NATIVE_ENDIAN, .endianness = DEVICE_NATIVE_ENDIAN,
}; };
static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
rc4030State *s = container_of(iommu, rc4030State, dma_mr); rc4030State *s = container_of(iommu, rc4030State, dma_mr);
...@@ -679,7 +679,7 @@ static void rc4030_realize(DeviceState *dev, Error **errp) ...@@ -679,7 +679,7 @@ static void rc4030_realize(DeviceState *dev, Error **errp)
memory_region_init_iommu(&s->dma_mr, o, &rc4030_dma_ops, memory_region_init_iommu(&s->dma_mr, o, &rc4030_dma_ops,
"rc4030.dma", UINT32_MAX); "rc4030.dma", UINT32_MAX);
address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma"); address_space_init(&s->dma_as, MEMORY_REGION(&s->dma_mr), "rc4030-dma");
} }
static void rc4030_unrealize(DeviceState *dev, Error **errp) static void rc4030_unrealize(DeviceState *dev, Error **errp)
...@@ -717,7 +717,7 @@ static void rc4030_register_types(void) ...@@ -717,7 +717,7 @@ static void rc4030_register_types(void)
type_init(rc4030_register_types) type_init(rc4030_register_types)
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr) DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr)
{ {
DeviceState *dev; DeviceState *dev;
......
...@@ -52,7 +52,7 @@ struct AMDVIAddressSpace { ...@@ -52,7 +52,7 @@ struct AMDVIAddressSpace {
uint8_t bus_num; /* bus number */ uint8_t bus_num; /* bus number */
uint8_t devfn; /* device function */ uint8_t devfn; /* device function */
AMDVIState *iommu_state; /* AMDVI - one per machine */ AMDVIState *iommu_state; /* AMDVI - one per machine */
MemoryRegion iommu; /* Device's address translation region */ IOMMUMemoryRegion iommu; /* Device's address translation region */
MemoryRegion iommu_ir; /* Device's interrupt remapping region */ MemoryRegion iommu_ir; /* Device's interrupt remapping region */
AddressSpace as; /* device's corresponding address space */ AddressSpace as; /* device's corresponding address space */
}; };
...@@ -987,7 +987,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr) ...@@ -987,7 +987,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr)
return addr >= AMDVI_INT_ADDR_FIRST && addr <= AMDVI_INT_ADDR_LAST; return addr >= AMDVI_INT_ADDR_FIRST && addr <= AMDVI_INT_ADDR_LAST;
} }
static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
...@@ -1046,7 +1046,8 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) ...@@ -1046,7 +1046,8 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s), memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s),
&s->iommu_ops, "amd-iommu", UINT64_MAX); &s->iommu_ops, "amd-iommu", UINT64_MAX);
address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu, address_space_init(&iommu_as[devfn]->as,
MEMORY_REGION(&iommu_as[devfn]->iommu),
"amd-iommu"); "amd-iommu");
} }
return &iommu_as[devfn]->as; return &iommu_as[devfn]->as;
...@@ -1067,7 +1068,7 @@ static const MemoryRegionOps mmio_mem_ops = { ...@@ -1067,7 +1068,7 @@ static const MemoryRegionOps mmio_mem_ops = {
} }
}; };
static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu, static void amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old, IOMMUNotifierFlag old,
IOMMUNotifierFlag new) IOMMUNotifierFlag new)
{ {
......
...@@ -972,9 +972,9 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) ...@@ -972,9 +972,9 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
/* Turn off first then on the other */ /* Turn off first then on the other */
if (use_iommu) { if (use_iommu) {
memory_region_set_enabled(&as->sys_alias, false); memory_region_set_enabled(&as->sys_alias, false);
memory_region_set_enabled(&as->iommu, true); memory_region_set_enabled(MEMORY_REGION(&as->iommu), true);
} else { } else {
memory_region_set_enabled(&as->iommu, false); memory_region_set_enabled(MEMORY_REGION(&as->iommu), false);
memory_region_set_enabled(&as->sys_alias, true); memory_region_set_enabled(&as->sys_alias, true);
} }
...@@ -1366,7 +1366,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) ...@@ -1366,7 +1366,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry, static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,
void *private) void *private)
{ {
memory_region_notify_iommu((MemoryRegion *)private, *entry); memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry);
return 0; return 0;
} }
...@@ -2264,7 +2264,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr, ...@@ -2264,7 +2264,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
} }
} }
static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
...@@ -2303,7 +2303,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, ...@@ -2303,7 +2303,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
return iotlb; return iotlb;
} }
static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu, static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old, IOMMUNotifierFlag old,
IOMMUNotifierFlag new) IOMMUNotifierFlag new)
{ {
...@@ -2736,7 +2736,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) ...@@ -2736,7 +2736,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
memory_region_add_subregion_overlap(&vtd_dev_as->root, 0, memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
&vtd_dev_as->sys_alias, 1); &vtd_dev_as->sys_alias, 1);
memory_region_add_subregion_overlap(&vtd_dev_as->root, 0, memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
&vtd_dev_as->iommu, 1); MEMORY_REGION(&vtd_dev_as->iommu),
1);
vtd_switch_address_space(vtd_dev_as); vtd_switch_address_space(vtd_dev_as);
} }
return vtd_dev_as; return vtd_dev_as;
...@@ -2816,9 +2817,9 @@ static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) ...@@ -2816,9 +2817,9 @@ static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
return 0; return 0;
} }
static void vtd_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n) static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
{ {
VTDAddressSpace *vtd_as = container_of(mr, VTDAddressSpace, iommu); VTDAddressSpace *vtd_as = container_of(iommu_mr, VTDAddressSpace, iommu);
IntelIOMMUState *s = vtd_as->iommu_state; IntelIOMMUState *s = vtd_as->iommu_state;
uint8_t bus_n = pci_bus_num(vtd_as->bus); uint8_t bus_n = pci_bus_num(vtd_as->bus);
VTDContextEntry ce; VTDContextEntry ce;
......
...@@ -130,7 +130,7 @@ static void mips_jazz_init(MachineState *machine, ...@@ -130,7 +130,7 @@ static void mips_jazz_init(MachineState *machine,
CPUMIPSState *env; CPUMIPSState *env;
qemu_irq *i8259; qemu_irq *i8259;
rc4030_dma *dmas; rc4030_dma *dmas;
MemoryRegion *rc4030_dma_mr; IOMMUMemoryRegion *rc4030_dma_mr;
MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1);
......
...@@ -123,7 +123,7 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) ...@@ -123,7 +123,7 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
typedef struct IOMMUState { typedef struct IOMMUState {
AddressSpace iommu_as; AddressSpace iommu_as;
MemoryRegion iommu; IOMMUMemoryRegion iommu;
uint64_t regs[IOMMU_NREGS]; uint64_t regs[IOMMU_NREGS];
} IOMMUState; } IOMMUState;
...@@ -208,7 +208,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) ...@@ -208,7 +208,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
} }
/* Called from RCU critical section */ /* Called from RCU critical section */
static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
IOMMUState *is = container_of(iommu, IOMMUState, iommu); IOMMUState *is = container_of(iommu, IOMMUState, iommu);
...@@ -699,7 +699,7 @@ PCIBus *pci_apb_init(hwaddr special_base, ...@@ -699,7 +699,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops, memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops,
"iommu-apb", UINT64_MAX); "iommu-apb", UINT64_MAX);
address_space_init(&is->iommu_as, &is->iommu, "pbm-as"); address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as");
pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
/* APB secondary busses */ /* APB secondary busses */
......
...@@ -110,7 +110,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table) ...@@ -110,7 +110,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
} }
/* Called from RCU critical section */ /* Called from RCU critical section */
static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
...@@ -150,14 +151,14 @@ static void spapr_tce_table_pre_save(void *opaque) ...@@ -150,14 +151,14 @@ static void spapr_tce_table_pre_save(void *opaque)
tcet->bus_offset, tcet->page_shift); tcet->bus_offset, tcet->page_shift);
} }
static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu) static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
{ {
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
return 1ULL << tcet->page_shift; return 1ULL << tcet->page_shift;
} }
static void spapr_tce_notify_flag_changed(MemoryRegion *iommu, static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old, IOMMUNotifierFlag old,
IOMMUNotifierFlag new) IOMMUNotifierFlag new)
{ {
...@@ -348,9 +349,10 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet, ...@@ -348,9 +349,10 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
&tcet->fd, &tcet->fd,
tcet->need_vfio); tcet->need_vfio);
memory_region_set_size(&tcet->iommu, memory_region_set_size(MEMORY_REGION(&tcet->iommu),
(uint64_t)tcet->nb_table << tcet->page_shift); (uint64_t)tcet->nb_table << tcet->page_shift);
memory_region_add_subregion(&tcet->root, tcet->bus_offset, &tcet->iommu); memory_region_add_subregion(&tcet->root, tcet->bus_offset,
MEMORY_REGION(&tcet->iommu));
} }
void spapr_tce_table_disable(sPAPRTCETable *tcet) void spapr_tce_table_disable(sPAPRTCETable *tcet)
...@@ -359,8 +361,8 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet) ...@@ -359,8 +361,8 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet)
return; return;
} }
memory_region_del_subregion(&tcet->root, &tcet->iommu); memory_region_del_subregion(&tcet->root, MEMORY_REGION(&tcet->iommu));
memory_region_set_size(&tcet->iommu, 0); memory_region_set_size(MEMORY_REGION(&tcet->iommu), 0);
spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table); spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table);
tcet->fd = -1; tcet->fd = -1;
......
...@@ -356,7 +356,7 @@ out: ...@@ -356,7 +356,7 @@ out:
return pte; return pte;
} }
static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr, static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
uint64_t pte; uint64_t pte;
...@@ -525,14 +525,14 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu) ...@@ -525,14 +525,14 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr), memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr),
&s390_iommu_ops, name, iommu->pal + 1); &s390_iommu_ops, name, iommu->pal + 1);
iommu->enabled = true; iommu->enabled = true;
memory_region_add_subregion(&iommu->mr, 0, &iommu->iommu_mr); memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr));
g_free(name); g_free(name);
} }
void s390_pci_iommu_disable(S390PCIIOMMU *iommu) void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
{ {
iommu->enabled = false; iommu->enabled = false;
memory_region_del_subregion(&iommu->mr, &iommu->iommu_mr); memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr));
object_unparent(OBJECT(&iommu->iommu_mr)); object_unparent(OBJECT(&iommu->iommu_mr));
} }
......
...@@ -266,7 +266,7 @@ typedef struct S390PCIIOMMU { ...@@ -266,7 +266,7 @@ typedef struct S390PCIIOMMU {
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev;
AddressSpace as; AddressSpace as;
MemoryRegion mr; MemoryRegion mr;
MemoryRegion iommu_mr; IOMMUMemoryRegion iommu_mr;
bool enabled; bool enabled;
uint64_t g_iota; uint64_t g_iota;
uint64_t pba; uint64_t pba;
......
...@@ -563,7 +563,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) ...@@ -563,7 +563,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
S390PCIIOMMU *iommu; S390PCIIOMMU *iommu;
hwaddr start, end; hwaddr start, end;
IOMMUTLBEntry entry; IOMMUTLBEntry entry;
MemoryRegion *mr; IOMMUMemoryRegion *iommu_mr;
cpu_synchronize_state(CPU(cpu)); cpu_synchronize_state(CPU(cpu));
...@@ -622,9 +622,9 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) ...@@ -622,9 +622,9 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out; goto out;
} }
mr = &iommu->iommu_mr; iommu_mr = &iommu->iommu_mr;
while (start < end) { while (start < end) {
entry = mr->iommu_ops->translate(mr, start, IOMMU_NONE); entry = iommu_mr->iommu_ops->translate(iommu_mr, start, IOMMU_NONE);
if (!entry.translated_addr) { if (!entry.translated_addr) {
pbdev->state = ZPCI_FS_ERROR; pbdev->state = ZPCI_FS_ERROR;
...@@ -635,7 +635,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) ...@@ -635,7 +635,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out; goto out;
} }
memory_region_notify_iommu(mr, entry); memory_region_notify_iommu(iommu_mr, entry);
start += entry.addr_mask + 1; start += entry.addr_mask + 1;
} }
......
...@@ -479,6 +479,7 @@ static void vfio_listener_region_add(MemoryListener *listener, ...@@ -479,6 +479,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
if (memory_region_is_iommu(section->mr)) { if (memory_region_is_iommu(section->mr)) {
VFIOGuestIOMMU *giommu; VFIOGuestIOMMU *giommu;
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
trace_vfio_listener_region_add_iommu(iova, end); trace_vfio_listener_region_add_iommu(iova, end);
/* /*
...@@ -488,7 +489,7 @@ static void vfio_listener_region_add(MemoryListener *listener, ...@@ -488,7 +489,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
* device emulation the VFIO iommu handles to use). * device emulation the VFIO iommu handles to use).
*/ */
giommu = g_malloc0(sizeof(*giommu)); giommu = g_malloc0(sizeof(*giommu));
giommu->iommu = section->mr; giommu->iommu = iommu_mr;
giommu->iommu_offset = section->offset_within_address_space - giommu->iommu_offset = section->offset_within_address_space -
section->offset_within_region; section->offset_within_region;
giommu->container = container; giommu->container = container;
...@@ -501,7 +502,7 @@ static void vfio_listener_region_add(MemoryListener *listener, ...@@ -501,7 +502,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
int128_get64(llend)); int128_get64(llend));
QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
memory_region_register_iommu_notifier(giommu->iommu, &giommu->n); memory_region_register_iommu_notifier(section->mr, &giommu->n);
memory_region_iommu_replay(giommu->iommu, &giommu->n); memory_region_iommu_replay(giommu->iommu, &giommu->n);
return; return;
...@@ -569,9 +570,9 @@ static void vfio_listener_region_del(MemoryListener *listener, ...@@ -569,9 +570,9 @@ static void vfio_listener_region_del(MemoryListener *listener,
VFIOGuestIOMMU *giommu; VFIOGuestIOMMU *giommu;
QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
if (giommu->iommu == section->mr && if (MEMORY_REGION(giommu->iommu) == section->mr &&
giommu->n.start == section->offset_within_region) { giommu->n.start == section->offset_within_region) {
memory_region_unregister_iommu_notifier(giommu->iommu, memory_region_unregister_iommu_notifier(section->mr,
&giommu->n); &giommu->n);
QLIST_REMOVE(giommu, giommu_next); QLIST_REMOVE(giommu, giommu_next);
g_free(giommu); g_free(giommu);
...@@ -1163,7 +1164,8 @@ static void vfio_disconnect_container(VFIOGroup *group) ...@@ -1163,7 +1164,8 @@ static void vfio_disconnect_container(VFIOGroup *group)
QLIST_REMOVE(container, next); QLIST_REMOVE(container, next);
QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
memory_region_unregister_iommu_notifier(giommu->iommu, &giommu->n); memory_region_unregister_iommu_notifier(
MEMORY_REGION(giommu->iommu), &giommu->n);
QLIST_REMOVE(giommu, giommu_next); QLIST_REMOVE(giommu, giommu_next);
g_free(giommu); g_free(giommu);
} }
......
...@@ -143,7 +143,8 @@ int vfio_spapr_create_window(VFIOContainer *container, ...@@ -143,7 +143,8 @@ int vfio_spapr_create_window(VFIOContainer *container,
hwaddr *pgsize) hwaddr *pgsize)
{ {
int ret; int ret;
unsigned pagesize = memory_region_iommu_get_min_page_size(section->mr); IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
unsigned pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
unsigned entries, pages; unsigned entries, pages;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) }; struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
#define MEMORY_REGION(obj) \ #define MEMORY_REGION(obj) \
OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION) 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 MemoryRegionOps MemoryRegionOps;
typedef struct MemoryRegionMmio MemoryRegionMmio; typedef struct MemoryRegionMmio MemoryRegionMmio;
...@@ -198,16 +202,16 @@ struct MemoryRegionIOMMUOps { ...@@ -198,16 +202,16 @@ struct MemoryRegionIOMMUOps {
* set flag to IOMMU_NONE to mean that we don't need any * set flag to IOMMU_NONE to mean that we don't need any
* read/write permission checks, like, when for region replay. * read/write permission checks, like, when for region replay.
*/ */
IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag); IOMMUAccessFlags flag);
/* Returns minimum supported page size */ /* 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 */ /* Called when IOMMU Notifier flag changed */
void (*notify_flag_changed)(MemoryRegion *iommu, void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old_flags, IOMMUNotifierFlag old_flags,
IOMMUNotifierFlag new_flags); IOMMUNotifierFlag new_flags);
/* Set this up to provide customized IOMMU replay function */ /* 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; typedef struct CoalescedMemoryRange CoalescedMemoryRange;
...@@ -227,9 +231,9 @@ struct MemoryRegion { ...@@ -227,9 +231,9 @@ struct MemoryRegion {
bool flush_coalesced_mmio; bool flush_coalesced_mmio;
bool global_locking; bool global_locking;
uint8_t dirty_log_mask; uint8_t dirty_log_mask;
bool is_iommu;
RAMBlock *ram_block; RAMBlock *ram_block;
Object *owner; Object *owner;
const MemoryRegionIOMMUOps *iommu_ops;
const MemoryRegionOps *ops; const MemoryRegionOps *ops;
void *opaque; void *opaque;
...@@ -252,6 +256,12 @@ struct MemoryRegion { ...@@ -252,6 +256,12 @@ struct MemoryRegion {
const char *name; const char *name;
unsigned ioeventfd_nb; unsigned ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds; MemoryRegionIoeventfd *ioeventfds;
};
struct IOMMUMemoryRegion {
MemoryRegion parent_obj;
const MemoryRegionIOMMUOps *iommu_ops;
QLIST_HEAD(, IOMMUNotifier) iommu_notify; QLIST_HEAD(, IOMMUNotifier) iommu_notify;
IOMMUNotifierFlag iommu_notify_flags; IOMMUNotifierFlag iommu_notify_flags;
}; };
...@@ -618,13 +628,13 @@ static inline void memory_region_init_reservation(MemoryRegion *mr, ...@@ -618,13 +628,13 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
* An IOMMU region translates addresses and forwards accesses to a target * An IOMMU region translates addresses and forwards accesses to a target
* memory region. * 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 * @owner: the object that tracks the region's reference count
* @ops: a function that translates addresses into the @target region * @ops: a function that translates addresses into the @target region
* @name: used for debugging; not visible to the user or ABI * @name: used for debugging; not visible to the user or ABI
* @size: size of the region. * @size: size of the region.
*/ */
void memory_region_init_iommu(MemoryRegion *mr, void memory_region_init_iommu(IOMMUMemoryRegion *iommu_mr,
struct Object *owner, struct Object *owner,
const MemoryRegionIOMMUOps *ops, const MemoryRegionIOMMUOps *ops,
const char *name, const char *name,
...@@ -679,20 +689,25 @@ static inline bool memory_region_is_romd(MemoryRegion *mr) ...@@ -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 * @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) { if (mr->alias) {
return memory_region_is_iommu(mr->alias); return memory_region_get_iommu(mr->alias);
}
if (mr->is_iommu) {
return (IOMMUMemoryRegion *) mr;
} }
return mr->iommu_ops; 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 * 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) ...@@ -700,9 +715,9 @@ static inline bool memory_region_is_iommu(MemoryRegion *mr)
* *
* Returns minimum supported page size for an iommu. * 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. * 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); ...@@ -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 * Note: for any IOMMU implementation, an in-place mapping change
* should be notified with an UNMAP followed by a MAP. * 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 * @entry: the new entry in the IOMMU translation table. The entry
* replaces all old entries for the same virtual I/O address range. * replaces all old entries for the same virtual I/O address range.
* Deleted entries have .@perm == 0. * Deleted entries have .@perm == 0.
*/ */
void memory_region_notify_iommu(MemoryRegion *mr, void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry); IOMMUTLBEntry entry);
/** /**
...@@ -756,18 +771,18 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, ...@@ -756,18 +771,18 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
* a notifier with the minimum page granularity returned by * a notifier with the minimum page granularity returned by
* mr->iommu_ops->get_page_size(). * 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 * @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 * memory_region_iommu_replay_all: replay existing IOMMU translations
* to all the notifiers registered. * 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 * memory_region_unregister_iommu_notifier: unregister a notifier for
......
...@@ -83,7 +83,7 @@ struct VTDAddressSpace { ...@@ -83,7 +83,7 @@ struct VTDAddressSpace {
PCIBus *bus; PCIBus *bus;
uint8_t devfn; uint8_t devfn;
AddressSpace as; AddressSpace as;
MemoryRegion iommu; IOMMUMemoryRegion iommu;
MemoryRegion root; MemoryRegion root;
MemoryRegion sys_alias; MemoryRegion sys_alias;
MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */ MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */
......
...@@ -19,6 +19,6 @@ typedef struct rc4030DMAState *rc4030_dma; ...@@ -19,6 +19,6 @@ typedef struct rc4030DMAState *rc4030_dma;
void rc4030_dma_read(void *dma, uint8_t *buf, int len); void rc4030_dma_read(void *dma, uint8_t *buf, int len);
void rc4030_dma_write(void *dma, uint8_t *buf, int len); void rc4030_dma_write(void *dma, uint8_t *buf, int len);
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr); DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
#endif #endif
...@@ -594,7 +594,8 @@ struct sPAPRTCETable { ...@@ -594,7 +594,8 @@ struct sPAPRTCETable {
bool bypass; bool bypass;
bool need_vfio; bool need_vfio;
int fd; int fd;
MemoryRegion root, iommu; MemoryRegion root;
IOMMUMemoryRegion iommu;
struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */ struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */
QLIST_ENTRY(sPAPRTCETable) list; QLIST_ENTRY(sPAPRTCETable) list;
}; };
......
...@@ -95,7 +95,7 @@ typedef struct VFIOContainer { ...@@ -95,7 +95,7 @@ typedef struct VFIOContainer {
typedef struct VFIOGuestIOMMU { typedef struct VFIOGuestIOMMU {
VFIOContainer *container; VFIOContainer *container;
MemoryRegion *iommu; IOMMUMemoryRegion *iommu;
hwaddr iommu_offset; hwaddr iommu_offset;
IOMMUNotifier n; IOMMUNotifier n;
QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
......
...@@ -45,6 +45,7 @@ typedef struct MachineState MachineState; ...@@ -45,6 +45,7 @@ typedef struct MachineState MachineState;
typedef struct MemoryListener MemoryListener; typedef struct MemoryListener MemoryListener;
typedef struct MemoryMappingList MemoryMappingList; typedef struct MemoryMappingList MemoryMappingList;
typedef struct MemoryRegion MemoryRegion; typedef struct MemoryRegion MemoryRegion;
typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
typedef struct MemoryRegionCache MemoryRegionCache; typedef struct MemoryRegionCache MemoryRegionCache;
typedef struct MemoryRegionSection MemoryRegionSection; typedef struct MemoryRegionSection MemoryRegionSection;
typedef struct MigrationIncomingState MigrationIncomingState; typedef struct MigrationIncomingState MigrationIncomingState;
......
...@@ -977,12 +977,11 @@ static char *memory_region_escape_name(const char *name) ...@@ -977,12 +977,11 @@ static char *memory_region_escape_name(const char *name)
return escaped; return escaped;
} }
void memory_region_init(MemoryRegion *mr, static void memory_region_do_init(MemoryRegion *mr,
Object *owner, Object *owner,
const char *name, const char *name,
uint64_t size) uint64_t size)
{ {
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
mr->size = int128_make64(size); mr->size = int128_make64(size);
if (size == UINT64_MAX) { if (size == UINT64_MAX) {
mr->size = int128_2_64(); mr->size = int128_2_64();
...@@ -1006,6 +1005,15 @@ void memory_region_init(MemoryRegion *mr, ...@@ -1006,6 +1005,15 @@ void memory_region_init(MemoryRegion *mr,
} }
} }
void memory_region_init(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
memory_region_do_init(mr, owner, name, size);
}
static void memory_region_get_addr(Object *obj, Visitor *v, const char *name, static void memory_region_get_addr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp) void *opaque, Error **errp)
{ {
...@@ -1092,6 +1100,13 @@ static void memory_region_initfn(Object *obj) ...@@ -1092,6 +1100,13 @@ static void memory_region_initfn(Object *obj)
NULL, NULL, &error_abort); NULL, NULL, &error_abort);
} }
static void iommu_memory_region_initfn(Object *obj)
{
MemoryRegion *mr = MEMORY_REGION(obj);
mr->is_iommu = true;
}
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
unsigned size) unsigned size)
{ {
...@@ -1491,17 +1506,22 @@ void memory_region_init_rom_device(MemoryRegion *mr, ...@@ -1491,17 +1506,22 @@ void memory_region_init_rom_device(MemoryRegion *mr,
mr->ram_block = qemu_ram_alloc(size, mr, errp); mr->ram_block = qemu_ram_alloc(size, mr, errp);
} }
void memory_region_init_iommu(MemoryRegion *mr, void memory_region_init_iommu(IOMMUMemoryRegion *iommu_mr,
Object *owner, Object *owner,
const MemoryRegionIOMMUOps *ops, const MemoryRegionIOMMUOps *ops,
const char *name, const char *name,
uint64_t size) uint64_t size)
{ {
memory_region_init(mr, owner, name, size); struct MemoryRegion *mr;
mr->iommu_ops = ops,
object_initialize(iommu_mr, sizeof(*iommu_mr), TYPE_IOMMU_MEMORY_REGION);
mr = MEMORY_REGION(iommu_mr);
memory_region_do_init(mr, owner, name, size);
iommu_mr = IOMMU_MEMORY_REGION(mr);
iommu_mr->iommu_ops = ops,
mr->terminates = true; /* then re-forwards */ mr->terminates = true; /* then re-forwards */
QLIST_INIT(&mr->iommu_notify); QLIST_INIT(&iommu_mr->iommu_notify);
mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE; iommu_mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
} }
static void memory_region_finalize(Object *obj) static void memory_region_finalize(Object *obj)
...@@ -1596,63 +1616,67 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client) ...@@ -1596,63 +1616,67 @@ 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) static void memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr)
{ {
IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE; IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE;
IOMMUNotifier *iommu_notifier; IOMMUNotifier *iommu_notifier;
IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
flags |= iommu_notifier->notifier_flags; flags |= iommu_notifier->notifier_flags;
} }
if (flags != mr->iommu_notify_flags && if (flags != iommu_mr->iommu_notify_flags &&
mr->iommu_ops->notify_flag_changed) { iommu_mr->iommu_ops->notify_flag_changed) {
mr->iommu_ops->notify_flag_changed(mr, mr->iommu_notify_flags, iommu_mr->iommu_ops->notify_flag_changed(iommu_mr,
flags); iommu_mr->iommu_notify_flags,
flags);
} }
mr->iommu_notify_flags = flags; iommu_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)
{ {
IOMMUMemoryRegion *iommu_mr;
if (mr->alias) { if (mr->alias) {
memory_region_register_iommu_notifier(mr->alias, n); memory_region_register_iommu_notifier(mr->alias, n);
return; return;
} }
/* We need to register for at least one bitfield */ /* We need to register for at least one bitfield */
iommu_mr = IOMMU_MEMORY_REGION(mr);
assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
assert(n->start <= n->end); assert(n->start <= n->end);
QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
memory_region_update_iommu_notify_flags(mr); memory_region_update_iommu_notify_flags(iommu_mr);
} }
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr) uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr)
{ {
assert(memory_region_is_iommu(mr)); if (iommu_mr->iommu_ops && iommu_mr->iommu_ops->get_min_page_size) {
if (mr->iommu_ops && mr->iommu_ops->get_min_page_size) { return iommu_mr->iommu_ops->get_min_page_size(iommu_mr);
return mr->iommu_ops->get_min_page_size(mr);
} }
return TARGET_PAGE_SIZE; return TARGET_PAGE_SIZE;
} }
void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n) void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
{ {
MemoryRegion *mr = MEMORY_REGION(iommu_mr);
hwaddr addr, granularity; hwaddr addr, granularity;
IOMMUTLBEntry iotlb; IOMMUTLBEntry iotlb;
/* If the IOMMU has its own replay callback, override */ /* If the IOMMU has its own replay callback, override */
if (mr->iommu_ops->replay) { if (iommu_mr->iommu_ops->replay) {
mr->iommu_ops->replay(mr, n); iommu_mr->iommu_ops->replay(iommu_mr, n);
return; return;
} }
granularity = memory_region_iommu_get_min_page_size(mr); granularity = memory_region_iommu_get_min_page_size(iommu_mr);
for (addr = 0; addr < memory_region_size(mr); addr += granularity) { for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
iotlb = mr->iommu_ops->translate(mr, addr, IOMMU_NONE); iotlb = iommu_mr->iommu_ops->translate(iommu_mr, addr, IOMMU_NONE);
if (iotlb.perm != IOMMU_NONE) { if (iotlb.perm != IOMMU_NONE) {
n->notify(n, &iotlb); n->notify(n, &iotlb);
} }
...@@ -1665,24 +1689,27 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n) ...@@ -1665,24 +1689,27 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n)
} }
} }
void memory_region_iommu_replay_all(MemoryRegion *mr) void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr)
{ {
IOMMUNotifier *notifier; IOMMUNotifier *notifier;
IOMMU_NOTIFIER_FOREACH(notifier, mr) { IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
memory_region_iommu_replay(mr, notifier); memory_region_iommu_replay(iommu_mr, notifier);
} }
} }
void memory_region_unregister_iommu_notifier(MemoryRegion *mr, void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n) IOMMUNotifier *n)
{ {
IOMMUMemoryRegion *iommu_mr;
if (mr->alias) { if (mr->alias) {
memory_region_unregister_iommu_notifier(mr->alias, n); memory_region_unregister_iommu_notifier(mr->alias, n);
return; return;
} }
QLIST_REMOVE(n, node); QLIST_REMOVE(n, node);
memory_region_update_iommu_notify_flags(mr); iommu_mr = IOMMU_MEMORY_REGION(mr);
memory_region_update_iommu_notify_flags(iommu_mr);
} }
void memory_region_notify_one(IOMMUNotifier *notifier, void memory_region_notify_one(IOMMUNotifier *notifier,
...@@ -1710,14 +1737,14 @@ void memory_region_notify_one(IOMMUNotifier *notifier, ...@@ -1710,14 +1737,14 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
} }
} }
void memory_region_notify_iommu(MemoryRegion *mr, void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry) IOMMUTLBEntry entry)
{ {
IOMMUNotifier *iommu_notifier; IOMMUNotifier *iommu_notifier;
assert(memory_region_is_iommu(mr)); assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
memory_region_notify_one(iommu_notifier, &entry); memory_region_notify_one(iommu_notifier, &entry);
} }
} }
...@@ -2825,9 +2852,17 @@ static const TypeInfo memory_region_info = { ...@@ -2825,9 +2852,17 @@ static const TypeInfo memory_region_info = {
.instance_finalize = memory_region_finalize, .instance_finalize = memory_region_finalize,
}; };
static const TypeInfo iommu_memory_region_info = {
.parent = TYPE_MEMORY_REGION,
.name = TYPE_IOMMU_MEMORY_REGION,
.instance_size = sizeof(IOMMUMemoryRegion),
.instance_init = iommu_memory_region_initfn,
};
static void memory_register_types(void) static void memory_register_types(void)
{ {
type_register_static(&memory_region_info); type_register_static(&memory_region_info);
type_register_static(&iommu_memory_region_info);
} }
type_init(memory_register_types) type_init(memory_register_types)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册