From aea5b071012d3507885724362913d0b71dd6c303 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH] apb: QOMify IOMMU This is in preparation to split the IOMMU device out of the APB. As part of this commit we also enforce separation of the IOMMU and APB devices by using a QOM object link to pass the IOMMU reference and accessing the IOMMU registers via a separate memory region mapped into the APB config space rather than directly. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/pci-host/apb.c | 77 +++++++++++++++++++++++++++++---------- hw/sparc64/sun4u.c | 7 +++- include/hw/pci-host/apb.h | 8 +++- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 44b08c090e..060e6e6d1c 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -36,6 +36,7 @@ #include "hw/pci-host/apb.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" +#include "qapi/error.h" #include "qemu/log.h" /* debug APB */ @@ -250,8 +251,8 @@ static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, return ret; } -static void iommu_config_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) +static void iommu_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { IOMMUState *is = opaque; @@ -295,7 +296,7 @@ static void iommu_config_write(void *opaque, hwaddr addr, } } -static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) { IOMMUState *is = opaque; uint64_t val; @@ -344,7 +345,6 @@ static void apb_config_writel (void *opaque, hwaddr addr, uint64_t val, unsigned size) { APBState *s = opaque; - IOMMUState *is = &s->iommu; APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val); @@ -352,9 +352,6 @@ static void apb_config_writel (void *opaque, hwaddr addr, case 0x30 ... 0x4f: /* DMA error registers */ /* XXX: not implemented yet */ break; - case 0x200 ... 0x217: /* IOMMU */ - iommu_config_write(is, (addr & 0x1f), val, size); - break; case 0xc00 ... 0xc3f: /* PCI interrupt control */ if (addr & 4) { unsigned int ino = (addr & 0x3f) >> 3; @@ -426,7 +423,6 @@ static uint64_t apb_config_readl (void *opaque, hwaddr addr, unsigned size) { APBState *s = opaque; - IOMMUState *is = &s->iommu; uint32_t val; switch (addr & 0xffff) { @@ -434,9 +430,6 @@ static uint64_t apb_config_readl (void *opaque, val = 0; /* XXX: not implemented yet */ break; - case 0x200 ... 0x217: /* IOMMU */ - val = iommu_config_read(is, (addr & 0x1f), size); - break; case 0xc00 ... 0xc3f: /* PCI interrupt control */ if (addr & 4) { val = s->pci_irq_map[(addr & 0x3f) >> 3]; @@ -643,7 +636,6 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp) PCIHostState *phb = PCI_HOST_BRIDGE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(s); PCIDevice *pci_dev; - IOMMUState *is; /* apb_config */ sysbus_mmio_map(sbd, 0, s->special_base); @@ -665,14 +657,9 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp) pci_create_simple(phb->bus, 0, "pbm-pci"); /* APB IOMMU */ - is = &s->iommu; - memset(is, 0, sizeof(IOMMUState)); - - memory_region_init_iommu(&is->iommu, sizeof(is->iommu), - TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev), - "iommu-apb", UINT64_MAX); - address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as"); - pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); + memory_region_add_subregion_overlap(&s->apb_config, 0x200, + sysbus_mmio_get_region(SYS_BUS_DEVICE(s->iommu), 0), 1); + pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, s->iommu); /* APB secondary busses */ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, @@ -708,6 +695,12 @@ static void pci_pbm_init(Object *obj) s->irq_request = NO_IRQ_REQUEST; s->pci_irq_in = 0ULL; + /* IOMMU */ + object_property_add_link(obj, "iommu", TYPE_SUN4U_IOMMU, + (Object **) &s->iommu, + qdev_prop_allow_set_link_before_realize, + 0, NULL); + /* apb_config */ memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s, "apb-config", 0x10000); @@ -814,6 +807,49 @@ static const TypeInfo pbm_pci_bridge_info = { }, }; +static const MemoryRegionOps iommu_mem_ops = { + .read = iommu_mem_read, + .write = iommu_mem_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void iommu_reset(DeviceState *d) +{ + IOMMUState *s = SUN4U_IOMMU(d); + + memset(s->regs, 0, IOMMU_NREGS * sizeof(uint64_t)); +} + +static void iommu_init(Object *obj) +{ + IOMMUState *s = SUN4U_IOMMU(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_iommu(&s->iommu, sizeof(s->iommu), + TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(s), + "iommu-apb", UINT64_MAX); + address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "pbm-as"); + + memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu", + IOMMU_NREGS * sizeof(uint64_t)); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void iommu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = iommu_reset; +} + +static const TypeInfo pbm_iommu_info = { + .name = TYPE_SUN4U_IOMMU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IOMMUState), + .instance_init = iommu_init, + .class_init = iommu_class_init, +}; + static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); @@ -832,6 +868,7 @@ static void pbm_register_types(void) type_register_static(&pbm_host_info); type_register_static(&pbm_pci_host_info); type_register_static(&pbm_pci_bridge_info); + type_register_static(&pbm_iommu_info); type_register_static(&pbm_iommu_memory_region_info); } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 5d802bdfde..aaee3de03a 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -469,7 +469,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, PCIDevice *ebus, *pci_dev; SysBusDevice *s; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DeviceState *dev; + DeviceState *iommu, *dev; FWCfgState *fw_cfg; NICInfo *nd; MACAddr macaddr; @@ -478,6 +478,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, /* init CPUs */ cpu = sparc64_cpu_devinit(machine->cpu_type, hwdef->prom_addr); + /* IOMMU */ + iommu = qdev_create(NULL, TYPE_SUN4U_IOMMU); + qdev_init_nofail(iommu); + /* set up devices */ ram_init(0, machine->ram_size); @@ -487,6 +491,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, apb = APB_DEVICE(qdev_create(NULL, TYPE_APB)); qdev_prop_set_uint64(DEVICE(apb), "special-base", APB_SPECIAL_BASE); qdev_prop_set_uint64(DEVICE(apb), "mem-base", APB_MEM_BASE); + object_property_set_link(OBJECT(apb), OBJECT(iommu), "iommu", &error_abort); qdev_init_nofail(DEVICE(apb)); /* Wire up PCI interrupts to CPU */ diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index 6194c8cbad..33dbc7a8cb 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -44,12 +44,18 @@ #define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL typedef struct IOMMUState { + SysBusDevice parent_obj; + AddressSpace iommu_as; IOMMUMemoryRegion iommu; + MemoryRegion iomem; uint64_t regs[IOMMU_NREGS]; } IOMMUState; +#define TYPE_SUN4U_IOMMU "sun4u-iommu" +#define SUN4U_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4U_IOMMU) + #define MAX_IVEC 0x40 /* OBIO IVEC IRQs */ @@ -78,7 +84,7 @@ typedef struct APBState { MemoryRegion pci_mmio; MemoryRegion pci_ioport; uint64_t pci_irq_in; - IOMMUState iommu; + IOMMUState *iommu; PCIBridge *bridgeA; PCIBridge *bridgeB; uint32_t pci_control[16]; -- GitLab