Skip to content

Commit

Permalink
Qemu: Enable the vcpu-hotplug for arm
Browse files Browse the repository at this point in the history
Initially enable vcpu hotplug in qemu for arm base on Salli's work[1].

Fixes:#3280

Signed-off-by: Huang Shijie <shijie8@gmail.com>
[1] https://github.com/salil-mehta/qemu/tree/virt-cpuhp-armv8/rfc-v1
  • Loading branch information
zyzii committed Jan 14, 2022
1 parent 97e18cf commit 2d0ec00
Show file tree
Hide file tree
Showing 29 changed files with 4,177 additions and 0 deletions.
@@ -0,0 +1,79 @@
From cbc35b3747ff8c50e64e3b8aeecf1b782ee27cad Mon Sep 17 00:00:00 2001
From: Huang Shijie <shijie8@gmail.com>
Date: Mon, 22 Nov 2021 17:51:11 +0800
Subject: [PATCH 01/28] arm/cpuhp: Add QMP vcpu params validation support

From Salil Mehta <salil.mehta@huawei.com>
For now, vcpu hotplug is only supported with single socket single thread,
single die. NUMA is not supported either and everthing falls into single
node. Work to properly support these could be taken later once community
agrees with the base framework changes being presented to support ARM vcpu
hotplug in QEMU. Hence, these checks.

Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Huang Shijie <shijie8@gmail.com>
---
hw/arm/virt.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 81eda46b0b..99d59fada2 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2564,6 +2564,44 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
return NULL;
}

+static void virt_smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
+{
+ unsigned cpus = config->has_cpus ? config->cpus : 1;
+ unsigned sockets = config->has_sockets ? config->sockets: 1;
+ unsigned cores = config->has_cores ? config->cores : cpus;
+ unsigned threads = config->has_threads ? config->threads: 1;
+ unsigned int max_cpus;
+
+ if (sockets > 1 || threads > 1) {
+ error_report("does not support more than one socket or thread");
+ exit(1);
+ }
+
+ if (cores != cpus) {
+ error_report("cpu topology: "
+ "sockets (%u) * cores (%u) * threads (%u) < "
+ "smp_cpus (%u)",
+ sockets, cores, threads, cpus);
+ exit(1);
+ }
+
+ max_cpus = config->has_maxcpus ? config->maxcpus : cpus;
+ if (sockets * cores * threads > max_cpus) {
+ error_report("cpu topology: "
+ "sockets (%u) * cores (%u) * threads (%u) > "
+ "maxcpus (%u)",
+ sockets, cores, threads,
+ max_cpus);
+ exit(1);
+ }
+
+ ms->smp.max_cpus = max_cpus;
+ ms->smp.sockets = sockets;
+ ms->smp.cpus = cpus;
+ ms->smp.cores = cores;
+ ms->smp.threads = threads;
+}
+
/*
* for arm64 kvm_type [7-0] encodes the requested number of bits
* in the IPA address space
@@ -2641,6 +2679,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->auto_enable_numa_with_memhp = true;
mc->auto_enable_numa_with_memdev = true;
mc->default_ram_id = "mach-virt.ram";
+ mc->smp_parse = virt_smp_parse;

object_class_property_add(oc, "acpi", "OnOffAuto",
virt_get_acpi, virt_set_acpi,
--
2.30.2

@@ -0,0 +1,101 @@
From a24ce04b7c2e958a0730f19e6f54e6570a075b20 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 23 Nov 2021 15:08:45 +0800
Subject: [PATCH 02/28] arm/cpuhp: Add new ARMCPU core-id property

This shall be used to store user specified core index and shall be directly
used as slot-index during hot{plug|unplug} of vcpu.

For now, we are not taking into account of other topology info like thread-id,
socket-id to derive mp-affinity. Host KVM uses vcpu-id to derive the mpidr for
the vcpu of the guest. This is not in exact corroboration with the ARM spec
view of the MPIDR. Hence, the concept of threads or SMT bit present as part of
the MPIDR_EL1 also gets lost.

Also, we need ACPI PPTT Table support in QEMU to be able to export this
topology info to the guest VM and the info should be consistent with what host
cpu supports if accel=kvm is being used.

Perhaps some comments on this will help? @Andrew/drjones@redhat.com

Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Huang Shijie <shijie8@gmail.com>
---
hw/arm/virt.c | 5 +++++
target/arm/cpu.c | 5 +++++
target/arm/cpu.h | 1 +
3 files changed, 11 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 99d59fada2..86e1470925 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1944,6 +1944,7 @@ static void machvirt_init(MachineState *machine)
&error_fatal);

aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL);
+ object_property_set_int(cpuobj, "core-id", n, NULL);

if (!vms->secure) {
object_property_set_bool(cpuobj, "has_el3", false, NULL);
@@ -2357,6 +2358,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
{
int n;
unsigned int max_cpus = ms->smp.max_cpus;
+ unsigned int smp_threads = ms->smp.threads;
VirtMachineState *vms = VIRT_MACHINE(ms);

if (ms->possible_cpus) {
@@ -2369,10 +2371,13 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
ms->possible_cpus->len = max_cpus;
for (n = 0; n < ms->possible_cpus->len; n++) {
ms->possible_cpus->cpus[n].type = ms->cpu_type;
+ ms->possible_cpus->cpus[n].vcpus_count = smp_threads;
ms->possible_cpus->cpus[n].arch_id =
virt_cpu_mp_affinity(vms, n);
ms->possible_cpus->cpus[n].props.has_thread_id = true;
ms->possible_cpus->cpus[n].props.thread_id = n;
+ ms->possible_cpus->cpus[n].props.has_core_id = true;
+ ms->possible_cpus->cpus[n].props.core_id = n;
}
return ms->possible_cpus;
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2866dd7658..5dc3fa6c3a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1130,6 +1130,9 @@ static Property arm_cpu_has_dsp_property =
static Property arm_cpu_has_mpu_property =
DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);

+static Property arm_cpu_coreid_property =
+ DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1);
+
/* This is like DEFINE_PROP_UINT32 but it doesn't set the default value,
* because the CPU initfn will have already set cpu->pmsav7_dregion to
* the right value for that particular CPU type, and we don't want
@@ -1303,6 +1306,8 @@ void arm_cpu_post_init(Object *obj)
kvm_arm_add_vcpu_properties(obj);
}

+ qdev_property_add_static(DEVICE(obj), &arm_cpu_coreid_property);
+
#ifndef CONFIG_USER_ONLY
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) &&
cpu_isar_feature(aa64_mte, cpu)) {
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9f0a5f84d5..ba11468ab5 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -999,6 +999,7 @@ struct ARMCPU {
QLIST_HEAD(, ARMELChangeHook) el_change_hooks;

int32_t node_id; /* NUMA node this CPU belongs to */
+ int32_t core_id; /* core-id of this ARM VCPU */

