summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell2014-06-06 00:05:07 +0200
committerPeter Maydell2014-06-06 00:05:07 +0200
commit50809c8b9288a9bfe1fdec926b7ef985608a7ea6 (patch)
treea3110c29be93ca8ffa24b46c53bf046773913764 /hw
parentMerge remote-tracking branch 'remotes/mdroth/qga-pull-2014-06-05' into staging (diff)
parentapb: implement IOMMU translation for PCI host bridge (diff)
downloadqemu-50809c8b9288a9bfe1fdec926b7ef985608a7ea6.tar.gz
qemu-50809c8b9288a9bfe1fdec926b7ef985608a7ea6.tar.xz
qemu-50809c8b9288a9bfe1fdec926b7ef985608a7ea6.zip
Merge remote-tracking branch 'remotes/mcayland/qemu-sparc' into staging
* remotes/mcayland/qemu-sparc: apb: implement IOMMU translation for PCI host bridge apb: handle reading/writing of IOMMU control registers apb: fix IOMMU register sizes apb: Move IOMMU registers into a separate IOMMUState struct tcx: move initialisation from realizefn to initfn tcx: move initialisation from SysBusDevice class to TCX class realizefn cg3: add extra check to prevent CG3 register array overflow cg3: move initialisation from realizefn to initfn Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/display/cg3.c27
-rw-r--r--hw/display/tcx.c64
-rw-r--r--hw/pci-host/apb.c288
-rw-r--r--hw/sparc/sun4m.c10
4 files changed, 336 insertions, 53 deletions
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index f5a8299e5e..65ef7a7fe6 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -177,7 +177,7 @@ static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
/* monitor ID 6, board type = 1 (color) */
val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
break;
- case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1:
val = s->regs[addr - 0x10];
break;
default:
@@ -247,7 +247,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
qemu_irq_lower(s->irq);
}
break;
- case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1:
s->regs[addr - 0x10] = val;
break;
default:
@@ -274,6 +274,20 @@ static const GraphicHwOps cg3_ops = {
.gfx_update = cg3_update_display,
};
+static void cg3_initfn(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ CG3State *s = CG3(obj);
+
+ memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
+ memory_region_set_readonly(&s->rom, true);
+ sysbus_init_mmio(sbd, &s->rom);
+
+ memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
+ CG3_REG_SIZE);
+ sysbus_init_mmio(sbd, &s->reg);
+}
+
static void cg3_realizefn(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
@@ -282,11 +296,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
char *fcode_filename;
/* FCode ROM */
- memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
vmstate_register_ram_global(&s->rom);
- memory_region_set_readonly(&s->rom, true);
- sysbus_init_mmio(sbd, &s->rom);
-
fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
if (fcode_filename) {
ret = load_image_targphys(fcode_filename, s->prom_addr,
@@ -296,10 +306,6 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
}
}
- memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
- CG3_REG_SIZE);
- sysbus_init_mmio(sbd, &s->reg);
-
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
vmstate_register_ram_global(&s->vram_mem);
sysbus_init_mmio(sbd, &s->vram_mem);
@@ -374,6 +380,7 @@ static const TypeInfo cg3_info = {
.name = TYPE_CG3,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(CG3State),
+ .instance_init = cg3_initfn,
.class_init = cg3_class_init,
};
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 2551b677aa..28c742cc24 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -530,8 +530,36 @@ static const GraphicHwOps tcx24_ops = {
.gfx_update = tcx24_update_display,
};
-static int tcx_init1(SysBusDevice *dev)
+static void tcx_initfn(Object *obj)
{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ TCXState *s = TCX(obj);
+
+ memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE);
+ memory_region_set_readonly(&s->rom, true);
+ sysbus_init_mmio(sbd, &s->rom);
+
+ /* DAC */
+ memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s,
+ "tcx.dac", TCX_DAC_NREGS);
+ sysbus_init_mmio(sbd, &s->dac);
+
+ /* TEC (dummy) */
+ memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s,
+ "tcx.tec", TCX_TEC_NREGS);
+ sysbus_init_mmio(sbd, &s->tec);
+
+ /* THC: NetBSD writes here even with 8-bit display: dummy */
+ memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24",
+ TCX_THC_NREGS_24);
+ sysbus_init_mmio(sbd, &s->thc24);
+
+ return;
+}
+
+static void tcx_realizefn(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
TCXState *s = TCX(dev);
ram_addr_t vram_offset = 0;
int size, ret;
@@ -544,18 +572,13 @@ static int tcx_init1(SysBusDevice *dev)
vram_base = memory_region_get_ram_ptr(&s->vram_mem);
/* FCode ROM */
- memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE);
vmstate_register_ram_global(&s->rom);
- memory_region_set_readonly(&s->rom, true);
- sysbus_init_mmio(dev, &s->rom);
-
fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE);
if (fcode_filename) {
ret = load_image_targphys(fcode_filename, s->prom_addr,
FCODE_MAX_ROM_SIZE);
if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
- fprintf(stderr, "tcx: could not load prom '%s'\n", TCX_ROM_FILE);
- return -1;
+ error_report("tcx: could not load prom '%s'", TCX_ROM_FILE);
}
}
@@ -564,24 +587,10 @@ static int tcx_init1(SysBusDevice *dev)
size = s->vram_size;
memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit",
&s->vram_mem, vram_offset, size);
- sysbus_init_mmio(dev, &s->vram_8bit);
+ sysbus_init_mmio(sbd, &s->vram_8bit);
vram_offset += size;
vram_base += size;
- /* DAC */
- memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s,
- "tcx.dac", TCX_DAC_NREGS);
- sysbus_init_mmio(dev, &s->dac);
-
- /* TEC (dummy) */
- memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s,
- "tcx.tec", TCX_TEC_NREGS);
- sysbus_init_mmio(dev, &s->tec);
- /* THC: NetBSD writes here even with 8-bit display: dummy */
- memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24",
- TCX_THC_NREGS_24);
- sysbus_init_mmio(dev, &s->thc24);
-
if (s->depth == 24) {
/* 24-bit plane */
size = s->vram_size * 4;
@@ -589,7 +598,7 @@ static int tcx_init1(SysBusDevice *dev)
s->vram24_offset = vram_offset;
memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit",
&s->vram_mem, vram_offset, size);
- sysbus_init_mmio(dev, &s->vram_24bit);
+ sysbus_init_mmio(sbd, &s->vram_24bit);
vram_offset += size;
vram_base += size;
@@ -599,20 +608,19 @@ static int tcx_init1(SysBusDevice *dev)
s->cplane_offset = vram_offset;
memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane",
&s->vram_mem, vram_offset, size);
- sysbus_init_mmio(dev, &s->vram_cplane);
+ sysbus_init_mmio(sbd, &s->vram_cplane);
s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
} else {
/* THC 8 bit (dummy) */
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
TCX_THC_NREGS_8);
- sysbus_init_mmio(dev, &s->thc8);
+ sysbus_init_mmio(sbd, &s->thc8);
s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
}
qemu_console_resize(s->con, s->width, s->height);
- return 0;
}
static Property tcx_properties[] = {
@@ -627,9 +635,8 @@ static Property tcx_properties[] = {
static void tcx_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = tcx_init1;
+ dc->realize = tcx_realizefn;
dc->reset = tcx_reset;
dc->vmsd = &vmstate_tcx;
dc->props = tcx_properties;
@@ -639,6 +646,7 @@ static const TypeInfo tcx_info = {
.name = TYPE_TCX,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(TCXState),
+ .instance_init = tcx_initfn,
.class_init = tcx_class_init,
};
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index 252caefda7..1497008258 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -46,6 +46,16 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
#define APB_DPRINTF(fmt, ...)
#endif
+/* debug IOMMU */
+//#define DEBUG_IOMMU
+
+#ifdef DEBUG_IOMMU
+#define IOMMU_DPRINTF(fmt, ...) \
+do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define IOMMU_DPRINTF(fmt, ...)
+#endif
+
/*
* Chipset docs:
* PBM: "UltraSPARC IIi User's Manual",
@@ -70,6 +80,51 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
#define MAX_IVEC 0x40
#define NO_IRQ_REQUEST (MAX_IVEC + 1)
+#define IOMMU_PAGE_SIZE_8K (1ULL << 13)
+#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
+#define IOMMU_PAGE_SIZE_64K (1ULL << 16)
+#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
+
+#define IOMMU_NREGS 3
+
+#define IOMMU_CTRL 0x0
+#define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
+#define IOMMU_CTRL_MMU_EN (1ULL)
+
+#define IOMMU_CTRL_TSB_SHIFT 16
+
+#define IOMMU_BASE 0x8
+
+#define IOMMU_TTE_DATA_V (1ULL << 63)
+#define IOMMU_TTE_DATA_SIZE (1ULL << 61)
+#define IOMMU_TTE_DATA_W (1ULL << 1)
+
+#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000
+#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000
+
+#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
+
+#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
+
+typedef struct IOMMUState {
+ AddressSpace iommu_as;
+ MemoryRegion iommu;
+
+ uint64_t regs[IOMMU_NREGS];
+} IOMMUState;
+
#define TYPE_APB "pbm"
#define APB_DEVICE(obj) \
@@ -83,7 +138,7 @@ typedef struct APBState {
MemoryRegion pci_mmio;
MemoryRegion pci_ioport;
uint64_t pci_irq_in;
- uint32_t iommu[4];
+ IOMMUState iommu;
uint32_t pci_control[16];
uint32_t pci_irq_map[8];
uint32_t obio_irq_map[32];
@@ -141,10 +196,217 @@ static inline void pbm_clear_request(APBState *s, unsigned int irq_num)
s->irq_request = NO_IRQ_REQUEST;
}
+static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+ IOMMUState *is = opaque;
+
+ return &is->iommu_as;
+}
+
+static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr)
+{
+ IOMMUState *is = container_of(iommu, IOMMUState, iommu);
+ hwaddr baseaddr, offset;
+ uint64_t tte;
+ uint32_t tsbsize;
+ IOMMUTLBEntry ret = {
+ .target_as = &address_space_memory,
+ .iova = 0,
+ .translated_addr = 0,
+ .addr_mask = ~(hwaddr)0,
+ .perm = IOMMU_NONE,
+ };
+
+ if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) {
+ /* IOMMU disabled, passthrough using standard 8K page */
+ ret.iova = addr & IOMMU_PAGE_MASK_8K;
+ ret.translated_addr = addr;
+ ret.addr_mask = IOMMU_PAGE_MASK_8K;
+ ret.perm = IOMMU_RW;
+
+ return ret;
+ }
+
+ baseaddr = is->regs[IOMMU_BASE >> 3];
+ tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7;
+
+ if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) {
+ /* 64K */
+ switch (tsbsize) {
+ case 0:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13;
+ break;
+ case 1:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13;
+ break;
+ case 2:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13;
+ break;
+ case 3:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13;
+ break;
+ case 4:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13;
+ break;
+ case 5:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13;
+ break;
+ default:
+ /* Not implemented, error */
+ return ret;
+ }
+ } else {
+ /* 8K */
+ switch (tsbsize) {
+ case 0:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10;
+ break;
+ case 1:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10;
+ break;
+ case 2:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10;
+ break;
+ case 3:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10;
+ break;
+ case 4:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10;
+ break;
+ case 5:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10;
+ break;
+ case 6:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10;
+ break;
+ case 7:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10;
+ break;
+ }
+ }
+
+ tte = ldq_be_phys(&address_space_memory, baseaddr + offset);
+
+ if (!(tte & IOMMU_TTE_DATA_V)) {
+ /* Invalid mapping */
+ return ret;
+ }
+
+ if (tte & IOMMU_TTE_DATA_W) {
+ /* Writeable */
+ ret.perm = IOMMU_RW;
+ } else {
+ ret.perm = IOMMU_RO;
+ }
+
+ /* Extract phys */
+ if (tte & IOMMU_TTE_DATA_SIZE) {
+ /* 64K */
+ ret.iova = addr & IOMMU_PAGE_MASK_64K;
+ ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K;
+ ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1);
+ } else {
+ /* 8K */
+ ret.iova = addr & IOMMU_PAGE_MASK_8K;
+ ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K;
+ ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1);
+ }
+
+ return ret;
+}
+
+static MemoryRegionIOMMUOps pbm_iommu_ops = {
+ .translate = pbm_translate_iommu,
+};
+
+static void iommu_config_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ IOMMUState *is = opaque;
+
+ IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64
+ " size: %d\n", addr, val, size);
+
+ switch (addr) {
+ case IOMMU_CTRL:
+ if (size == 4) {
+ is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL;
+ is->regs[IOMMU_CTRL >> 3] |= val << 32;
+ } else {
+ is->regs[IOMMU_CTRL] = val;
+ }
+ break;
+ case IOMMU_CTRL + 0x4:
+ is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL;
+ is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL;
+ break;
+ case IOMMU_BASE:
+ if (size == 4) {
+ is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL;
+ is->regs[IOMMU_BASE >> 3] |= val << 32;
+ } else {
+ is->regs[IOMMU_BASE] = val;
+ }
+ break;
+ case IOMMU_BASE + 0x4:
+ is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
+ is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "apb iommu: Unimplemented register write "
+ "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
+ addr, size, val);
+ break;
+ }
+}
+
+static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IOMMUState *is = opaque;
+ uint64_t val;
+
+ switch (addr) {
+ case IOMMU_CTRL:
+ if (size == 4) {
+ val = is->regs[IOMMU_CTRL >> 3] >> 32;
+ } else {
+ val = is->regs[IOMMU_CTRL >> 3];
+ }
+ break;
+ case IOMMU_CTRL + 0x4:
+ val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL;
+ break;
+ case IOMMU_BASE:
+ if (size == 4) {
+ val = is->regs[IOMMU_BASE >> 3] >> 32;
+ } else {
+ val = is->regs[IOMMU_BASE >> 3];
+ }
+ break;
+ case IOMMU_BASE + 0x4:
+ val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "apb iommu: Unimplemented register read "
+ "reg 0x%" HWADDR_PRIx " size 0x%x\n",
+ addr, size);
+ val = 0;
+ break;
+ }
+
+ IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64
+ " size: %d\n", addr, val, size);
+
+ return val;
+}
+
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);
@@ -152,10 +414,8 @@ static void apb_config_writel (void *opaque, hwaddr addr,
case 0x30 ... 0x4f: /* DMA error registers */
/* XXX: not implemented yet */
break;
- case 0x200 ... 0x20b: /* IOMMU */
- s->iommu[(addr & 0xf) >> 2] = val;
- break;
- case 0x20c ... 0x3ff: /* IOMMU flush */
+ case 0x200 ... 0x217: /* IOMMU */
+ iommu_config_write(is, (addr & 0xf), val, size);
break;
case 0xc00 ... 0xc3f: /* PCI interrupt control */
if (addr & 4) {
@@ -228,6 +488,7 @@ 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) {
@@ -235,11 +496,8 @@ static uint64_t apb_config_readl (void *opaque,
val = 0;
/* XXX: not implemented yet */
break;
- case 0x200 ... 0x20b: /* IOMMU */
- val = s->iommu[(addr & 0xf) >> 2];
- break;
- case 0x20c ... 0x3ff: /* IOMMU flush */
- val = 0;
+ case 0x200 ... 0x217: /* IOMMU */
+ val = iommu_config_read(is, (addr & 0xf), size);
break;
case 0xc00 ... 0xc3f: /* PCI interrupt control */
if (addr & 4) {
@@ -390,6 +648,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
SysBusDevice *s;
PCIHostState *phb;
APBState *d;
+ IOMMUState *is;
PCIDevice *pci_dev;
PCIBridge *br;
@@ -420,6 +679,15 @@ PCIBus *pci_apb_init(hwaddr special_base,
pci_create_simple(phb->bus, 0, "pbm-pci");
+ /* APB IOMMU */
+ is = &d->iommu;
+ memset(is, 0, sizeof(IOMMUState));
+
+ memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops,
+ "iommu-apb", UINT64_MAX);
+ address_space_init(&is->iommu_as, &is->iommu, "pbm-as");
+ pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
+
/* APB secondary busses */
pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
"pbm-bridge");
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 4e793c2760..67e3663bfd 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -543,14 +543,14 @@ static void tcx_init(hwaddr addr, int vram_size, int width,
s = SYS_BUS_DEVICE(dev);
/* FCode ROM */
sysbus_mmio_map(s, 0, addr);
- /* 8-bit plane */
- sysbus_mmio_map(s, 1, addr + 0x00800000ULL);
/* DAC */
- sysbus_mmio_map(s, 2, addr + 0x00200000ULL);
+ sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
/* TEC (dummy) */
- sysbus_mmio_map(s, 3, addr + 0x00700000ULL);
+ sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
/* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
- sysbus_mmio_map(s, 4, addr + 0x00301000ULL);
+ sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
+ /* 8-bit plane */
+ sysbus_mmio_map(s, 4, addr + 0x00800000ULL);
if (depth == 24) {
/* 24-bit plane */
sysbus_mmio_map(s, 5, addr + 0x02000000ULL);