diff options
Diffstat (limited to 'hw/ppc/e500.c')
-rw-r--r-- | hw/ppc/e500.c | 125 |
1 files changed, 103 insertions, 22 deletions
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index c9ae51211e..38f799031a 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -472,6 +472,107 @@ static void ppce500_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env); } +static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, + qemu_irq **irqs) +{ + DeviceState *dev; + SysBusDevice *s; + int i, j, k; + + dev = qdev_create(NULL, TYPE_OPENPIC); + 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); + + k = 0; + for (i = 0; i < smp_cpus; i++) { + for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { + sysbus_connect_irq(s, k++, irqs[i][j]); + } + } + + 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, TYPE_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); + + return mpic; +} + void ppce500_init(PPCE500Params *params) { MemoryRegion *address_space_mem = get_system_memory(); @@ -487,7 +588,7 @@ void ppce500_init(PPCE500Params *params) target_ulong initrd_base = 0; target_long initrd_size = 0; target_ulong cur_base = 0; - int i = 0, j, k; + int i; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; qemu_irq **irqs, *mpic; DeviceState *dev; @@ -563,27 +664,7 @@ void ppce500_init(PPCE500Params *params) memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, ccsr_addr_space); - /* MPIC */ - 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_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - k = 0; - for (i = 0; i < smp_cpus; i++) { - for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { - sysbus_connect_irq(s, k++, irqs[i][j]); - } - } - - for (i = 0; i < 256; i++) { - mpic[i] = qdev_get_gpio_in(dev, i); - } - - memory_region_add_subregion(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET, - s->mmio[0].memory); + mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); /* Serial */ if (serial_hds[0]) { |