diff options
author | Scott Wood <scottwood@freescale.com> | 2013-06-12 15:32:51 -0500 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-07-01 01:11:14 +0200 |
commit | d85937e683f6ff4d68293cb24c780fb1f6820d2c (patch) | |
tree | d5e22e6fe43fcb1d004d39d3974241e8fd1d7aa7 /hw/ppc | |
parent | 4be1db86060d803f2335c08a483218eb6a8bd9eb (diff) |
kvm/openpic: in-kernel mpic support
Enables support for the in-kernel MPIC that thas been merged into the
KVM next branch. This includes irqfd/KVM_IRQ_LINE support from Alex
Graf (along with some other improvements).
Note from Alex regarding kvm_irqchip_create():
On x86, one would call kvm_irqchip_create() to initialize an
in-kernel interrupt controller. That function then goes ahead and
initializes global capability variables as well as the default irq
routing table.
On ppc, we can't call kvm_irqchip_create() because we can have
different types of interrupt controllers. So we want to do all the
things that function would do for us in the in-kernel device init
handler.
Signed-off-by: Scott Wood <scottwood@freescale.com>
[agraf: squash in kvm_irqchip_commit_routes patch, fix non-kvm build,
fix ppcemb]
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/e500.c | 79 |
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); |