Add a virtual SPE device for virt machine while using PPI 5 for SPE overflow interrupt number which has already selected in kvmtool for the in-kernel irqchip support.
Reviewed-by: Andrew Jones <drjo...@redhat.com> Signed-off-by: Haibo Xu <haibo...@linaro.org> --- hw/arm/virt-acpi-build.c | 3 +++ hw/arm/virt.c | 43 ++++++++++++++++++++++++++++++++++++- include/hw/acpi/acpi-defs.h | 3 +++ include/hw/arm/virt.h | 1 + target/arm/cpu.c | 2 ++ target/arm/cpu.h | 2 ++ 6 files changed, 53 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 9efd7a3881..3fd80fda53 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -665,6 +665,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); } + if (cpu_isar_feature(aa64_spe, armcpu)) { + gicc->spe_interrupt = cpu_to_le32(PPI(VIRTUAL_SPE_IRQ)); + } if (vms->virt) { gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ)); } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6bacfb668d..ee0831922b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -545,6 +545,32 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) } } +static void fdt_add_spe_nodes(const VirtMachineState *vms) +{ + ARMCPU *armcpu = ARM_CPU(first_cpu); + uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI; + + if (!cpu_isar_feature(aa64_spe, armcpu)) { + assert(!object_property_get_bool(OBJECT(armcpu), "spe", NULL)); + return; + } + + if (vms->gic_version == VIRT_GIC_VERSION_2) { + irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, + GIC_FDT_IRQ_PPI_CPU_WIDTH, + (1 << vms->smp_cpus) - 1); + } + + qemu_fdt_add_subnode(vms->fdt, "/spe"); + if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { + const char compat[] = "arm,statistical-profiling-extension-v1"; + qemu_fdt_setprop(vms->fdt, "/spe", "compatible", + compat, sizeof(compat)); + qemu_fdt_setprop_cells(vms->fdt, "/spe", "interrupts", + GIC_FDT_IRQ_TYPE_PPI, VIRTUAL_SPE_IRQ, irqflags); + } +} + static inline DeviceState *create_acpi_ged(VirtMachineState *vms) { DeviceState *dev; @@ -717,6 +743,10 @@ static void create_gic(VirtMachineState *vms) qdev_get_gpio_in(vms->gic, ppibase + VIRTUAL_PMU_IRQ)); + qdev_connect_gpio_out_named(cpudev, "spe-interrupt", 0, + qdev_get_gpio_in(vms->gic, ppibase + + VIRTUAL_SPE_IRQ)); + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicbusdev, i + smp_cpus, qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); @@ -1664,11 +1694,12 @@ static void finalize_gic_version(VirtMachineState *vms) static void virt_cpu_post_init(VirtMachineState *vms) { - bool aarch64, pmu; + bool aarch64, pmu, spe; CPUState *cpu; aarch64 = object_property_get_bool(OBJECT(first_cpu), "aarch64", NULL); pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL); + spe = object_property_get_bool(OBJECT(first_cpu), "spe", NULL); if (kvm_enabled()) { CPU_FOREACH(cpu) { @@ -1679,6 +1710,14 @@ static void virt_cpu_post_init(VirtMachineState *vms) } kvm_arm_pmu_init(cpu); } + + if (spe) { + assert(ARM_CPU(cpu)->has_spe == ON_OFF_AUTO_ON); + if (kvm_irqchip_in_kernel()) { + kvm_arm_spe_set_irq(cpu, PPI(VIRTUAL_SPE_IRQ)); + kvm_arm_spe_init(cpu); + } + } } } else { if (aarch64 && vms->highmem) { @@ -1927,6 +1966,8 @@ static void machvirt_init(MachineState *machine) fdt_add_pmu_nodes(vms); + fdt_add_spe_nodes(vms); + create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); if (vms->secure) { diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 38a42f409a..21e58f27c5 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -302,6 +302,9 @@ struct AcpiMadtGenericCpuInterface { uint32_t vgic_interrupt; uint64_t gicr_base_address; uint64_t arm_mpidr; + uint8_t efficiency_class; + uint8_t reserved2[1]; + uint16_t spe_interrupt; /* ACPI 6.3 */ } QEMU_PACKED; typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface; diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 72c269aaa5..6013b6d535 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -49,6 +49,7 @@ #define ARCH_TIMER_NS_EL1_IRQ 14 #define ARCH_TIMER_NS_EL2_IRQ 10 +#define VIRTUAL_SPE_IRQ 5 #define VIRTUAL_PMU_IRQ 7 #define PPI(irq) ((irq) + 16) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index f211958eaa..786cc6134c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1041,6 +1041,8 @@ static void arm_cpu_initfn(Object *obj) "gicv3-maintenance-interrupt", 1); qdev_init_gpio_out_named(DEVICE(cpu), &cpu->pmu_interrupt, "pmu-interrupt", 1); + qdev_init_gpio_out_named(DEVICE(cpu), &cpu->spe_interrupt, + "spe-interrupt", 1); #endif /* DTB consumers generally don't in fact care what the 'compatible' diff --git a/target/arm/cpu.h b/target/arm/cpu.h index baf2bbcee8..395a1e5df8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -800,6 +800,8 @@ struct ARMCPU { qemu_irq gicv3_maintenance_interrupt; /* GPIO output for the PMU interrupt */ qemu_irq pmu_interrupt; + /* GPIO output for the SPE interrupt */ + qemu_irq spe_interrupt; /* MemoryRegion to use for secure physical accesses */ MemoryRegion *secure_memory; -- 2.17.1