qemu/arm-virt-gicv3-Changes-to-pre-size-GIC-with-possible.patch
Jiabo Feng c025e9059a QEMU update to version 8.2.0-6:
- coro: support live patch for libcare
- tests/acpi: Update expected ACPI tables for vcpu hotplug(update BinDir)
- arm/virt: Require mc->has_hotpluggable_cpus for cold-plugged vcpu
- arm/virt: Consider has_ged when set mc->has_hotpluggable_cpus
- arm/virt-acpi: Require possible_cpu_arch_ids for build_cpus_aml()
- acpi/ged: Remove cpuhp field of ged
- acpi/ged: Init cpu hotplug only when machine support it
- intc/gicv3: Fixes for vcpu hotplug
- arm/kvm: Set psci smccc filter only with vcpu hotplug
- accel/kvm: Use correct id for parked vcpu
- arm/virt: Fix adjudgement of core_id for vcpu hotplugged
- arm/virt.c: Convey local_err when set psci-conduit
- system/cpus: Fix resume_all_vcpus() under vCPU hotplug condition
- system/cpus: Fix pause_all_vcpus() under concurrent environment
- acpi/cpu: Fix cpu_hotplug_hw_init()
- arm/cpu: Some fixes for arm_cpu_unrealizefn()
- system/physmem: Fix possible double free when destroy cpu as
- hw/arm/virt: Expose cold-booted CPUs as MADT GICC Enabled
- tcg/mttcg: enable threads to unregister in tcg_ctxs[]
- hw/arm: Support hotplug capability check using _OSC method
- target/arm/kvm,tcg: Register/Handle SMCCC hypercall exits to VMM/Qemu
- target/arm/kvm: Write CPU state back to KVM on reset
- target/arm: Add support of *unrealize* ARMCPU during vCPU Hot-unplug
- physmem,gdbstub: Common helping funcs/changes to *unrealize* vCPU
- hw/arm: Changes required for reset and to support next boot
- arm/virt: Update the guest(via GED) about CPU hot-(un)plug events
- hw/intc/arm-gicv3*: Changes required to (re)init the vCPU register info
- hw/arm,gicv3: Changes to update GIC with vCPU hot-plug notification
- arm/virt: Changes to (un)wire GICC<->vCPU IRQs during hot-(un)plug
- arm/virt: Add/update basic hot-(un)plug framework
- hw/acpi: Update ACPI GED framework to support vCPU Hotplug
- arm/virt: Release objects for *disabled* possible vCPUs after init
- hw/acpi: Make _MAT method optional
- hw/arm: MADT Tbl change to size the guest with possible vCPUs
- hw/acpi: Update GED _EVT method AML with cpu scan
- hw/acpi: ACPI/AML Changes to reflect the correct _STA.{PRES,ENA} Bits to Guest
- arm/virt: Make ARM vCPU *present* status ACPI *persistent*
- arm/virt/acpi: Build CPUs AML with CPU Hotplug support
- tests/acpi/bios-tables-test: Allow changes to virt/DSDT file
- acpi/cpu: Add cpu_cppc building support
- arm/virt/acpi: Factor out CPPC building from DSDT CPU aml
- hw/acpi: Update CPUs AML with cpu-(ctrl)dev change
- arm/virt: Create GED dev before *disabled* CPU Objs are destroyed
- arm/virt: Add cpu hotplug events to GED during creation
- hw/acpi: Init GED framework with cpu hotplug events
- hw/acpi: Use qemu_present_cpu() API in ACPI CPU hotplug init
- hw/acpi: Add ACPI CPU hotplug init stub
- arm/acpi: Enable ACPI support for vcpu hotplug
- hw/acpi: Move CPU ctrl-dev MMIO region len macro to common header file
- arm/virt: Init PMU at host for all possible vcpus
- arm/virt,gicv3: Changes to pre-size GIC with possible vcpus @machine init
- arm/virt,kvm: Pre-create disabled possible vCPUs @machine init
- accel/kvm: Extract common KVM vCPU {creation,parking} code
- arm/virt,target/arm: Machine init time change common to vCPU {cold|hot}-plug
- hw/arm/virt: Move setting of common CPU properties in a function
- cpus-common: Add common CPU utility for possible vCPUs
- arm/virt,target/arm: Add new ARMCPU {socket,cluster,core,thread}-id property

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
2024-04-10 21:01:15 +08:00

