aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_vio.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/spapr_vio.c')
-rw-r--r--hw/ppc/spapr_vio.c47
1 files changed, 36 insertions, 11 deletions
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 032ee1a5f1..1360b97ab0 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -322,6 +322,18 @@ static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
free_crq(dev);
}
+void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass)
+{
+ if (!dev->tcet) {
+ return;
+ }
+
+ memory_region_set_enabled(&dev->mrbypass, bypass);
+ memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass);
+
+ dev->tcet->bypass = bypass;
+}
+
static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
@@ -348,7 +360,7 @@ static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return;
}
- spapr_tce_set_bypass(dev->tcet, !!enable);
+ spapr_vio_set_bypass(dev, !!enable);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
@@ -407,12 +419,13 @@ static void spapr_vio_busdev_reset(DeviceState *qdev)
dev->signal_state = 0;
+ spapr_vio_set_bypass(dev, false);
if (pc->reset) {
pc->reset(dev);
}
}
-static int spapr_vio_busdev_init(DeviceState *qdev)
+static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
{
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
@@ -428,11 +441,11 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
VIOsPAPRDevice *other = reg_conflict(dev);
if (other) {
- fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
- object_get_typename(OBJECT(qdev)),
- object_get_typename(OBJECT(&other->qdev)),
- dev->reg);
- return -1;
+ error_setg(errp, "%s and %s devices conflict at address %#x",
+ object_get_typename(OBJECT(qdev)),
+ object_get_typename(OBJECT(&other->qdev)),
+ dev->reg);
+ return;
}
} else {
/* Need to assign an address */
@@ -451,20 +464,32 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false);
if (!dev->irq) {
- return -1;
+ error_setg(errp, "can't allocate IRQ");
+ return;
}
if (pc->rtce_window_size) {
uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
+
+ memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root",
+ ram_size);
+ memory_region_init_alias(&dev->mrbypass, OBJECT(dev),
+ "iommu-spapr-bypass", get_system_memory(),
+ 0, ram_size);
+ memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1);
+ address_space_init(&dev->as, &dev->mrroot, qdev->id);
+
dev->tcet = spapr_tce_new_table(qdev, liobn,
0,
SPAPR_TCE_PAGE_SHIFT,
pc->rtce_window_size >>
SPAPR_TCE_PAGE_SHIFT, false);
- address_space_init(&dev->as, spapr_tce_get_iommu(dev->tcet), qdev->id);
+ dev->tcet->vdev = dev;
+ memory_region_add_subregion_overlap(&dev->mrroot, 0,
+ spapr_tce_get_iommu(dev->tcet), 2);
}
- return pc->init(dev);
+ pc->realize(dev, errp);
}
static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@@ -570,7 +595,7 @@ const VMStateDescription vmstate_spapr_vio = {
static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
- k->init = spapr_vio_busdev_init;
+ k->realize = spapr_vio_busdev_realize;
k->reset = spapr_vio_busdev_reset;
k->bus_type = TYPE_SPAPR_VIO_BUS;
k->props = spapr_vio_props;