From patchwork Thu Jul 2 14:14:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Fedin X-Patchwork-Id: 490660 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4999B140081 for ; Fri, 3 Jul 2015 00:22:22 +1000 (AEST) Received: from localhost ([::1]:36883 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZAfNc-0000DQ-DJ for incoming@patchwork.ozlabs.org; Thu, 02 Jul 2015 10:22:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36688) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZAfFq-0003lO-VV for qemu-devel@nongnu.org; Thu, 02 Jul 2015 10:14:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZAfFm-0003QO-Cj for qemu-devel@nongnu.org; Thu, 02 Jul 2015 10:14:18 -0400 Received: from mailout4.w1.samsung.com ([210.118.77.14]:32463) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZAfFl-0003Mc-Tj for qemu-devel@nongnu.org; Thu, 02 Jul 2015 10:14:14 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NQV00DA567NRTB0@mailout4.w1.samsung.com> for qemu-devel@nongnu.org; Thu, 02 Jul 2015 15:14:11 +0100 (BST) X-AuditID: cbfec7f4-f79c56d0000012ee-45-559547331f0e Received: from eusync2.samsung.com ( [203.254.199.212]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 82.35.04846.33745955; Thu, 2 Jul 2015 15:14:11 +0100 (BST) Received: from localhost ([106.109.131.169]) by eusync2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0NQV00MRO67NLF80@eusync2.samsung.com>; Thu, 02 Jul 2015 15:14:11 +0100 (BST) From: Pavel Fedin To: qemu-devel@nongnu.org Date: Thu, 02 Jul 2015 17:14:02 +0300 Message-id: <7301d5cb99fe7d96090333fc697c8b1b2d6514a6.1435844519.git.p.fedin@samsung.com> X-Mailer: git-send-email 1.9.5.msysgit.0 In-reply-to: References: In-reply-to: References: X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpjluLIzCtJLcpLzFFi42I5/e/4FV1j96mhBrsfGlnMOfOAxeJ47w4W ByaPO9f2sHk8ubaZKYApissmJTUnsyy1SN8ugSvj+K4v7AWvMitmfbzP1MA4z6+LkZNDQsBE 4uL9JawQtpjEhXvr2boYuTiEBJYySmx8tIwdwvnGKPHoD0QVm4C6xOmvH1hAbBEBSYnfXaeZ QYqYBR4xSlxrO8cMkhAWsJV482M+mM0ioCrRs2ExmM0rEC3xdcMkqHUaEou+zGEDsTkFzCWu P21iB7GFBMwkDt5sY8QlPoGRfwEjwypG0dTS5ILipPRcQ73ixNzi0rx0veT83E2MkND5soNx 8TGrQ4wCHIxKPLwraqaECrEmlhVX5h5ilOBgVhLh3WI5NVSINyWxsiq1KD++qDQntfgQozQH i5I479xd70OEBNITS1KzU1MLUotgskwcnFINjKVPTbunbprVcmyKT3DJtk3+q4/cmvGoIDKx fpGfUeqqpomp98s3f1nzrEXoyA8ZR/ujYR6yluqGs761/XxTosWwYmGu0FmzGXfUFY5NcAhQ 3fr5urLoGbnfuw94av2Y7noop/J8gueasIgtQS89TUXkhbZM3JQY8uzXX7Oz+jFrLc5ISV2J y1JiKc5INNRiLipOBAC5oLPKGQIAAA== X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 210.118.77.14 Cc: Peter Maydell , Shlomo Pongratz , Shlomo Pongratz , Christoffer Dall , Eric Auger Subject: [Qemu-devel] [PATCH v4 4/9] Add virt-v3 machine that uses GIC-500 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Instead of adding gic-version option, it is much easier to create a new machine type. The problem is mc->max_cpus. I tried to change this value inside property handling code, but it simply did not work, and i still got " Maximum CPUs greater than specified machine type limit" error from qemu. It looks like CPU number limitation is evaluated before machine is instantiated and properties are evaluated. It is possible to make a workaround, of course, but it seems to require much more changes than simply subclassing a machine. This patch also introduces kernel_irqchip_type member in Machine class. Currently it it used only by virt machine for its internal purposes, however in future it is to be passed to KVM in kvm_irqchip_create(). The variable is defined as int in order to be architecture agnostic, for potential future users. Signed-off-by: Pavel Fedin --- hw/arm/virt.c | 141 ++++++++++++++++++++++++++++++++++++++++++-------- include/hw/arm/fdt.h | 2 +- include/hw/arm/virt.h | 6 ++- include/hw/boards.h | 1 + 4 files changed, 126 insertions(+), 24 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 4846892..5c07d07 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -48,6 +48,7 @@ #include "hw/arm/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/arm/fdt.h" +#include "linux/kvm.h" /* For KVM_DEV_TYPE_ARM_VGIC_V{2|3} */ /* Number of external interrupt lines to configure the GIC with */ #define NUM_IRQS 256 @@ -67,6 +68,7 @@ typedef struct VirtBoardInfo { uint32_t clock_phandle; uint32_t gic_phandle; uint32_t v2m_phandle; + const char *class_name; } VirtBoardInfo; typedef struct { @@ -80,6 +82,7 @@ typedef struct { } VirtMachineState; #define TYPE_VIRT_MACHINE "virt" +#define TYPE_VIRTV3_MACHINE "virt-v3" #define VIRT_MACHINE(obj) \ OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) #define VIRT_MACHINE_GET_CLASS(obj) \ @@ -106,7 +109,12 @@ static const MemMapEntry a15memmap[] = { /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, - [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, + [VIRT_GIC_V2M] = { 0x08020000, 0x00010000 }, + /* On v3 VIRT_GIC_DIST_MBI and VIRT_ITS_CONTROL take place of + * VIRT_GIC_CPU and VIRT_GIC_V2M respectively + */ + [VIRT_ITS_TRANSLATION] = { 0x08030000, 0x00010000 }, + [VIRT_LPI] = { 0x08040000, 0x00800000 }, [VIRT_UART] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 }, [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, @@ -138,16 +146,25 @@ static VirtBoardInfo machines[] = { .cpu_model = "cortex-a53", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_ARM_CPU, + }, + { + .cpu_model = "cortex-a53", + .memmap = a15memmap, + .irqmap = a15irqmap, + .class_name = TYPE_AARCH64_CPU, }, { .cpu_model = "cortex-a57", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_AARCH64_CPU, }, { .cpu_model = "host", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_ARM_CPU, }, }; @@ -256,10 +271,13 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) * they are edge-triggered. */ ARMCPU *armcpu; + uint32_t max; uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; + /* Argument is 32 bit but 8 bits are reserved for flags */ + max = (vbi->smp_cpus >= 24) ? 24 : vbi->smp_cpus; irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, - GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1); + GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << max) - 1); qemu_fdt_add_subnode(vbi->fdt, "/timer"); @@ -283,6 +301,18 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) { int cpu; + /* + * From Documentation/devicetree/bindings/arm/cpus.txt + * On ARM v8 64-bit systems value should be set to 2, + * that corresponds to the MPIDR_EL1 register size. + * If MPIDR_EL1[63:32] value is equal to 0 on all CPUs + * in the system, #address-cells can be set to 1, since + * MPIDR_EL1[63:32] bits are not used for CPUs + * identification. + * + * Now GIC500 doesn't support affinities 2 & 3 so currently + * #address-cells can stay 1 until future GIC + */ qemu_fdt_add_subnode(vbi->fdt, "/cpus"); qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1); qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); @@ -319,25 +349,36 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle); } -static void fdt_add_gic_node(VirtBoardInfo *vbi) +static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) { vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle); qemu_fdt_add_subnode(vbi->fdt, "/intc"); - /* 'cortex-a15-gic' means 'GIC v2' */ - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", - "arm,cortex-a15-gic"); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_CPU].base, - 2, vbi->memmap[VIRT_GIC_CPU].size); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2); qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0); + if (type == KVM_DEV_TYPE_ARM_VGIC_V3) { + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + "arm,gic-v3"); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", + 2, vbi->memmap[VIRT_GIC_DIST].base, + 2, vbi->memmap[VIRT_GIC_DIST].size, + 2, vbi->memmap[VIRT_LPI].base, + 2, vbi->memmap[VIRT_LPI].size); + } else { + /* 'cortex-a15-gic' means 'GIC v2' */ + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + "arm,cortex-a15-gic"); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", + 2, vbi->memmap[VIRT_GIC_DIST].base, + 2, vbi->memmap[VIRT_GIC_DIST].size, + 2, vbi->memmap[VIRT_GIC_CPU].base, + 2, vbi->memmap[VIRT_GIC_CPU].size); + } + qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); } @@ -360,20 +401,32 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) fdt_add_v2m_gic_node(vbi); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type) { /* We create a standalone GIC v2 */ DeviceState *gicdev; SysBusDevice *gicbusdev; - const char *gictype = "arm_gic"; + const char *gictype; int i; - if (kvm_irqchip_in_kernel()) { + if (type == KVM_DEV_TYPE_ARM_VGIC_V3) { + gictype = "arm_gicv3"; + } else if (kvm_irqchip_in_kernel()) { gictype = "kvm-arm-gic"; + } else { + gictype = "arm_gic"; } gicdev = qdev_create(NULL, gictype); - qdev_prop_set_uint32(gicdev, "revision", 2); + + for (i = 0; i < vbi->smp_cpus; i++) { + CPUState *cpu = qemu_get_cpu(i); + CPUARMState *env = cpu->env_ptr; + env->nvic = gicdev; + } + + qdev_prop_set_uint32(gicdev, "revision", + type == KVM_DEV_TYPE_ARM_VGIC_V3 ? 3 : 2); qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); /* Note that the num-irq property counts both internal and external * interrupts; there are always 32 of the former (mandated by GIC spec). @@ -383,6 +436,11 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) gicbusdev = SYS_BUS_DEVICE(gicdev); sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + if (type == KVM_DEV_TYPE_ARM_VGIC_V3) { + sysbus_mmio_map(gicbusdev, 2, vbi->memmap[VIRT_ITS_CONTROL].base); + sysbus_mmio_map(gicbusdev, 3, vbi->memmap[VIRT_ITS_TRANSLATION].base); + sysbus_mmio_map(gicbusdev, 4, vbi->memmap[VIRT_LPI].base); + } /* Wire the outputs from each CPU's generic timer to the * appropriate GIC PPI inputs, and the GIC's IRQ output to @@ -409,9 +467,11 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) pic[i] = qdev_get_gpio_in(gicdev, i); } - fdt_add_gic_node(vbi); + fdt_add_gic_node(vbi, type); - create_v2m(vbi, pic); + if (type == KVM_DEV_TYPE_ARM_VGIC_V2) { + create_v2m(vbi, pic); + } } static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) @@ -825,7 +885,7 @@ static void machvirt_init(MachineState *machine) create_fdt(vbi); for (n = 0; n < smp_cpus; n++) { - ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); + ObjectClass *oc = cpu_class_by_name(vbi->class_name, cpustr[0]); CPUClass *cc = CPU_CLASS(oc); Object *cpuobj; Error *err = NULL; @@ -875,7 +935,7 @@ static void machvirt_init(MachineState *machine) create_flash(vbi); - create_gic(vbi, pic); + create_gic(vbi, pic, machine->kernel_irqchip_type); create_uart(vbi, pic); @@ -933,7 +993,7 @@ static void virt_set_secure(Object *obj, bool value, Error **errp) vms->secure = value; } -static void virt_instance_init(Object *obj) +static void virt_instance_init_common(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -947,6 +1007,14 @@ static void virt_instance_init(Object *obj) NULL); } +static void virt_instance_init(Object *obj) +{ + MachineState *ms = MACHINE(obj); + + ms->kernel_irqchip_type = KVM_DEV_TYPE_ARM_VGIC_V2; + virt_instance_init_common(obj); +} + static void virt_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -969,9 +1037,38 @@ static const TypeInfo machvirt_info = { .class_init = virt_class_init, }; +static void virtv3_instance_init(Object *obj) +{ + MachineState *ms = MACHINE(obj); + + ms->kernel_irqchip_type = KVM_DEV_TYPE_ARM_VGIC_V3; + virt_instance_init_common(obj); +} + +static void virtv3_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->name = TYPE_VIRTV3_MACHINE; + mc->desc = "ARM Virtual Machine with GICv3", + mc->init = machvirt_init; + /* With gic3 full implementation (with bitops) rase the lmit to 128 */ + mc->max_cpus = 64; +} + +static const TypeInfo machvirtv3_info = { + .name = TYPE_VIRTV3_MACHINE, + .parent = TYPE_VIRT_MACHINE, + .instance_size = sizeof(VirtMachineState), + .instance_init = virtv3_instance_init, + .class_size = sizeof(VirtMachineClass), + .class_init = virtv3_class_init, +}; + static void machvirt_machine_init(void) { type_register_static(&machvirt_info); + type_register_static(&machvirtv3_info); } machine_init(machvirt_machine_init); diff --git a/include/hw/arm/fdt.h b/include/hw/arm/fdt.h index c3d5015..dd794dd 100644 --- a/include/hw/arm/fdt.h +++ b/include/hw/arm/fdt.h @@ -29,6 +29,6 @@ #define GIC_FDT_IRQ_FLAGS_LEVEL_LO 8 #define GIC_FDT_IRQ_PPI_CPU_START 8 -#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8 +#define GIC_FDT_IRQ_PPI_CPU_WIDTH 24 #endif diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index d22fd8e..852efb9 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -46,6 +46,11 @@ enum { VIRT_CPUPERIPHS, VIRT_GIC_DIST, VIRT_GIC_CPU, + VIRT_GIC_V2M, + VIRT_GIC_DIST_MBI = VIRT_GIC_CPU, + VIRT_ITS_CONTROL = VIRT_GIC_V2M, + VIRT_ITS_TRANSLATION, + VIRT_LPI, VIRT_UART, VIRT_MMIO, VIRT_RTC, @@ -54,7 +59,6 @@ enum { VIRT_PCIE_MMIO, VIRT_PCIE_PIO, VIRT_PCIE_ECAM, - VIRT_GIC_V2M, VIRT_PLATFORM_BUS, }; diff --git a/include/hw/boards.h b/include/hw/boards.h index 6379901..6e42cf2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -126,6 +126,7 @@ struct MachineState { char *accel; bool kernel_irqchip_allowed; bool kernel_irqchip_required; + int kernel_irqchip_type; int kvm_shadow_mem; char *dtb; char *dumpdtb;