226 lines
9.0 KiB
Diff

From fe61cbaf2dc92b062c8d147b05c3ce213734c24a Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Wed, 6 May 2020 02:20:23 +0100
Subject: [PATCH] arm/virt,gicv3: Changes to pre-size GIC with possible vcpus
@machine init
GIC needs to be pre-sized with possible vcpus at the initialization time. This
is necessary because Memory regions and resources associated with GICC/GICR
etc cannot be changed (add/del/modified) after VM has inited. Also, GIC_TYPER
needs to be initialized with mp_affinity and cpu interface number association.
This cannot be changed after GIC has initialized.
Once all the cpu interfaces of the GIC has been inited it needs to be ensured
that any updates to the GICC during reset only takes place for the present
vcpus and not the disabled ones. Therefore, proper checks are required at
various places.
Co-developed-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
[changed the comment in arm_gicv3_icc_reset]
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 13 +++++++------
hw/intc/arm_gicv3_common.c | 7 +++++--
hw/intc/arm_gicv3_cpuif.c | 8 ++++++++
hw/intc/arm_gicv3_kvm.c | 34 +++++++++++++++++++++++++++++++---
include/hw/arm/virt.h | 2 +-
5 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index f10d75366b..08ba255317 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -802,6 +802,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
const char *gictype;
int i;
unsigned int smp_cpus = ms->smp.cpus;
+ unsigned int max_cpus = ms->smp.max_cpus;
uint32_t nb_redist_regions = 0;
int revision;
@@ -826,7 +827,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
}
vms->gic = qdev_new(gictype);
qdev_prop_set_uint32(vms->gic, "revision", revision);
- qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(vms->gic, "num-cpu", max_cpus);
/* Note that the num-irq property counts both internal and external
* interrupts; there are always 32 of the former (mandated by GIC spec).
*/
@@ -838,7 +839,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
if (vms->gic_version != VIRT_GIC_VERSION_2) {
QList *redist_region_count;
uint32_t redist0_capacity = virt_redist_capacity(vms, VIRT_GIC_REDIST);
- uint32_t redist0_count = MIN(smp_cpus, redist0_capacity);
+ uint32_t redist0_count = MIN(max_cpus, redist0_capacity);
nb_redist_regions = virt_gicv3_redist_region_count(vms);
@@ -915,7 +916,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
} else if (vms->virt) {
qemu_irq irq = qdev_get_gpio_in(vms->gic,
intidbase + ARCH_GIC_MAINT_IRQ);
- sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq);
+ sysbus_connect_irq(gicbusdev, i + 4 * max_cpus, irq);
}
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
@@ -923,11 +924,11 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
+ VIRTUAL_PMU_IRQ));
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
- sysbus_connect_irq(gicbusdev, i + smp_cpus,
+ sysbus_connect_irq(gicbusdev, i + max_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
- sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
+ sysbus_connect_irq(gicbusdev, i + 2 * max_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
- sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
+ sysbus_connect_irq(gicbusdev, i + 3 * max_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 2ebf880ead..ebd99af610 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -392,10 +392,13 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
for (i = 0; i < s->num_cpu; i++) {
- CPUState *cpu = qemu_get_cpu(i);
+ CPUState *cpu = qemu_get_possible_cpu(i);
uint64_t cpu_affid;
- s->cpu[i].cpu = cpu;
+ if (qemu_enabled_cpu(cpu)) {
+ s->cpu[i].cpu = cpu;
+ }
+
s->cpu[i].gic = s;
/* Store GICv3CPUState in CPUARMState gicv3state pointer */
gicv3_set_gicv3state(cpu, &s->cpu[i]);
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index ab1a00508e..0d0eb2f62f 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -934,6 +934,10 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
ARMCPU *cpu = ARM_CPU(cs->cpu);
CPUARMState *env = &cpu->env;
+ if (!qemu_enabled_cpu(cs->cpu)) {
+ return;
+ }
+
g_assert(qemu_mutex_iothread_locked());
trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq,
@@ -1826,6 +1830,10 @@ static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs,
for (i = 0; i < s->num_cpu; i++) {
GICv3CPUState *ocs = &s->cpu[i];
+ if (!qemu_enabled_cpu(ocs->cpu)) {
+ continue;
+ }
+
if (irm) {
/* IRM == 1 : route to all CPUs except self */
if (cs == ocs) {
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 77eb37e131..db06c75e2b 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -24,6 +24,7 @@
#include "hw/intc/arm_gicv3_common.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "sysemu/runstate.h"
#include "kvm_arm.h"
@@ -458,6 +459,18 @@ static void kvm_arm_gicv3_put(GICv3State *s)
GICv3CPUState *c = &s->cpu[ncpu];
int num_pri_bits;
+ /*
+ * To support hotplug of vcpus we need to make sure all gic cpuif/GICC
+ * are initialized at machvirt init time. Once the init is done we
+ * release the ARMCPU object for disabled vcpus but this leg could hit
+ * during reset of GICC later as well i.e. after init has happened and
+ * all of the cases we want to make sure we dont acess the GICC for
+ * the disabled VCPUs.
+ */
+ if (!qemu_enabled_cpu(c->cpu)) {
+ continue;
+ }
+
kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true);
kvm_gicc_access(s, ICC_CTLR_EL1, ncpu,
&c->icc_ctlr_el1[GICV3_NS], true);
@@ -616,6 +629,11 @@ static void kvm_arm_gicv3_get(GICv3State *s)
GICv3CPUState *c = &s->cpu[ncpu];
int num_pri_bits;
+ /* don't access GICC for the disabled vCPUs. */
+ if (!qemu_enabled_cpu(c->cpu)) {
+ continue;
+ }
+
kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, false);
kvm_gicc_access(s, ICC_CTLR_EL1, ncpu,
&c->icc_ctlr_el1[GICV3_NS], false);
@@ -695,10 +713,19 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
return;
}
+ /*
+ * This shall be called even when vcpu is being hotplugged or onlined and
+ * other vcpus might be running. Host kernel KVM code to handle device
+ * access of IOCTLs KVM_{GET|SET}_DEVICE_ATTR might fail due to inability to
+ * grab vcpu locks for all the vcpus. Hence, we need to pause all vcpus to
+ * facilitate locking within host.
+ */
+ pause_all_vcpus();
/* Initialize to actual HW supported configuration */
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer),
&c->icc_ctlr_el1[GICV3_NS], false, &error_abort);
+ resume_all_vcpus();
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
}
@@ -808,9 +835,10 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
for (i = 0; i < s->num_cpu; i++) {
- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
-
- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+ CPUState *cs = qemu_get_cpu(i);
+ if (qemu_enabled_cpu(cs)) {
+ define_arm_cp_regs(ARM_CPU(cs), gicv3_cpuif_reginfo);
+ }
}
/* Try to create the device via the device control API */
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 49d1ec8656..a6977bade5 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -208,7 +208,7 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
assert(vms->gic_version != VIRT_GIC_VERSION_2);
- return (MACHINE(vms)->smp.cpus > redist0_capacity &&
+ return (MACHINE(vms)->smp.max_cpus > redist0_capacity &&
vms->highmem_redists) ? 2 : 1;
}
--
2.27.0