aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc')
-rw-r--r--hw/ppc/e500.c79
1 files changed, 74 insertions, 5 deletions
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 2d57b29286..d38a688fa1 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -472,18 +472,17 @@ static void ppce500_cpu_reset(void *opaque)
mmubooke_create_initial_mapping(env);
}
-static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
- qemu_irq **irqs)
+static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
+ qemu_irq **irqs)
{
- qemu_irq *mpic;
DeviceState *dev;
SysBusDevice *s;
int i, j, k;
- mpic = g_new(qemu_irq, 256);
dev = qdev_create(NULL, "openpic");
- qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
qdev_prop_set_uint32(dev, "model", params->mpic_version);
+ qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
+
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
@@ -494,10 +493,80 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
}
}
+ return dev;
+}
+
+static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
+ qemu_irq **irqs)
+{
+ DeviceState *dev;
+ CPUPPCState *env;
+ CPUState *cs;
+ int r;
+
+ dev = qdev_create(NULL, "kvm-openpic");
+ qdev_prop_set_uint32(dev, "model", params->mpic_version);
+
+ r = qdev_init(dev);
+ if (r) {
+ return NULL;
+ }
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cs = ENV_GET_CPU(env);
+
+ if (kvm_openpic_connect_vcpu(dev, cs)) {
+ fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
+ __func__);
+ abort();
+ }
+ }
+
+ return dev;
+}
+
+static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
+ qemu_irq **irqs)
+{
+ QemuOptsList *list;
+ qemu_irq *mpic;
+ DeviceState *dev = NULL;
+ SysBusDevice *s;
+ int i;
+
+ mpic = g_new(qemu_irq, 256);
+
+ if (kvm_enabled()) {
+ bool irqchip_allowed = true, irqchip_required = false;
+
+ list = qemu_find_opts("machine");
+ if (!QTAILQ_EMPTY(&list->head)) {
+ irqchip_allowed = qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+ "kernel_irqchip", true);
+ irqchip_required = qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+ "kernel_irqchip", false);
+ }
+
+ if (irqchip_allowed) {
+ dev = ppce500_init_mpic_kvm(params, irqs);
+ }
+
+ if (irqchip_required && !dev) {
+ fprintf(stderr, "%s: irqchip requested but unavailable\n",
+ __func__);
+ abort();
+ }
+ }
+
+ if (!dev) {
+ dev = ppce500_init_mpic_qemu(params, irqs);
+ }
+
for (i = 0; i < 256; i++) {
mpic[i] = qdev_get_gpio_in(dev, i);
}
+ s = SYS_BUS_DEVICE(dev);
memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
s->mmio[0].memory);