/* Used to synchronize KVM and QEMU in-kernel device levels */
uint8_t device_irq_level;
--
2.30.2

@@ -0,0 +1,97 @@
From cf832166791bddea562ba9372795db04ea41a581 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Tue, 23 Nov 2021 15:22:27 +0800
Subject: [PATCH 03/28] arm/cpuhp: Add common cpu utility for possible vcpus

Adds various utility functions which might be required to fetch or check the
state of the possible vcpus. This also introduces concept of *disabled* vcpus,
which are part of the *possible* vcpus but are not part of the *present* vcpu.
This state shall be used during machine init time to check the presence of
vcpus.

Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
cpus-common.c | 19 +++++++++++++++++++
include/hw/core/cpu.h | 21 +++++++++++++++++++++
2 files changed, 40 insertions(+)

diff --git a/cpus-common.c b/cpus-common.c
index 6e73d3e58d..4f0fa42a2e 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -23,6 +23,7 @@
#include "hw/core/cpu.h"
#include "sysemu/cpus.h"
#include "qemu/lockable.h"
+#include "hw/boards.h"

static QemuMutex qemu_cpu_list_lock;
static QemuCond exclusive_cond;
@@ -86,6 +87,24 @@ void cpu_list_add(CPUState *cpu)
QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
}

+CPUState *qemu_get_possible_cpu(int index)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ const CPUArchIdList *possible_cpus = ms->possible_cpus;
+ CPUState *cpu;
+
+ assert((index >= 0) && (index < possible_cpus->len));
+
+ cpu = CPU(possible_cpus->cpus[index].cpu);
+
+ return cpu;
+}
+
+bool qemu_present_cpu(CPUState *cpu)
+{
+ return (cpu && !cpu->disabled);
+}
+
void cpu_list_remove(CPUState *cpu)
{
QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index bc864564ce..5a2571af3e 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -391,6 +391,7 @@ struct CPUState {
SavedIOTLB saved_iotlb;
#endif

+ bool disabled;
/* TODO Move common fields from CPUArchState here. */
int cpu_index;
int cluster_index;
@@ -749,6 +750,26 @@ static inline bool cpu_in_exclusive_context(const CPUState *cpu)
*/
CPUState *qemu_get_cpu(int index);

+/**
+ * qemu_get_possible_cpu:
+ * @index: The CPUState@cpu_index value of the CPU to obtain.
+ *
+ * Gets a CPU matching @index.
+ *
+ * Returns: The possible CPU or %NULL if there is no matching CPU.
+ */
+CPUState *qemu_get_possible_cpu(int index);
+
+/**
+ * qemu_present_cpu:
+ * @cpu: The vCPU to check
+ *
+ * Checks if the vcpu is amongst the present possible vcpus.
+ *
+ * Returns: True if it is present possible vcpu else false
+ */
+bool qemu_present_cpu(CPUState *cpu);
+
/**
* cpu_exists:
* @id: Guest-exposed CPU ID to lookup.
--
2.30.2

0 comments on commit 2d0ec00

Please sign in to comment.