This series is an attempt to provide CPU hotplug support on ARM virt platform. This is based on ACPI GED device. We should enable ACPI support, and use vGICv3 and 64bit CPU to support CPU hotplug. Under KVM accel, the KVM vCPUs is pre-created. Besides, vGIC IRIs is pre-created too. However, QEMU vCPU objects are defer-created. Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
160 lines
5.0 KiB
Diff
160 lines
5.0 KiB
Diff
From 11f9628ceff019259ff12ce469deafbf50eb3075 Mon Sep 17 00:00:00 2001
|
|
From: Keqian Zhu <zhukeqian1@huawei.com>
|
|
Date: Fri, 10 Apr 2020 14:20:59 +0800
|
|
Subject: [PATCH] arm/virt: Start up CPU hot-plug
|
|
|
|
All the CPU hotplug facilities are ready. Assemble them
|
|
to start up CPU hot-plug capability for arm/virt.
|
|
|
|
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
|
|
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
|
---
|
|
hw/arm/virt.c | 61 ++++++++++++++++++++++++++++++++++++++++---
|
|
include/hw/arm/virt.h | 1 +
|
|
qom/cpu.c | 5 ++++
|
|
target/arm/cpu.c | 2 ++
|
|
4 files changed, 65 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
|
|
index c6a99e683a..112a6ae7cb 100644
|
|
--- a/hw/arm/virt.c
|
|
+++ b/hw/arm/virt.c
|
|
@@ -48,6 +48,8 @@
|
|
#include "sysemu/cpus.h"
|
|
#include "sysemu/sysemu.h"
|
|
#include "sysemu/kvm.h"
|
|
+#include "sysemu/cpus.h"
|
|
+#include "sysemu/hw_accel.h"
|
|
#include "hw/loader.h"
|
|
#include "exec/address-spaces.h"
|
|
#include "qemu/bitops.h"
|
|
@@ -649,9 +651,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
|
|
event |= ACPI_GED_MEM_HOTPLUG_EVT;
|
|
}
|
|
|
|
- /* event |= ACPI_GED_CPU_HOTPLUG_EVT;
|
|
- * Currently CPU hotplug is not enabled.
|
|
- */
|
|
+ if (vms->cpu_hotplug_enabled) {
|
|
+ event |= ACPI_GED_CPU_HOTPLUG_EVT;
|
|
+ }
|
|
|
|
dev = qdev_create(NULL, TYPE_ACPI_GED);
|
|
qdev_prop_set_uint32(dev, "ged-event", event);
|
|
@@ -2214,12 +2216,62 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
|
object_property_set_link(cpuobj, OBJECT(secure_sysmem),
|
|
"secure-memory", &error_abort);
|
|
}
|
|
+
|
|
+ /* If we use KVM accel, we should pause all vcpus to
|
|
+ * allow hot access of vcpu registers.
|
|
+ */
|
|
+ if (dev->hotplugged && kvm_enabled()) {
|
|
+ pause_all_vcpus();
|
|
+ }
|
|
}
|
|
|
|
static void virt_cpu_plug(HotplugHandler *hotplug_dev,
|
|
DeviceState *dev, Error **errp)
|
|
{
|
|
- /* Currently nothing to do */
|
|
+ CPUArchId *cpu_slot;
|
|
+ CPUState *cs = CPU(dev);
|
|
+ int ncpu = cs->cpu_index;
|
|
+ MachineState *ms = MACHINE(hotplug_dev);
|
|
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
|
+ GICv3State *gicv3;
|
|
+ ARMGICv3CommonClass *agcc;
|
|
+ Error *local_err = NULL;
|
|
+
|
|
+ if (dev->hotplugged) {
|
|
+ /* Realize GIC related parts of CPU */
|
|
+ assert(vms->gic_version == 3);
|
|
+ gicv3 = ARM_GICV3_COMMON(vms->gic);
|
|
+ agcc = ARM_GICV3_COMMON_GET_CLASS(gicv3);
|
|
+ agcc->cpu_hotplug_realize(gicv3, ncpu);
|
|
+ connect_gic_cpu_irqs(vms, ncpu);
|
|
+
|
|
+ /* Register CPU reset and trigger it manually */
|
|
+ cpu_synchronize_state(cs);
|
|
+ cpu_hotplug_register_reset(ncpu);
|
|
+ cpu_hotplug_reset_manually(ncpu);
|
|
+ cpu_synchronize_post_reset(cs);
|
|
+
|
|
+ if (kvm_enabled()) {
|
|
+ resume_all_vcpus();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (vms->acpi_dev) {
|
|
+ hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err);
|
|
+ if (local_err) {
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ vms->boot_cpus++;
|
|
+ if (vms->fw_cfg) {
|
|
+ fw_cfg_modify_i16(vms->fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus);
|
|
+ }
|
|
+
|
|
+ cpu_slot = &ms->possible_cpus->cpus[ncpu];
|
|
+ cpu_slot->cpu = OBJECT(dev);
|
|
+out:
|
|
+ error_propagate(errp, local_err);
|
|
}
|
|
|
|
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
|
@@ -2324,6 +2376,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
|
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
|
|
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
|
|
mc->kvm_type = virt_kvm_type;
|
|
+ mc->has_hotpluggable_cpus = true;
|
|
assert(!mc->get_hotplug_handler);
|
|
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
|
|
hc->pre_plug = virt_machine_device_pre_plug_cb;
|
|
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
|
|
index b4c53d920e..a9429bed25 100644
|
|
--- a/include/hw/arm/virt.h
|
|
+++ b/include/hw/arm/virt.h
|
|
@@ -140,6 +140,7 @@ typedef struct {
|
|
uint32_t msi_phandle;
|
|
uint32_t iommu_phandle;
|
|
int psci_conduit;
|
|
+ uint32_t boot_cpus;
|
|
hwaddr highest_gpa;
|
|
DeviceState *gic;
|
|
DeviceState *acpi_dev;
|
|
diff --git a/qom/cpu.c b/qom/cpu.c
|
|
index f376f782d8..58cd9d5bbc 100644
|
|
--- a/qom/cpu.c
|
|
+++ b/qom/cpu.c
|
|
@@ -342,7 +342,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
|
|
|
|
if (dev->hotplugged) {
|
|
cpu_synchronize_post_init(cpu);
|
|
+
|
|
+#ifdef __aarch64__
|
|
+ if (!kvm_enabled())
|
|
+#endif
|
|
cpu_resume(cpu);
|
|
+
|
|
}
|
|
|
|
/* NOTE: latest generic point where the cpu is fully realized */
|
|
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
|
|
index 91f1e36cd8..811e5c6365 100644
|
|
--- a/target/arm/cpu.c
|
|
+++ b/target/arm/cpu.c
|
|
@@ -2598,6 +2598,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
|
acc->parent_reset = cc->reset;
|
|
cc->reset = arm_cpu_reset;
|
|
|
|
+ dc->user_creatable = true;
|
|
+
|
|
cc->class_by_name = arm_cpu_class_by_name;
|
|
cc->has_work = arm_cpu_has_work;
|
|
cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
|
|
--
|
|
2.19.1
|