arm/virt: Add ACPI CPU hotplug support

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>
This commit is contained in:
Keqian Zhu 2020-04-22 21:59:17 +08:00 committed by Ying Fang
parent d01be9927c
commit 1c823f0431
29 changed files with 3451 additions and 0 deletions

View File

@ -0,0 +1,27 @@
From 843f593280b93e03bb7b0d0001da7488d61f13f6 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 6 Apr 2020 08:55:17 +0800
Subject: [PATCH] Typo: Correct the name of CPU hotplug memory region
Replace "acpi-mem-hotplug" with "acpi-cpu-hotplug"
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/cpu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 7a90c8f82d..0c0bfe479a 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -203,7 +203,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
state->devs[i].arch_id = id_list->cpus[i].arch_id;
}
memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state,
- "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN);
+ "acpi-cpu-hotplug", ACPI_CPU_HOTPLUG_REG_LEN);
memory_region_add_subregion(as, base_addr, &state->ctrl_reg);
}
--
2.19.1

View File

@ -0,0 +1,63 @@
From 135119d2e82e99adc67346572c761fbe54d73e4a Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:04:40 +0800
Subject: [PATCH] accel/kvm: Add pre-park vCPU support
For that KVM do not support dynamic adjustment of vCPU count,
we must pre-park all possible vCPU at start.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
accel/kvm/kvm-all.c | 23 +++++++++++++++++++++++
include/sysemu/kvm.h | 1 +
2 files changed, 24 insertions(+)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index f450f25295..84edbe8bb1 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -339,6 +339,29 @@ err:
return ret;
}
+int kvm_create_parked_vcpu(unsigned long vcpu_id)
+{
+ KVMState *s = kvm_state;
+ struct KVMParkedVcpu *vcpu = NULL;
+ int ret;
+
+ DPRINTF("kvm_create_parked_vcpu\n");
+
+ ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
+ if (ret < 0) {
+ DPRINTF("kvm_create_vcpu failed\n");
+ goto err;
+ }
+
+ vcpu = g_malloc0(sizeof(*vcpu));
+ vcpu->vcpu_id = vcpu_id;
+ vcpu->kvm_fd = ret;
+ QLIST_INSERT_HEAD(&s->kvm_parked_vcpus, vcpu, node);
+
+err:
+ return ret;
+}
+
static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
{
struct KVMParkedVcpu *cpu;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index acd90aebb6..565adb4e2c 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -216,6 +216,7 @@ int kvm_has_many_ioeventfds(void);
int kvm_has_gsi_routing(void);
int kvm_has_intx_set_mask(void);
+int kvm_create_parked_vcpu(unsigned long vcpu_id);
int kvm_init_vcpu(CPUState *cpu);
int kvm_cpu_exec(CPUState *cpu);
int kvm_destroy_vcpu(CPUState *cpu);
--
2.19.1

View File

@ -0,0 +1,128 @@
From 107c267ebe5b8c461268a4ff8384ad2f2b9e8ce0 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Wed, 22 Apr 2020 16:11:13 +0800
Subject: [PATCH] acpi/cpu: Prepare build_cpus_aml for arm virt
We will reuse build_cpus_aml to build DSDT cpus aml in arm/virt
ACPI to realize cpu hotplug. Three points are added.
1. Make ACPI IO address space configurable, because ARM64 platforms
don't use port IO for ACPI IO space.
2. Add GICC struct building support in _MAT of cpu aml.
3. Let the hotplug method parameter can be NULL, because ACPI GED
will realize it.
Besides, CPU CPPC building is injected.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/acpi/cpu.c | 32 +++++++++++++++++++++++++-------
hw/i386/acpi-build.c | 2 +-
include/hw/acpi/cpu.h | 3 ++-
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 0c0bfe479a..72ad1fcff2 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -314,7 +314,8 @@ const VMStateDescription vmstate_cpu_hotplug = {
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
hwaddr io_base,
const char *res_root,
- const char *event_handler_method)
+ const char *event_handler_method,
+ AmlRegionSpace rs)
{
Aml *ifctx;
Aml *field;
@@ -342,13 +343,18 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
- ACPI_CPU_HOTPLUG_REG_LEN));
+ if (rs == AML_SYSTEM_IO) {
+ aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
+ ACPI_CPU_HOTPLUG_REG_LEN));
+ } else {
+ aml_append(crs, aml_memory32_fixed(io_base,
+ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE));
+ }
aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs));
/* declare CPU hotplug MMIO region with related access fields */
aml_append(cpu_ctrl_dev,
- aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base),
+ aml_operation_region("PRST", rs, aml_int(io_base),
ACPI_CPU_HOTPLUG_REG_LEN));
field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,
@@ -517,6 +523,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(dev, aml_name_decl("_UID", uid));
}
+ assert(adevc);
+ if (adevc->cpu_cppc) {
+ adevc->cpu_cppc(adev, i, arch_ids->len, dev);
+ }
+
method = aml_method("_STA", 0, AML_SERIALIZED);
aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid)));
aml_append(dev, method);
@@ -535,6 +546,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
apic->flags = cpu_to_le32(1);
break;
}
+ case ACPI_APIC_GENERIC_CPU_INTERFACE: {
+ AcpiMadtGenericCpuInterface *gicc = (void *)madt_buf->data;
+ gicc->flags = cpu_to_le32(1);
+ break;
+ }
default:
assert(0);
}
@@ -570,9 +586,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(sb_scope, cpus_dev);
aml_append(table, sb_scope);
- method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
- aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD));
- aml_append(table, method);
+ if (event_handler_method) {
+ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD));
+ aml_append(table, method);
+ }
g_free(cphp_res_path);
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 749218561a..c97731ecb3 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1869,7 +1869,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
.acpi_1_compatible = true, .has_legacy_cphp = true
};
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
- "\\_SB.PCI0", "\\_GPE._E02");
+ "\\_SB.PCI0", "\\_GPE._E02", AML_SYSTEM_IO);
}
if (pcms->memhp_io_base && nr_mem) {
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index 62f0278ba2..a30ec84a4f 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -55,7 +55,8 @@ typedef struct CPUHotplugFeatures {
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
hwaddr io_base,
const char *res_root,
- const char *event_handler_method);
+ const char *event_handler_method,
+ AmlRegionSpace rs);
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list);
--
2.19.1

View File

@ -0,0 +1,41 @@
From 3cd6df0b9e7d7b544673ce9a63b405e236d8265b Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 10:05:54 +0800
Subject: [PATCH] acpi/ged: Add virt_madt_cpu_entry to madt_cpu hook
In build_cpus_aml, we will invoke this hook to build _MAT
aml mehtod for cpus.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/acpi/generic_event_device.c | 1 +
include/hw/acpi/generic_event_device.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 9cee90cc70..b834ae3ff6 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -288,6 +288,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
hc->plug = acpi_ged_device_plug_cb;
adevc->send_event = acpi_ged_send_event;
+ adevc->madt_cpu = virt_madt_cpu_entry;
}
static const TypeInfo acpi_ged_info = {
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index d157eac088..f99efad7a3 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -61,6 +61,7 @@
#include "hw/sysbus.h"
#include "hw/acpi/memory_hotplug.h"
+#include "hw/arm/virt.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
--
2.19.1

View File

@ -0,0 +1,204 @@
From 05d22b55133db1a2526cfe305102e075e883b5e2 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 3 Apr 2020 15:41:01 +0800
Subject: [PATCH] acpi/ged: Extend ACPI GED to support CPU hotplug
This adds a new GED event called ACPI_GED_CPU_HOTPLUG_EVT.
The basic workflow is that: GED sends this event to guest,
then ACPI driver in guest will call _EVT method of GED aml,
then _EVT will call CSCN method in cpus aml to get status of
all cpus.
The status of cpus is maintained by CPUHotplugState in GED and
is made accessable to guest through memory region.
This also adds migration support to CPUHotplugState.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++-
hw/acpi/cpu.c | 1 -
hw/acpi/generic_event_device.c | 35 ++++++++++++++++++++++++++
hw/arm/Kconfig | 1 +
include/hw/acpi/cpu.h | 2 ++
include/hw/acpi/generic_event_device.h | 4 +++
6 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst
index 911a98255b..deb481555d 100644
--- a/docs/specs/acpi_hw_reduced_hotplug.rst
+++ b/docs/specs/acpi_hw_reduced_hotplug.rst
@@ -63,7 +63,8 @@ GED IO interface (4 byte access)
bits:
0: Memory hotplug event
1: System power down event
- 2-31: Reserved
+ 2: CPU hotplug event
+ 3-31: Reserved
**write_access:**
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 72ad1fcff2..cb6bb67f3c 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -6,7 +6,6 @@
#include "trace.h"
#include "sysemu/numa.h"
-#define ACPI_CPU_HOTPLUG_REG_LEN 12
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
#define ACPI_CPU_FLAGS_OFFSET_RW 4
#define ACPI_CPU_CMD_OFFSET_WR 5
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 82139b4314..478a4ee87c 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -23,6 +23,7 @@
static const uint32_t ged_supported_events[] = {
ACPI_GED_MEM_HOTPLUG_EVT,
ACPI_GED_PWR_DOWN_EVT,
+ ACPI_GED_CPU_HOTPLUG_EVT,
};
/*
@@ -110,6 +111,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
aml_int(0x80)));
break;
+ case ACPI_GED_CPU_HOTPLUG_EVT:
+ aml_append(if_ctx, aml_call0("\\_SB.CPUS.CSCN"));
+ break;
default:
/*
* Please make sure all the events in ged_supported_events[]
@@ -176,6 +180,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -192,6 +198,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
sel = ACPI_GED_MEM_HOTPLUG_EVT;
} else if (ev & ACPI_POWER_DOWN_STATUS) {
sel = ACPI_GED_PWR_DOWN_EVT;
+ } else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
+ sel = ACPI_GED_CPU_HOTPLUG_EVT;
} else {
/* Unknown event. Return without generating interrupt. */
warn_report("GED: Unsupported event %d. No irq injected", ev);
@@ -224,6 +232,16 @@ static const VMStateDescription vmstate_memhp_state = {
}
};
+static const VMStateDescription vmstate_cpuhp_state = {
+ .name = "acpi-ged/cpuhp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ged_state = {
.name = "acpi-ged-state",
.version_id = 1,
@@ -244,6 +262,7 @@ static const VMStateDescription vmstate_acpi_ged = {
},
.subsections = (const VMStateDescription * []) {
&vmstate_memhp_state,
+ &vmstate_cpuhp_state,
NULL
}
};
@@ -254,6 +273,7 @@ static void acpi_ged_initfn(Object *obj)
AcpiGedState *s = ACPI_GED(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
GEDState *ged_st = &s->ged_state;
+ MachineClass *mc;
memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st,
TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
@@ -273,6 +293,21 @@ static void acpi_ged_initfn(Object *obj)
sysbus_init_mmio(sbd, &s->container_memhp);
acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
&s->memhp_state, 0);
+
+ mc = MACHINE_GET_CLASS(qdev_get_machine());
+ if (!mc->possible_cpu_arch_ids) {
+ /*
+ * MachineClass should support possible_cpu_arch_ids in
+ * cpu_hotplug_hw_init below.
+ */
+ return;
+ }
+
+ memory_region_init(&s->container_cpuhp, OBJECT(dev), "cpuhp container",
+ ACPI_CPU_HOTPLUG_REG_LEN);
+ sysbus_init_mmio(sbd, &s->container_cpuhp);
+ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
+ &s->cpuhp_state, 0);
}
static void acpi_ged_class_init(ObjectClass *class, void *data)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index ad7f7c089b..15e18b0a48 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -24,6 +24,7 @@ config ARM_VIRT
select DIMM
select ACPI_MEMORY_HOTPLUG
select ACPI_HW_REDUCED
+ select ACPI_CPU_HOTPLUG
config CHEETAH
bool
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index a30ec84a4f..e726414459 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -17,6 +17,8 @@
#include "hw/acpi/aml-build.h"
#include "hw/hotplug.h"
+#define ACPI_CPU_HOTPLUG_REG_LEN 12
+
typedef struct AcpiCpuStatus {
struct CPUState *cpu;
uint64_t arch_id;
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index f99efad7a3..e702ff1e18 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -62,6 +62,7 @@
#include "hw/sysbus.h"
#include "hw/acpi/memory_hotplug.h"
#include "hw/arm/virt.h"
+#include "hw/acpi/cpu.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
@@ -83,6 +84,7 @@
*/
#define ACPI_GED_MEM_HOTPLUG_EVT 0x1
#define ACPI_GED_PWR_DOWN_EVT 0x2
+#define ACPI_GED_CPU_HOTPLUG_EVT 0x4
typedef struct GEDState {
MemoryRegion io;
@@ -93,6 +95,8 @@ typedef struct AcpiGedState {
SysBusDevice parent_obj;
MemHotplugState memhp_state;
MemoryRegion container_memhp;
+ CPUHotplugState cpuhp_state;
+ MemoryRegion container_cpuhp;
GEDState ged_state;
uint32_t ged_event_bitmap;
qemu_irq irq;
--
2.19.1

View File

@ -0,0 +1,95 @@
From 0288d98f0ef4d17a73cf2bad1b928cd7c044e318 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:40:44 +0800
Subject: [PATCH] acpi/madt: Add pre-sizing capability to MADT GICC struct
The count of possible CPUs is exposed to guest through the count
of MADT GICC struct, so we should pre-sizing MADT GICC too.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 26 +++++++++++++++++++++-----
include/hw/acpi/acpi-defs.h | 1 +
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index dbe9acb148..efac788ba1 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -678,6 +678,13 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const MemMapEntry *memmap = vms->memmap;
AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc));
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid));
+ static bool pmu;
+
+ if (uid == 0) {
+ pmu = arm_feature(&armcpu->env, ARM_FEATURE_PMU);
+ }
+ /* FEATURE_PMU should be all enabled or disabled for CPUs */
+ assert(!armcpu || arm_feature(&armcpu->env, ARM_FEATURE_PMU) == pmu);
gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
gicc->length = sizeof(*gicc);
@@ -687,11 +694,15 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base);
}
gicc->cpu_interface_number = cpu_to_le32(uid);
- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
+ gicc->arm_mpidr = possible_cpus->cpus[uid].arch_id;
gicc->uid = cpu_to_le32(uid);
- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
+ if (armcpu) {
+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
+ } else {
+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_DISABLED);
+ }
- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
+ if (pmu) {
gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
}
if (vms->virt) {
@@ -704,12 +715,17 @@ static void
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+ MachineClass *mc = MACHINE_GET_CLASS(vms);
+ MachineState *ms = MACHINE(vms);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
int madt_start = table_data->len;
const MemMapEntry *memmap = vms->memmap;
const int *irqmap = vms->irqmap;
AcpiMultipleApicTable *madt;
AcpiMadtGenericDistributor *gicd;
AcpiMadtGenericMsiFrame *gic_msi;
+ /* The MADT GICC numbers */
+ int num_cpu = vms->smp_cpus;
int i;
madt = acpi_data_push(table_data, sizeof *madt);
@@ -720,8 +736,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base);
gicd->version = vms->gic_version;
- for (i = 0; i < vms->smp_cpus; i++) {
- virt_madt_cpu_entry(NULL, i, NULL, table_data);
+ for (i = 0; i < num_cpu; i++) {
+ virt_madt_cpu_entry(NULL, i, possible_cpus, table_data);
}
if (vms->gic_version == 3) {
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 39ae91d3b8..6bfa7f9152 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -306,6 +306,7 @@ typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface;
/* GICC CPU Interface Flags */
#define ACPI_MADT_GICC_ENABLED 1
+#define ACPI_MADT_GICC_DISABLED 0
struct AcpiMadtGenericDistributor {
ACPI_SUB_HEADER_DEF
--
2.19.1

View File

@ -0,0 +1,108 @@
From a3097eed8b642dc6fe891112340821e869b90cc2 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 13 Jan 2020 19:02:20 +0800
Subject: [PATCH] acpi/madt: Factor out the building of MADT GICC struct
To realize CPU hotplug, the cpus aml within ACPI DSDT should contain
_MAT mathod, which is equal to the GICC struct in ACPI MADT. Factor
out the GICC building code from ACPI MADT and reuse it in build_cpus_aml.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 51 +++++++++++++++++++++++-----------------
include/hw/arm/virt.h | 3 +++
2 files changed, 32 insertions(+), 22 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f48733d9f2..4b6aace433 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -664,6 +664,34 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
table_data->len - gtdt_start, 2, NULL, NULL);
}
+void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
+ const CPUArchIdList *possible_cpus, GArray *entry)
+{
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+ const MemMapEntry *memmap = vms->memmap;
+ AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc));
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid));
+
+ gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
+ gicc->length = sizeof(*gicc);
+ if (vms->gic_version == 2) {
+ gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base);
+ gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base);
+ gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base);
+ }
+ gicc->cpu_interface_number = cpu_to_le32(uid);
+ gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
+ gicc->uid = cpu_to_le32(uid);
+ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
+
+ if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
+ gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
+ }
+ if (vms->virt) {
+ gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ));
+ }
+}
+
/* MADT */
static void
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
@@ -686,28 +714,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicd->version = vms->gic_version;
for (i = 0; i < vms->smp_cpus; i++) {
- AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data,
- sizeof(*gicc));
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
-
- gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
- gicc->length = sizeof(*gicc);
- if (vms->gic_version == 2) {
- gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base);
- gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base);
- gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base);
- }
- gicc->cpu_interface_number = cpu_to_le32(i);
- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
- gicc->uid = cpu_to_le32(i);
- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
-
- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
- gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
- }
- if (vms->virt) {
- gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ));
- }
+ virt_madt_cpu_entry(NULL, i, NULL, table_data);
}
if (vms->gic_version == 3) {
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 3dfefca93b..6b1f10b231 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -37,6 +37,7 @@
#include "hw/block/flash.h"
#include "sysemu/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
+#include "hw/acpi/acpi_dev_interface.h"
#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
@@ -154,6 +155,8 @@ typedef struct {
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
void virt_acpi_setup(VirtMachineState *vms);
+void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
+ const CPUArchIdList *cpu_list, GArray *entry);
/* Return the number of used redistributor regions */
static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
--
2.19.1

View File

@ -0,0 +1,42 @@
From d8e0b51447d8c64788cd7f9b0fa75c4ccb06f8eb Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 10:17:27 +0800
Subject: [PATCH] arm/cpu: assign arm_get_arch_id handler to get_arch_id hook
This hook will be called in get_cpu_status, which is called
during cpu hotplug.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
target/arm/cpu.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 39bbe7e2d7..1ccb30e5eb 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2575,6 +2575,13 @@ static gchar *arm_gdb_arch_name(CPUState *cs)
return g_strdup("arm");
}
+static int64_t arm_cpu_get_arch_id(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ return cpu->mp_affinity;
+}
+
static void arm_cpu_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -2596,6 +2603,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->synchronize_from_tb = arm_cpu_synchronize_from_tb;
cc->gdb_read_register = arm_cpu_gdb_read_register;
cc->gdb_write_register = arm_cpu_gdb_write_register;
+ cc->get_arch_id = arm_cpu_get_arch_id;
#ifndef CONFIG_USER_ONLY
cc->do_interrupt = arm_cpu_do_interrupt;
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
--
2.19.1

View File

@ -0,0 +1,66 @@
From 6d287b3f1d961cc4adda1c6a452f41db84466f5a Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 3 Apr 2020 16:16:18 +0800
Subject: [PATCH] arm/virt: Add CPU hotplug framework
Establish the CPU hotplug framework for arm/virt, we will add
necessary code legs to this framework gradually to realize CPU
hotplug finally.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d09a5773df..0bd37af26c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2077,11 +2077,25 @@ out:
error_propagate(errp, local_err);
}
+static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ /* Currently nothing to do */
+}
+
+static void virt_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ /* Currently nothing to do */
+}
+
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ virt_cpu_pre_plug(hotplug_dev, dev, errp);
}
}
@@ -2098,6 +2112,8 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
}
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ virt_cpu_plug(hotplug_dev, dev, errp);
}
}
@@ -2112,7 +2128,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) ||
- (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) {
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
return HOTPLUG_HANDLER(machine);
}
--
2.19.1

View File

@ -0,0 +1,219 @@
From cde57fcae2ed16a10e1ef7f2da0ec368883988ba Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 6 Apr 2020 10:54:35 +0800
Subject: [PATCH] arm/virt: Add CPU topology support
The CPU topology specified by user (through -smp options) is used in
ACPI PPTT. Now we will use this information to locate which CPU to
plug or unplug.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 68 +++++++++++++++++++++++++++++++++++++--
include/hw/arm/topology.h | 61 +++++++++++++++++++++++++++++++++++
target/arm/cpu.c | 3 ++
target/arm/cpu.h | 3 ++
4 files changed, 133 insertions(+), 2 deletions(-)
create mode 100644 include/hw/arm/topology.h
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0bd37af26c..64532b61b2 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -36,6 +36,7 @@
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/arm/primecell.h"
+#include "hw/arm/topology.h"
#include "hw/arm/virt.h"
#include "hw/block/flash.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
@@ -2020,6 +2021,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
int n;
unsigned int max_cpus = ms->smp.max_cpus;
VirtMachineState *vms = VIRT_MACHINE(ms);
+ ARMCPUTopoInfo topo;
if (ms->possible_cpus) {
assert(ms->possible_cpus->len == max_cpus);
@@ -2031,10 +2033,17 @@ 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 = 1;
ms->possible_cpus->cpus[n].arch_id =
virt_cpu_mp_affinity(vms, n);
+
+ topo_ids_from_idx(n, ms->smp.cores, ms->smp.threads, &topo);
+ ms->possible_cpus->cpus[n].props.has_socket_id = true;
+ ms->possible_cpus->cpus[n].props.socket_id = topo.pkg_id;
+ ms->possible_cpus->cpus[n].props.has_core_id = true;
+ ms->possible_cpus->cpus[n].props.core_id = topo.core_id;
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.thread_id = topo.smt_id;
}
return ms->possible_cpus;
}
@@ -2080,7 +2089,62 @@ out:
static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- /* Currently nothing to do */
+ CPUState *cs = CPU(dev);
+ ARMCPUTopoInfo topo;
+ ARMCPU *cpu = ARM_CPU(dev);
+ MachineState *ms = MACHINE(hotplug_dev);
+ int smp_cores = ms->smp.cores;
+ int smp_threads = ms->smp.threads;
+
+ /* if cpu idx is not set, set it based on socket/core/thread properties */
+ if (cs->cpu_index == UNASSIGNED_CPU_INDEX) {
+ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores;
+ if (cpu->socket_id < 0 || cpu->socket_id >= max_socket) {
+ error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
+ cpu->socket_id, max_socket - 1);
+ return;
+ }
+ if (cpu->core_id < 0 || cpu->core_id >= smp_cores) {
+ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
+ cpu->core_id, smp_cores - 1);
+ return;
+ }
+ if (cpu->thread_id < 0 || cpu->thread_id >= smp_threads) {
+ error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
+ cpu->thread_id, smp_threads - 1);
+ return;
+ }
+
+ topo.pkg_id = cpu->socket_id;
+ topo.core_id = cpu->core_id;
+ topo.smt_id = cpu->thread_id;
+ cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo);
+ }
+
+ /* if 'address' properties socket-id/core-id/thread-id are not set, set them
+ * so that machine_query_hotpluggable_cpus would show correct values
+ */
+ topo_ids_from_idx(cs->cpu_index, smp_cores, smp_threads, &topo);
+ if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) {
+ error_setg(errp, "property socket-id: %u doesn't match set idx:"
+ " 0x%x (socket-id: %u)", cpu->socket_id, cs->cpu_index, topo.pkg_id);
+ return;
+ }
+ cpu->socket_id = topo.pkg_id;
+
+ if (cpu->core_id != -1 && cpu->core_id != topo.core_id) {
+ error_setg(errp, "property core-id: %u doesn't match set idx:"
+ " 0x%x (core-id: %u)", cpu->core_id, cs->cpu_index, topo.core_id);
+ return;
+ }
+ cpu->core_id = topo.core_id;
+
+ if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) {
+ error_setg(errp, "property thread-id: %u doesn't match set idx:"
+ " 0x%x (thread-id: %u)", cpu->thread_id, cs->cpu_index, topo.smt_id);
+ return;
+ }
+ cpu->thread_id = topo.smt_id;
}
static void virt_cpu_plug(HotplugHandler *hotplug_dev,
diff --git a/include/hw/arm/topology.h b/include/hw/arm/topology.h
new file mode 100644
index 0000000000..a3e5f436c5
--- /dev/null
+++ b/include/hw/arm/topology.h
@@ -0,0 +1,61 @@
+/*
+ * ARM CPU topology data structures and functions
+ *
+ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_ARM_TOPOLOGY_H
+#define HW_ARM_TOPOLOGY_H
+
+typedef struct ARMCPUTopoInfo {
+ unsigned pkg_id;
+ unsigned core_id;
+ unsigned smt_id;
+} ARMCPUTopoInfo;
+
+/* Calculate (contiguous) CPU index based on topology */
+static inline unsigned idx_from_topo_ids(unsigned nr_cores,
+ unsigned nr_threads,
+ const ARMCPUTopoInfo *topo)
+{
+ assert(nr_cores > 0);
+ assert(nr_threads > 0);
+ assert(topo != NULL);
+
+ return topo->pkg_id * nr_cores * nr_threads +
+ topo->core_id * nr_threads +
+ topo->smt_id;
+}
+
+/* Calculate thread/core/package topology
+ * based on (contiguous) CPU index
+ */
+static inline void topo_ids_from_idx(unsigned cpu_index,
+ unsigned nr_cores,
+ unsigned nr_threads,
+ ARMCPUTopoInfo *topo)
+{
+ assert(nr_cores > 0);
+ assert(nr_threads > 0);
+ assert(topo != NULL);
+
+ topo->smt_id = cpu_index % nr_threads;
+ topo->core_id = cpu_index / nr_threads % nr_cores;
+ topo->pkg_id = cpu_index / nr_threads / nr_cores;
+}
+
+#endif /* HW_ARM_TOPOLOGY_H */
+
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 1ccb30e5eb..91f1e36cd8 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2560,6 +2560,9 @@ static Property arm_cpu_properties[] = {
DEFINE_PROP_UINT64("mp-affinity", ARMCPU,
mp_affinity, ARM64_AFFINITY_INVALID),
DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
+ DEFINE_PROP_INT32("socket-id", ARMCPU, socket_id, -1),
+ DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1),
+ DEFINE_PROP_INT32("thread-id", ARMCPU, thread_id, -1),
DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e19531a77b..219c222b89 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -916,6 +916,9 @@ struct ARMCPU {
QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
int32_t node_id; /* NUMA node this CPU belongs to */
+ int32_t socket_id;
+ int32_t core_id;
+ int32_t thread_id;
/* Used to synchronize KVM and QEMU in-kernel device levels */
uint8_t device_irq_level;
--
2.19.1

View File

@ -0,0 +1,61 @@
From 31873c4c0454fb17654f57adece2bc396415f8bf Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:50:40 +0800
Subject: [PATCH] arm/virt: Add cpu_hotplug_enabled field
Some conditions must be satisfied to support CPU hotplug, including
ACPI, GED, 64bit CPU, GICv3.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 7 +++++++
include/hw/arm/virt.h | 1 +
2 files changed, 8 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index dda22194b5..304a4c2d31 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1645,6 +1645,7 @@ static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine);
+ MachineState *ms = MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const CPUArchIdList *possible_cpus;
MemoryRegion *sysmem = get_system_memory();
@@ -1655,6 +1656,7 @@ static void machvirt_init(MachineState *machine)
bool has_ged = !vmc->no_ged;
unsigned int smp_cpus = machine->smp.cpus;
unsigned int max_cpus = machine->smp.max_cpus;
+ ObjectClass *cpu_class;
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
@@ -1760,6 +1762,11 @@ static void machvirt_init(MachineState *machine)
create_fdt(vms);
+ cpu_class = object_class_by_name(ms->cpu_type);
+ vms->cpu_hotplug_enabled = has_ged && firmware_loaded &&
+ acpi_enabled && vms->gic_version == 3 &&
+ !!object_class_dynamic_cast(cpu_class, TYPE_AARCH64_CPU);
+
possible_cpus = mc->possible_cpu_arch_ids(machine);
for (n = 0; n < possible_cpus->len; n++) {
Object *cpuobj;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index beef4c8002..b4c53d920e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -126,6 +126,7 @@ typedef struct {
bool highmem_ecam;
bool its;
bool virt;
+ bool cpu_hotplug_enabled;
int32_t gic_version;
VirtIOMMUType iommu;
struct arm_boot_info bootinfo;
--
2.19.1

View File

@ -0,0 +1,66 @@
From 7cfb37c50209208f853c6fbd0df6673a95e03ef9 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 14:16:40 +0800
Subject: [PATCH] arm/virt: Add some sanity checks in cpu_pre_plug hook
For that user will try to hotplug a CPU when preconditions
are not satisfied, check these CPU hotplug preconditions in
pre_plug hook.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 983084c459..c6a99e683a 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2086,10 +2086,30 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev);
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+ const CPUArchId *cpu_slot = NULL;
MemoryRegion *sysmem = get_system_memory();
int smp_cores = ms->smp.cores;
int smp_threads = ms->smp.threads;
+ /* Some hotplug capability checks */
+
+ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
+ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
+ ms->cpu_type);
+ return;
+ }
+
+ if (dev->hotplugged && !vms->acpi_dev) {
+ error_setg(errp, "CPU hotplug is disabled: missing acpi device.");
+ return;
+ }
+
+ if (dev->hotplugged && !vms->cpu_hotplug_enabled) {
+ error_setg(errp, "CPU hotplug is disabled: "
+ "should use AArch64 CPU and GICv3.");
+ return;
+ }
+
/* if cpu idx is not set, set it based on socket/core/thread properties */
if (cs->cpu_index == UNASSIGNED_CPU_INDEX) {
int max_socket = ms->smp.max_cpus / smp_threads / smp_cores;
@@ -2145,6 +2165,13 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id,
"mp-affinity", NULL);
+ cpu_slot = &possible_cpus->cpus[cs->cpu_index];
+ if (cpu_slot->cpu) {
+ error_setg(errp, "CPU[%d] with mp_affinity %" PRIu64 " exists",
+ cs->cpu_index, cpu->mp_affinity);
+ return;
+ }
+
numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
&error_fatal);
--
2.19.1

View File

@ -0,0 +1,100 @@
From d38d1d4e859450535ddc6bf0c7a59f6217b1403c Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Sun, 5 Apr 2020 16:03:15 +0800
Subject: [PATCH] arm/virt: Attach ACPI CPU hotplug support to virt
Attach cpus aml building and GED support for CPU hotplug to
arm/virt, but currently we make it diabled by not add CPU
hotplug event to GED.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 15 ++++++++++++++-
hw/arm/virt.c | 6 ++++++
include/hw/arm/virt.h | 1 +
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 8b68a15d76..dbe9acb148 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -806,6 +806,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
MachineState *ms = MACHINE(vms);
const MemMapEntry *memmap = vms->memmap;
const int *irqmap = vms->irqmap;
+ bool cpu_aml_built = false;
dsdt = init_aml_allocator();
/* Reserve space for header */
@@ -817,7 +818,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* the RTC ACPI device at all when using UEFI.
*/
scope = aml_scope("\\_SB");
- acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms);
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
@@ -845,6 +845,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AML_SYSTEM_MEMORY,
memmap[VIRT_PCDIMM_ACPI].base);
}
+
+ if (event & ACPI_GED_CPU_HOTPLUG_EVT) {
+ CPUHotplugFeatures opts = {
+ .acpi_1_compatible = false, .has_legacy_cphp = false
+ };
+ build_cpus_aml(dsdt, ms, opts, memmap[VIRT_CPU_ACPI].base,
+ "\\_SB", NULL, AML_SYSTEM_MEMORY);
+ cpu_aml_built = true;
+ }
+ }
+
+ if (!cpu_aml_built) {
+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms);
}
acpi_dsdt_add_power_button(scope);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 8638aeedb7..d09a5773df 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -140,6 +140,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
+ [VIRT_CPU_ACPI] = { 0x09090000, ACPI_CPU_HOTPLUG_REG_LEN },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
[VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
@@ -645,11 +646,16 @@ 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.
+ */
+
dev = qdev_create(NULL, TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, vms->memmap[VIRT_CPU_ACPI].base);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq));
qdev_init_nofail(dev);
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index cbdea7ff32..6880ebe07c 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -81,6 +81,7 @@ enum {
VIRT_SECURE_MEM,
VIRT_PCDIMM_ACPI,
VIRT_ACPI_GED,
+ VIRT_CPU_ACPI,
VIRT_LOWMEMMAP_LAST,
};
--
2.19.1

View File

@ -0,0 +1,124 @@
From bf47ef282bfe8b0a98e1f87d8708051ffa7192a1 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:55:11 +0800
Subject: [PATCH] arm/virt: Pre-sizing MADT-GICC PPTT GICv3 and Pre-park KVM
vCPU
Establish all pre-sizing facilities based on cpu_hotplug_enabled
field.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt-acpi-build.c | 12 +++++++++++-
hw/arm/virt.c | 14 ++++++++++++--
target/arm/kvm.c | 6 +++---
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index efac788ba1..2cfac7b84f 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -736,6 +736,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base);
gicd->version = vms->gic_version;
+ if (vms->cpu_hotplug_enabled) {
+ num_cpu = ms->smp.max_cpus;
+ }
for (i = 0; i < num_cpu; i++) {
virt_madt_cpu_entry(NULL, i, possible_cpus, table_data);
}
@@ -902,9 +905,11 @@ static
void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
{
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+ MachineState *ms = MACHINE(vms);
GArray *table_offsets;
unsigned dsdt, xsdt;
GArray *tables_blob = tables->table_data;
+ int num_cpus;
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -923,7 +928,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
- build_pptt(tables_blob, tables->linker, vms->smp_cpus);
+ if (vms->cpu_hotplug_enabled) {
+ num_cpus = ms->smp.max_cpus;
+ } else {
+ num_cpus = ms->smp.cpus;
+ }
+ build_pptt(tables_blob, tables->linker, num_cpus);
acpi_add_table(table_offsets, tables_blob);
build_madt(tables_blob, tables->linker, vms);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 304a4c2d31..983084c459 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -767,6 +767,9 @@ static void create_gic(VirtMachineState *vms)
unsigned int smp_cpus = ms->smp.cpus;
uint32_t nb_redist_regions = 0;
+ if (vms->cpu_hotplug_enabled) {
+ num_cpus = ms->smp.max_cpus;
+ }
assert(num_cpus >= smp_cpus);
gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
@@ -1772,8 +1775,15 @@ static void machvirt_init(MachineState *machine)
Object *cpuobj;
CPUState *cs;
+ if (kvm_enabled() && vms->cpu_hotplug_enabled) {
+ if (kvm_create_parked_vcpu(n) < 0) {
+ error_report("mach-virt: Create KVM parked vCPU failed");
+ exit(1);
+ }
+ }
+
if (n >= smp_cpus) {
- break;
+ continue;
}
cpuobj = object_new(possible_cpus->cpus[n].type);
@@ -1857,7 +1867,7 @@ static void machvirt_init(MachineState *machine)
vms->bootinfo.kernel_filename = machine->kernel_filename;
vms->bootinfo.kernel_cmdline = machine->kernel_cmdline;
vms->bootinfo.initrd_filename = machine->initrd_filename;
- vms->bootinfo.nb_cpus = smp_cpus;
+ vms->bootinfo.nb_cpus = vms->cpu_hotplug_enabled ? max_cpus : smp_cpus;
vms->bootinfo.board_id = -1;
vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base;
vms->bootinfo.get_dtb = machvirt_dtb;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 327b3bc338..4f131f687d 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -202,7 +202,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
int ret = 0;
- unsigned int smp_cpus = ms->smp.cpus;
+ unsigned int max_cpus = ms->smp.max_cpus;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -216,9 +216,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
- if (smp_cpus > 256 &&
+ if (max_cpus > 256 &&
!kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
- error_report("Using more than 256 vcpus requires a host kernel "
+ error_report("Using more than max 256 vcpus requires a host kernel "
"with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
ret = -EINVAL;
}
--
2.19.1

View File

@ -0,0 +1,159 @@
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

View File

@ -0,0 +1,65 @@
From 91fed8840b004ec7bc91969afa10f03e13f311c4 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Wed, 22 Apr 2020 19:52:58 +0800
Subject: [PATCH] arm/virt/acpi: Extend cpufreq to support max_cpus
We will support CPU hotplug soon, so extend memory region size to
allow hotplugged CPU access cpufreq space.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/cpufreq.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c
index d02a25a6de..38dcab5683 100644
--- a/hw/acpi/cpufreq.c
+++ b/hw/acpi/cpufreq.c
@@ -84,6 +84,7 @@ typedef struct CpuhzState {
uint32_t PerformanceLimited;
uint32_t LowestFreq;
uint32_t NominalFreq;
+ uint32_t num_cpu;
uint32_t reg_size;
} CpuhzState;
@@ -95,10 +96,7 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset,
uint64_t r;
uint64_t n;
- MachineState *ms = MACHINE(qdev_get_machine());
- unsigned int smp_cpus = ms->smp.cpus;
-
- if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) {
+ if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) {
warn_report("cpufreq_read: offset 0x%lx out of range", offset);
return 0;
}
@@ -166,11 +164,10 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset,
static void cpufreq_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
+ CpuhzState *s = CPUFREQ(opaque);
uint64_t n;
- MachineState *ms = MACHINE(qdev_get_machine());
- unsigned int smp_cpus = ms->smp.cpus;
- if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) {
+ if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) {
error_printf("cpufreq_write: offset 0x%lx out of range", offset);
return;
}
@@ -251,9 +248,9 @@ static void cpufreq_init(Object *obj)
CpuhzState *s = CPUFREQ(obj);
MachineState *ms = MACHINE(qdev_get_machine());
- unsigned int smp_cpus = ms->smp.cpus;
+ s->num_cpu = ms->smp.max_cpus;
- s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE;
+ s->reg_size = s->num_cpu * CPPC_REG_PER_CPU_STRIDE;
if (s->reg_size > MAX_SUPPORT_SPACE) {
error_report("Required space 0x%x excesses the max support 0x%x",
s->reg_size, MAX_SUPPORT_SPACE);
--
2.19.1

View File

@ -0,0 +1,121 @@
From 2fdece10dac6161cb6c1f0f05247391aa3269eed Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Wed, 22 Apr 2020 15:58:27 +0800
Subject: [PATCH] arm/virt/acpi: Factor out CPPC building from DSDT CPU aml
When CPU hotplug is enabled, we will use build_cpus_aml instead of
acpi_dsdt_add_cpus, so factor out CPPC building and we can reuse it
in build_cpus_aml.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/acpi/generic_event_device.c | 1 +
hw/arm/virt-acpi-build.c | 33 +++++++++++++++++-----------
include/hw/acpi/acpi_dev_interface.h | 2 ++
include/hw/arm/virt.h | 2 ++
4 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index b834ae3ff6..82139b4314 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -289,6 +289,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
adevc->send_event = acpi_ged_send_event;
adevc->madt_cpu = virt_madt_cpu_entry;
+ adevc->cpu_cppc = virt_acpi_dsdt_cpu_cppc;
}
static const TypeInfo acpi_ged_info = {
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 4b6aace433..8b68a15d76 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -111,8 +111,24 @@ static void acpi_dsdt_add_cppc(Aml *dev, uint64_t cpu_base, int *regs_offset)
aml_append(dev, aml_name_decl("_CPC", cpc));
}
-static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus,
- const MemMapEntry *cppc_memmap)
+void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int ncpu, int num_cpu, Aml *dev)
+{
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+ const MemMapEntry *cppc_memmap = &vms->memmap[VIRT_CPUFREQ];
+
+ /*
+ * Append _CPC and _PSD to support CPU frequence show
+ * Check CPPC available by DESIRED_PERF register
+ */
+ if (cppc_regs_offset[DESIRED_PERF] != -1) {
+ acpi_dsdt_add_cppc(dev,
+ cppc_memmap->base + ncpu * CPPC_REG_PER_CPU_STRIDE,
+ cppc_regs_offset);
+ acpi_dsdt_add_psd(dev, num_cpu);
+ }
+}
+
+static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, VirtMachineState *vms)
{
uint16_t i;
@@ -121,16 +137,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus,
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
- /*
- * Append _CPC and _PSD to support CPU frequence show
- * Check CPPC available by DESIRED_PERF register
- */
- if (cppc_regs_offset[DESIRED_PERF] != -1) {
- acpi_dsdt_add_cppc(dev,
- cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE,
- cppc_regs_offset);
- acpi_dsdt_add_psd(dev, smp_cpus);
- }
+ virt_acpi_dsdt_cpu_cppc(NULL, i, smp_cpus, dev);
aml_append(scope, dev);
}
@@ -810,7 +817,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* the RTC ACPI device at all when using UEFI.
*/
scope = aml_scope("\\_SB");
- acpi_dsdt_add_cpus(scope, vms->smp_cpus, &memmap[VIRT_CPUFREQ]);
+ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms);
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index adcb3a816c..2952914569 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -3,6 +3,7 @@
#include "qom/object.h"
#include "hw/boards.h"
+#include "hw/acpi/aml-build.h"
/* These values are part of guest ABI, and can not be changed */
typedef enum {
@@ -55,5 +56,6 @@ typedef struct AcpiDeviceIfClass {
void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev);
void (*madt_cpu)(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry);
+ void (*cpu_cppc)(AcpiDeviceIf *adev, int uid, int num_cpu, Aml *dev);
} AcpiDeviceIfClass;
#endif
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 6b1f10b231..cbdea7ff32 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -157,6 +157,8 @@ typedef struct {
void virt_acpi_setup(VirtMachineState *vms);
void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *cpu_list, GArray *entry);
+void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int uid,
+ int num_cpu, Aml *dev);
/* Return the number of used redistributor regions */
static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
--
2.19.1

View File

@ -0,0 +1,123 @@
From 92124743f4560c490780a229f53ea5881f706383 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Sun, 5 Apr 2020 15:29:16 +0800
Subject: [PATCH] arm/virt/gic: Construct irqs connection from create_gic
Make the irqs can be connected to for individual CPU.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 90 ++++++++++++++++++++++++++++-----------------------
1 file changed, 49 insertions(+), 41 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 83f4887e57..55d403bad6 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -706,6 +706,54 @@ static void create_v2m(VirtMachineState *vms)
fdt_add_v2m_gic_node(vms);
}
+static void connect_gic_cpu_irqs(VirtMachineState *vms, int i)
+{
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+ SysBusDevice *gicbusdev = SYS_BUS_DEVICE(vms->gic);
+ int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
+ int num_cpus = object_property_get_uint(OBJECT(vms->gic), "num-cpu", NULL);
+ int gic_type = vms->gic_version;
+ int irq;
+ /* Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs we use for the virt board.
+ */
+ const int timer_irq[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ };
+
+ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
+ qdev_connect_gpio_out(cpudev, irq,
+ qdev_get_gpio_in(vms->gic,
+ ppibase + timer_irq[irq]));
+ }
+
+ if (gic_type == 3) {
+ qemu_irq irq = qdev_get_gpio_in(vms->gic,
+ ppibase + ARCH_GIC_MAINT_IRQ);
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
+ 0, irq);
+ } else if (vms->virt) {
+ qemu_irq irq = qdev_get_gpio_in(vms->gic,
+ ppibase + ARCH_GIC_MAINT_IRQ);
+ sysbus_connect_irq(gicbusdev, i + 4 * num_cpus, irq);
+ }
+
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
+ qdev_get_gpio_in(vms->gic, ppibase
+ + VIRTUAL_PMU_IRQ));
+
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicbusdev, i + num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ sysbus_connect_irq(gicbusdev, i + 2 * num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+ sysbus_connect_irq(gicbusdev, i + 3 * num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+}
+
static void create_gic(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
@@ -775,47 +823,7 @@ static void create_gic(VirtMachineState *vms)
* and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
*/
for (i = 0; i < smp_cpus; i++) {
- DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
- int irq;
- /* Mapping from the output timer irq lines from the CPU to the
- * GIC PPI inputs we use for the virt board.
- */
- const int timer_irq[] = {
- [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
- [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
- [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
- [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
- };
-
- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
- qdev_connect_gpio_out(cpudev, irq,
- qdev_get_gpio_in(vms->gic,
- ppibase + timer_irq[irq]));
- }
-
- if (type == 3) {
- qemu_irq irq = qdev_get_gpio_in(vms->gic,
- ppibase + ARCH_GIC_MAINT_IRQ);
- qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
- 0, irq);
- } else if (vms->virt) {
- qemu_irq irq = qdev_get_gpio_in(vms->gic,
- ppibase + ARCH_GIC_MAINT_IRQ);
- sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq);
- }
-
- qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
- qdev_get_gpio_in(vms->gic, ppibase
- + VIRTUAL_PMU_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));
- sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
- sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+ connect_gic_cpu_irqs(vms, i);
}
fdt_add_gic_node(vms);
--
2.19.1

View File

@ -0,0 +1,44 @@
From b9e4a4ff6f3292927adb1463777c86cd4063a6ef Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Sat, 18 Apr 2020 12:10:11 +0800
Subject: [PATCH] bugfix: Use gicr_typer in arm_gicv3_icc_reset
The KVM_VGIC_ATTR macro expect the second parameter as gicr_typer,
of which high 32bit is constructed by mp_affinity. For most case,
the high 32bit of mp_affinity is zero, so it will always access the
ICC_CTLR_EL1 of CPU0.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
hw/intc/arm_gicv3_kvm.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index d9c72f85be..b1e74147ba 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -661,13 +661,11 @@ static void kvm_arm_gicv3_get(GICv3State *s)
static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
- ARMCPU *cpu;
GICv3State *s;
GICv3CPUState *c;
c = (GICv3CPUState *)env->gicv3state;
s = c->gic;
- cpu = ARM_CPU(c->cpu);
c->icc_pmr_el1 = 0;
c->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
@@ -684,7 +682,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
/* 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, cpu->mp_affinity),
+ KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer),
&c->icc_ctlr_el1[GICV3_NS], false, &error_abort);
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
--
2.19.1

View File

@ -0,0 +1,115 @@
From de86ba0ff72a51b0c1cdbebf790869aea73ae9d3 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Thu, 9 Apr 2020 09:31:22 +0800
Subject: [PATCH] hw/arm/boot: Add manually register and trigger of CPU reset
We need to register and trigger CPU reset manually for hotplugged
CPU. Besides, we gather CPU reset handlers of all CPUs because CPU
reset should happen before GIC reset.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/boot.c | 18 ++++++++++++++++++
hw/core/reset.c | 25 +++++++++++++++++++++++++
include/hw/arm/boot.h | 3 +++
include/sysemu/reset.h | 4 ++++
4 files changed, 50 insertions(+)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index fc4e021a38..3ab9de6456 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -789,6 +789,24 @@ static void do_cpu_reset(void *opaque)
}
}
+void cpu_hotplug_register_reset(int ncpu)
+{
+ CPUState *cpu_0 = qemu_get_cpu(0);
+ CPUState *cpu = qemu_get_cpu(ncpu);
+ QEMUResetEntry *entry = qemu_get_reset_entry(do_cpu_reset, cpu_0);
+
+ assert(entry);
+ /* Gather the reset handlers of all CPUs */
+ qemu_register_reset_after(entry, do_cpu_reset, cpu);
+}
+
+void cpu_hotplug_reset_manually(int ncpu)
+{
+ CPUState *cpu = qemu_get_cpu(ncpu);
+
+ do_cpu_reset(cpu);
+}
+
/**
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
* by key.
diff --git a/hw/core/reset.c b/hw/core/reset.c
index 9c477f2bf5..0efaf2d76c 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -47,6 +47,31 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque)
QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
}
+QEMUResetEntry *qemu_get_reset_entry(QEMUResetHandler *func,
+ void *opaque)
+{
+ QEMUResetEntry *re;
+
+ QTAILQ_FOREACH(re, &reset_handlers, entry) {
+ if (re->func == func && re->opaque == opaque) {
+ return re;
+ }
+ }
+
+ return NULL;
+}
+
+void qemu_register_reset_after(QEMUResetEntry *entry,
+ QEMUResetHandler *func,
+ void *opaque)
+{
+ QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry));
+
+ re->func = func;
+ re->opaque = opaque;
+ QTAILQ_INSERT_AFTER(&reset_handlers, entry, re, entry);
+}
+
void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
{
QEMUResetEntry *re;
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
index c48cc4c2bc..9452ccd1fa 100644
--- a/include/hw/arm/boot.h
+++ b/include/hw/arm/boot.h
@@ -118,6 +118,9 @@ struct arm_boot_info {
arm_endianness endianness;
};
+void cpu_hotplug_register_reset(int ncpu);
+void cpu_hotplug_reset_manually(int ncpu);
+
/**
* arm_load_kernel - Loads memory with everything needed to boot
*
diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h
index 0b0d6d7598..f3ff26c637 100644
--- a/include/sysemu/reset.h
+++ b/include/sysemu/reset.h
@@ -2,7 +2,11 @@
#define QEMU_SYSEMU_RESET_H
typedef void QEMUResetHandler(void *opaque);
+typedef struct QEMUResetEntry QEMUResetEntry;
+QEMUResetEntry *qemu_get_reset_entry(QEMUResetHandler *func, void *opaque);
+void qemu_register_reset_after(QEMUResetEntry *entry,
+ QEMUResetHandler *func, void *opaque);
void qemu_register_reset(QEMUResetHandler *func, void *opaque);
void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
void qemu_devices_reset(void);
--
2.19.1

View File

@ -0,0 +1,170 @@
From 3a0af1446395e74476a763ca12713b28c099a144 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 6 Apr 2020 12:50:54 +0800
Subject: [PATCH] hw/arm/virt: Factor out some CPU init codes to pre_plug hook
The init path of hotplugged CPU is pre_plug/realize/plug, so we
must move these init code in machvirt_init to pre_plug hook, to
let them be shared by all CPUs.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 108 +++++++++++++++++++++++++++-----------------------
1 file changed, 58 insertions(+), 50 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 64532b61b2..83f4887e57 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -196,6 +196,8 @@ static const char *valid_cpus[] = {
ARM_CPU_TYPE_NAME("max"),
};
+static MemoryRegion *secure_sysmem;
+
static bool cpu_type_valid(const char *cpu)
{
int i;
@@ -1629,7 +1631,6 @@ static void machvirt_init(MachineState *machine)
MachineClass *mc = MACHINE_GET_CLASS(machine);
const CPUArchIdList *possible_cpus;
MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *secure_sysmem = NULL;
int n, virt_max_cpus;
MemoryRegion *ram = g_new(MemoryRegion, 1);
bool firmware_loaded;
@@ -1752,57 +1753,10 @@ static void machvirt_init(MachineState *machine)
}
cpuobj = object_new(possible_cpus->cpus[n].type);
- object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id,
- "mp-affinity", NULL);
+ aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL);
cs = CPU(cpuobj);
cs->cpu_index = n;
-
- numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
- &error_fatal);
-
- aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL);
-
- if (!vms->secure) {
- object_property_set_bool(cpuobj, false, "has_el3", NULL);
- }
-
- if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) {
- object_property_set_bool(cpuobj, false, "has_el2", NULL);
- }
-
- if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
- object_property_set_int(cpuobj, vms->psci_conduit,
- "psci-conduit", NULL);
-
- /* Secondary CPUs start in PSCI powered-down state */
- if (n > 0) {
- object_property_set_bool(cpuobj, true,
- "start-powered-off", NULL);
- }
- }
-
- if (vmc->kvm_no_adjvtime &&
- object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) {
- object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL);
- }
-
- if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) {
- object_property_set_bool(cpuobj, false, "pmu", NULL);
- }
-
- if (object_property_find(cpuobj, "reset-cbar", NULL)) {
- object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base,
- "reset-cbar", &error_abort);
- }
-
- object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
- &error_abort);
- if (vms->secure) {
- object_property_set_link(cpuobj, OBJECT(secure_sysmem),
- "secure-memory", &error_abort);
- }
-
object_property_set_bool(cpuobj, true, "realized", &error_fatal);
object_unref(cpuobj);
}
@@ -2089,10 +2043,16 @@ out:
static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- CPUState *cs = CPU(dev);
ARMCPUTopoInfo topo;
+ Object *cpuobj = OBJECT(dev);
+ CPUState *cs = CPU(dev);
ARMCPU *cpu = ARM_CPU(dev);
MachineState *ms = MACHINE(hotplug_dev);
+ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+ MemoryRegion *sysmem = get_system_memory();
int smp_cores = ms->smp.cores;
int smp_threads = ms->smp.threads;
@@ -2145,6 +2105,54 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
return;
}
cpu->thread_id = topo.smt_id;
+
+ /* Init some properties */
+
+ object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id,
+ "mp-affinity", NULL);
+
+ numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
+ &error_fatal);
+
+ if (!vms->secure) {
+ object_property_set_bool(cpuobj, false, "has_el3", NULL);
+ }
+
+ if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el2", NULL);
+ }
+
+ if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
+ object_property_set_int(cpuobj, vms->psci_conduit,
+ "psci-conduit", NULL);
+
+ /* Secondary CPUs start in PSCI powered-down state */
+ if (cs->cpu_index > 0) {
+ object_property_set_bool(cpuobj, true,
+ "start-powered-off", NULL);
+ }
+ }
+
+ if (vmc->kvm_no_adjvtime &&
+ object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) {
+ object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL);
+ }
+
+ if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) {
+ object_property_set_bool(cpuobj, false, "pmu", NULL);
+ }
+
+ if (object_property_find(cpuobj, "reset-cbar", NULL)) {
+ object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base,
+ "reset-cbar", &error_abort);
+ }
+
+ object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
+ &error_abort);
+ if (vms->secure) {
+ object_property_set_link(cpuobj, OBJECT(secure_sysmem),
+ "secure-memory", &error_abort);
+ }
}
static void virt_cpu_plug(HotplugHandler *hotplug_dev,
--
2.19.1

View File

@ -0,0 +1,402 @@
From 5d1be90750551f1debf5767d7a6e2b9c50054c05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@redhat.com>
Date: Mon, 9 Dec 2019 10:03:06 +0100
Subject: [PATCH] hw/arm/virt: Simplify by moving the gic in the machine state
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Make the gic a field in the machine state, and instead of filling
an array of qemu_irq and passing it around, directly call
qdev_get_gpio_in() on the gic field.
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
Message-id: 20191209090306.20433-1-philmd@redhat.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt.c | 109 +++++++++++++++++++++---------------------
include/hw/arm/virt.h | 1 +
2 files changed, 55 insertions(+), 55 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 18321e522b..8638aeedb7 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -634,7 +634,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
}
}
-static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic)
+static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
{
DeviceState *dev;
MachineState *ms = MACHINE(vms);
@@ -650,14 +650,14 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq));
qdev_init_nofail(dev);
return dev;
}
-static void create_its(VirtMachineState *vms, DeviceState *gicdev)
+static void create_its(VirtMachineState *vms)
{
const char *itsclass = its_class_name();
DeviceState *dev;
@@ -669,7 +669,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev)
dev = qdev_create(NULL, itsclass);
- object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3",
+ object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3",
&error_abort);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base);
@@ -677,7 +677,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev)
fdt_add_its_gic_node(vms);
}
-static void create_v2m(VirtMachineState *vms, qemu_irq *pic)
+static void create_v2m(VirtMachineState *vms)
{
int i;
int irq = vms->irqmap[VIRT_GIC_V2M];
@@ -690,17 +690,17 @@ static void create_v2m(VirtMachineState *vms, qemu_irq *pic)
qdev_init_nofail(dev);
for (i = 0; i < NUM_GICV2M_SPIS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+ qdev_get_gpio_in(vms->gic, irq + i));
}
fdt_add_v2m_gic_node(vms);
}
-static void create_gic(VirtMachineState *vms, qemu_irq *pic)
+static void create_gic(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
/* We create a standalone GIC */
- DeviceState *gicdev;
SysBusDevice *gicbusdev;
const char *gictype;
int type = vms->gic_version, i;
@@ -709,15 +709,15 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
- gicdev = qdev_create(NULL, gictype);
- qdev_prop_set_uint32(gicdev, "revision", type);
- qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
+ vms->gic = qdev_create(NULL, gictype);
+ qdev_prop_set_uint32(vms->gic, "revision", type);
+ qdev_prop_set_uint32(vms->gic, "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).
*/
- qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
+ qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
if (!kvm_irqchip_in_kernel()) {
- qdev_prop_set_bit(gicdev, "has-security-extensions", vms->secure);
+ qdev_prop_set_bit(vms->gic, "has-security-extensions", vms->secure);
}
if (type == 3) {
@@ -727,25 +727,25 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
nb_redist_regions = virt_gicv3_redist_region_count(vms);
- qdev_prop_set_uint32(gicdev, "len-redist-region-count",
+ qdev_prop_set_uint32(vms->gic, "len-redist-region-count",
nb_redist_regions);
- qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count);
+ qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count);
if (nb_redist_regions == 2) {
uint32_t redist1_capacity =
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
- qdev_prop_set_uint32(gicdev, "redist-region-count[1]",
+ qdev_prop_set_uint32(vms->gic, "redist-region-count[1]",
MIN(smp_cpus - redist0_count, redist1_capacity));
}
} else {
if (!kvm_irqchip_in_kernel()) {
- qdev_prop_set_bit(gicdev, "has-virtualization-extensions",
+ qdev_prop_set_bit(vms->gic, "has-virtualization-extensions",
vms->virt);
}
}
- qdev_init_nofail(gicdev);
- gicbusdev = SYS_BUS_DEVICE(gicdev);
+ qdev_init_nofail(vms->gic);
+ gicbusdev = SYS_BUS_DEVICE(vms->gic);
sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base);
if (type == 3) {
sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base);
@@ -781,23 +781,23 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
qdev_connect_gpio_out(cpudev, irq,
- qdev_get_gpio_in(gicdev,
+ qdev_get_gpio_in(vms->gic,
ppibase + timer_irq[irq]));
}
if (type == 3) {
- qemu_irq irq = qdev_get_gpio_in(gicdev,
+ qemu_irq irq = qdev_get_gpio_in(vms->gic,
ppibase + ARCH_GIC_MAINT_IRQ);
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
0, irq);
} else if (vms->virt) {
- qemu_irq irq = qdev_get_gpio_in(gicdev,
+ qemu_irq irq = qdev_get_gpio_in(vms->gic,
ppibase + ARCH_GIC_MAINT_IRQ);
sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq);
}
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
- qdev_get_gpio_in(gicdev, ppibase
+ qdev_get_gpio_in(vms->gic, ppibase
+ VIRTUAL_PMU_IRQ));
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
@@ -809,20 +809,16 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
- for (i = 0; i < NUM_IRQS; i++) {
- pic[i] = qdev_get_gpio_in(gicdev, i);
- }
-
fdt_add_gic_node(vms);
if (type == 3 && vms->its) {
- create_its(vms, gicdev);
+ create_its(vms);
} else if (type == 2) {
- create_v2m(vms, pic);
+ create_v2m(vms);
}
}
-static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart,
+static void create_uart(const VirtMachineState *vms, int uart,
MemoryRegion *mem, Chardev *chr)
{
char *nodename;
@@ -838,7 +834,7 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart,
qdev_init_nofail(dev);
memory_region_add_subregion(mem, base,
sysbus_mmio_get_region(s, 0));
- sysbus_connect_irq(s, 0, pic[irq]);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
nodename = g_strdup_printf("/pl011@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
@@ -880,7 +876,7 @@ static void create_cpufreq(const VirtMachineState *vms, MemoryRegion *mem)
memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
}
-static void create_rtc(const VirtMachineState *vms, qemu_irq *pic)
+static void create_rtc(const VirtMachineState *vms)
{
char *nodename;
hwaddr base = vms->memmap[VIRT_RTC].base;
@@ -888,7 +884,7 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic)
int irq = vms->irqmap[VIRT_RTC];
const char compat[] = "arm,pl031\0arm,primecell";
- sysbus_create_simple("pl031", base, pic[irq]);
+ sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
nodename = g_strdup_printf("/pl031@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
@@ -916,7 +912,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
}
}
-static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
+static void create_gpio(const VirtMachineState *vms)
{
char *nodename;
DeviceState *pl061_dev;
@@ -925,7 +921,8 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
int irq = vms->irqmap[VIRT_GPIO];
const char compat[] = "arm,pl061\0arm,primecell";
- pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
+ pl061_dev = sysbus_create_simple("pl061", base,
+ qdev_get_gpio_in(vms->gic, irq));
uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt);
nodename = g_strdup_printf("/pl061@%" PRIx64, base);
@@ -959,7 +956,7 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
g_free(nodename);
}
-static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
+static void create_virtio_devices(const VirtMachineState *vms)
{
int i;
hwaddr size = vms->memmap[VIRT_MMIO].size;
@@ -995,7 +992,8 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
int irq = vms->irqmap[VIRT_MMIO] + i;
hwaddr base = vms->memmap[VIRT_MMIO].base + i * size;
- sysbus_create_simple("virtio-mmio", base, pic[irq]);
+ sysbus_create_simple("virtio-mmio", base,
+ qdev_get_gpio_in(vms->gic, irq));
}
/* We add dtb nodes in reverse order so that they appear in the finished
@@ -1244,7 +1242,7 @@ static void create_pcie_irq_map(const VirtMachineState *vms,
0x7 /* PCI irq */);
}
-static void create_smmu(const VirtMachineState *vms, qemu_irq *pic,
+static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
char *node;
@@ -1267,7 +1265,8 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic,
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
for (i = 0; i < NUM_SMMU_IRQS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+ qdev_get_gpio_in(vms->gic, irq + i));
}
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
@@ -1294,7 +1293,7 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic,
g_free(node);
}
-static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
+static void create_pcie(VirtMachineState *vms)
{
hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base;
hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size;
@@ -1354,7 +1353,8 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
for (i = 0; i < GPEX_NUM_IRQS; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+ qdev_get_gpio_in(vms->gic, irq + i));
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
}
@@ -1414,7 +1414,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
if (vms->iommu) {
vms->iommu_phandle = qemu_fdt_alloc_phandle(vms->fdt);
- create_smmu(vms, pic, pci->bus);
+ create_smmu(vms, pci->bus);
qemu_fdt_setprop_cells(vms->fdt, nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x10000);
@@ -1423,7 +1423,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
g_free(nodename);
}
-static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic)
+static void create_platform_bus(VirtMachineState *vms)
{
DeviceState *dev;
SysBusDevice *s;
@@ -1439,8 +1439,8 @@ static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic)
s = SYS_BUS_DEVICE(dev);
for (i = 0; i < PLATFORM_BUS_NUM_IRQS; i++) {
- int irqn = vms->irqmap[VIRT_PLATFORM_BUS] + i;
- sysbus_connect_irq(s, i, pic[irqn]);
+ int irq = vms->irqmap[VIRT_PLATFORM_BUS] + i;
+ sysbus_connect_irq(s, i, qdev_get_gpio_in(vms->gic, irq));
}
memory_region_add_subregion(sysmem,
@@ -1621,7 +1621,6 @@ static void machvirt_init(MachineState *machine)
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const CPUArchIdList *possible_cpus;
- qemu_irq pic[NUM_IRQS];
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *secure_sysmem = NULL;
int n, virt_max_cpus;
@@ -1829,29 +1828,29 @@ static void machvirt_init(MachineState *machine)
virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
- create_gic(vms, pic);
+ create_gic(vms);
fdt_add_pmu_nodes(vms);
- create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0));
+ create_uart(vms, VIRT_UART, sysmem, serial_hd(0));
create_cpufreq(vms, sysmem);
if (vms->secure) {
create_secure_ram(vms, secure_sysmem);
- create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1));
+ create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1));
}
vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64);
- create_rtc(vms, pic);
+ create_rtc(vms);
- create_pcie(vms, pic);
+ create_pcie(vms);
if (has_ged && aarch64 && firmware_loaded && acpi_enabled) {
- vms->acpi_dev = create_acpi_ged(vms, pic);
+ vms->acpi_dev = create_acpi_ged(vms);
} else {
- create_gpio(vms, pic);
+ create_gpio(vms);
}
/* connect powerdown request */
@@ -1862,12 +1861,12 @@ static void machvirt_init(MachineState *machine)
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
*/
- create_virtio_devices(vms, pic);
+ create_virtio_devices(vms);
vms->fw_cfg = create_fw_cfg(vms, &address_space_memory);
rom_set_fw(vms->fw_cfg);
- create_platform_bus(vms, pic);
+ create_platform_bus(vms);
vms->bootinfo.ram_size = machine->ram_size;
vms->bootinfo.kernel_filename = machine->kernel_filename;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index dcceb9c615..3dfefca93b 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -138,6 +138,7 @@ typedef struct {
uint32_t iommu_phandle;
int psci_conduit;
hwaddr highest_gpa;
+ DeviceState *gic;
DeviceState *acpi_dev;
Notifier powerdown_notifier;
} VirtMachineState;
--
2.19.1

View File

@ -0,0 +1,170 @@
From 6bbfb186c8d66b745aeb08143d3198fcedc52d6c Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Mon, 6 Apr 2020 11:26:35 +0800
Subject: [PATCH] hw/intc/gicv3: Add CPU hotplug realize hook
GICv3 exposes individual CPU realization capability through
this hook. It will be used for hotplugged CPU.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/intc/arm_gicv3.c | 17 ++++++++++++++++-
hw/intc/arm_gicv3_common.c | 8 ++++++++
hw/intc/arm_gicv3_kvm.c | 11 +++++++++++
include/hw/intc/arm_gicv3.h | 2 ++
include/hw/intc/arm_gicv3_common.h | 4 ++++
5 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 2fe79f794d..cacef26546 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -361,6 +361,19 @@ static const MemoryRegionOps gic_ops[] = {
}
};
+static void gicv3_cpu_realize(GICv3State *s, int i)
+{
+ gicv3_init_one_cpuif(s, i);
+}
+
+static void arm_gicv3_cpu_hotplug_realize(GICv3State *s, int ncpu)
+{
+ ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s);
+
+ agc->parent_cpu_hotplug_realize(s, ncpu);
+ gicv3_cpu_realize(s, ncpu);
+}
+
static void arm_gic_realize(DeviceState *dev, Error **errp)
{
/* Device instance realize function for the GIC sysbus device */
@@ -388,7 +401,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
}
for (i = 0; i < s->num_cpu; i++) {
- gicv3_init_one_cpuif(s, i);
+ gicv3_cpu_realize(s, i);
}
}
@@ -398,6 +411,8 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data)
ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
ARMGICv3Class *agc = ARM_GICV3_CLASS(klass);
+ agc->parent_cpu_hotplug_realize = agcc->cpu_hotplug_realize;
+ agcc->cpu_hotplug_realize = arm_gicv3_cpu_hotplug_realize;
agcc->post_load = arm_gicv3_post_load;
device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize);
}
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 798f295d7c..8740a52c9f 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -313,6 +313,11 @@ static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu)
gicv3_set_gicv3state(cpu, &s->cpu[ncpu]);
}
+static void arm_gicv3_common_cpu_hotplug_realize(GICv3State *s, int ncpu)
+{
+ arm_gicv3_common_cpu_realize(s, ncpu);
+}
+
static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
{
GICv3State *s = ARM_GICV3_COMMON(dev);
@@ -357,6 +362,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->num_cpu; i++) {
CPUState *cpu = qemu_get_cpu(i);
+
uint64_t cpu_affid;
int last;
@@ -508,12 +514,14 @@ static Property arm_gicv3_common_properties[] = {
static void arm_gicv3_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
dc->reset = arm_gicv3_common_reset;
dc->realize = arm_gicv3_common_realize;
dc->props = arm_gicv3_common_properties;
dc->vmsd = &vmstate_gicv3;
+ agcc->cpu_hotplug_realize = arm_gicv3_common_cpu_hotplug_realize;
albifc->arm_linux_init = arm_gic_common_linux_init;
}
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index b2936938cb..f8d7be5479 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -78,6 +78,7 @@ typedef struct KVMARMGICv3Class {
ARMGICv3CommonClass parent_class;
DeviceRealize parent_realize;
void (*parent_reset)(DeviceState *dev);
+ CPUHotplugRealize parent_cpu_hotplug_realize;
} KVMARMGICv3Class;
static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level)
@@ -768,6 +769,14 @@ static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu)
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
}
+static void kvm_arm_gicv3_cpu_hotplug_realize(GICv3State *s, int ncpu)
+{
+ KVMARMGICv3Class *kagcc = KVM_ARM_GICV3_GET_CLASS(s);
+
+ kagcc->parent_cpu_hotplug_realize(s, ncpu);
+ kvm_arm_gicv3_cpu_realize(s, ncpu);
+}
+
static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
{
GICv3State *s = KVM_ARM_GICV3(dev);
@@ -884,6 +893,8 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass);
+ kgc->parent_cpu_hotplug_realize = agcc->cpu_hotplug_realize;
+ agcc->cpu_hotplug_realize = kvm_arm_gicv3_cpu_hotplug_realize;
agcc->pre_save = kvm_arm_gicv3_get;
agcc->post_load = kvm_arm_gicv3_put;
device_class_set_parent_realize(dc, kvm_arm_gicv3_realize,
diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h
index 4a6fd85e22..98f2bdb7e9 100644
--- a/include/hw/intc/arm_gicv3.h
+++ b/include/hw/intc/arm_gicv3.h
@@ -26,6 +26,8 @@ typedef struct ARMGICv3Class {
ARMGICv3CommonClass parent_class;
/*< public >*/
+ CPUHotplugRealize parent_cpu_hotplug_realize;
+
DeviceRealize parent_realize;
} ARMGICv3Class;
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index 31ec9a1ae4..45cc50ed3b 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -286,11 +286,15 @@ GICV3_BITMAP_ACCESSORS(edge_trigger)
#define ARM_GICV3_COMMON_GET_CLASS(obj) \
OBJECT_GET_CLASS(ARMGICv3CommonClass, (obj), TYPE_ARM_GICV3_COMMON)
+typedef void (*CPUHotplugRealize)(GICv3State *s, int ncpu);
+
typedef struct ARMGICv3CommonClass {
/*< private >*/
SysBusDeviceClass parent_class;
/*< public >*/
+ CPUHotplugRealize cpu_hotplug_realize;
+
void (*pre_save)(GICv3State *s);
void (*post_load)(GICv3State *s);
} ARMGICv3CommonClass;
--
2.19.1

View File

@ -0,0 +1,357 @@
From 0a75312c069d89be94bcaa688429d8f60a0c528b Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 13:15:35 +0800
Subject: [PATCH] intc/gicv3: Add pre-sizing capability to GICv3
Currently GICv3 supports fixed smp_cpus CPUs, and all CPUs are
present always. Now we want to pre-sizing GICv3 to support max_cpus
CPUs and not all of them are present always, so some sizing codes
should be concerned.
GIC irqs, GICR and GICC are pre-created for all possible CPUs at
start, but only smp_cpus CPUs are realize and irqs of smp_cpus CPUs
are connected.
Other code changes are mainly for arm_gicv3, and we do little about
kvm_arm_gicv3 becasue KVM will deal with the sizing information properly.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/arm/virt.c | 17 +++++++++++----
hw/intc/arm_gicv3.c | 43 +++++++++++++++++++++++++-------------
hw/intc/arm_gicv3_common.c | 23 ++++++++++++++++++--
hw/intc/arm_gicv3_cpuif.c | 4 ++++
hw/intc/arm_gicv3_kvm.c | 28 ++++++++++++++++++++++++-
include/hw/arm/virt.h | 3 ++-
6 files changed, 96 insertions(+), 22 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 55d403bad6..dda22194b5 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -761,14 +761,19 @@ static void create_gic(VirtMachineState *vms)
SysBusDevice *gicbusdev;
const char *gictype;
int type = vms->gic_version, i;
+ /* The max number of CPUs suppored by GIC */
+ unsigned int num_cpus = ms->smp.cpus;
+ /* The number of CPUs present before boot */
unsigned int smp_cpus = ms->smp.cpus;
uint32_t nb_redist_regions = 0;
+ assert(num_cpus >= smp_cpus);
+
gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
vms->gic = qdev_create(NULL, gictype);
qdev_prop_set_uint32(vms->gic, "revision", type);
- qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(vms->gic, "num-cpu", num_cpus);
/* Note that the num-irq property counts both internal and external
* interrupts; there are always 32 of the former (mandated by GIC spec).
*/
@@ -780,7 +785,7 @@ static void create_gic(VirtMachineState *vms)
if (type == 3) {
uint32_t redist0_capacity =
vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE;
- uint32_t redist0_count = MIN(smp_cpus, redist0_capacity);
+ uint32_t redist0_count = MIN(num_cpus, redist0_capacity);
nb_redist_regions = virt_gicv3_redist_region_count(vms);
@@ -793,7 +798,7 @@ static void create_gic(VirtMachineState *vms)
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
qdev_prop_set_uint32(vms->gic, "redist-region-count[1]",
- MIN(smp_cpus - redist0_count, redist1_capacity));
+ MIN(num_cpus - redist0_count, redist1_capacity));
}
} else {
if (!kvm_irqchip_in_kernel()) {
@@ -820,7 +825,11 @@ static void create_gic(VirtMachineState *vms)
/* Wire the outputs from each CPU's generic timer and the GICv3
* maintenance interrupt signal to the appropriate GIC PPI inputs,
- * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
+ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's
+ * inputs.
+ *
+ * The irqs of remaining CPUs (if we has) will be connected during
+ * hotplugging.
*/
for (i = 0; i < smp_cpus; i++) {
connect_gic_cpu_irqs(vms, i);
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index cacef26546..a60185113f 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -20,6 +20,7 @@
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "hw/intc/arm_gicv3.h"
+#include "qom/cpu.h"
#include "gicv3_internal.h"
static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
@@ -206,7 +207,9 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
assert(len > 0);
for (i = 0; i < s->num_cpu; i++) {
- s->cpu[i].seenbetter = false;
+ if (qemu_get_cpu(i)) {
+ s->cpu[i].seenbetter = false;
+ }
}
/* Find the highest priority pending interrupt in this range. */
@@ -248,16 +251,18 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
* now be the new best one).
*/
for (i = 0; i < s->num_cpu; i++) {
- GICv3CPUState *cs = &s->cpu[i];
+ if (qemu_get_cpu(i)) {
+ GICv3CPUState *cs = &s->cpu[i];
- if (cs->seenbetter) {
- cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
- }
+ if (cs->seenbetter) {
+ cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
+ }
- if (!cs->seenbetter && cs->hppi.prio != 0xff &&
- cs->hppi.irq >= start && cs->hppi.irq < start + len) {
- gicv3_full_update_noirqset(s);
- break;
+ if (!cs->seenbetter && cs->hppi.prio != 0xff &&
+ cs->hppi.irq >= start && cs->hppi.irq < start + len) {
+ gicv3_full_update_noirqset(s);
+ break;
+ }
}
}
}
@@ -268,7 +273,9 @@ void gicv3_update(GICv3State *s, int start, int len)
gicv3_update_noirqset(s, start, len);
for (i = 0; i < s->num_cpu; i++) {
- gicv3_cpuif_update(&s->cpu[i]);
+ if (qemu_get_cpu(i)) {
+ gicv3_cpuif_update(&s->cpu[i]);
+ }
}
}
@@ -280,7 +287,9 @@ void gicv3_full_update_noirqset(GICv3State *s)
int i;
for (i = 0; i < s->num_cpu; i++) {
- s->cpu[i].hppi.prio = 0xff;
+ if (qemu_get_cpu(i)) {
+ s->cpu[i].hppi.prio = 0xff;
+ }
}
/* Note that we can guarantee that these functions will not
@@ -291,7 +300,9 @@ void gicv3_full_update_noirqset(GICv3State *s)
gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL);
for (i = 0; i < s->num_cpu; i++) {
- gicv3_redist_update_noirqset(&s->cpu[i]);
+ if (qemu_get_cpu(i)) {
+ gicv3_redist_update_noirqset(&s->cpu[i]);
+ }
}
}
@@ -304,7 +315,9 @@ void gicv3_full_update(GICv3State *s)
gicv3_full_update_noirqset(s);
for (i = 0; i < s->num_cpu; i++) {
- gicv3_cpuif_update(&s->cpu[i]);
+ if (qemu_get_cpu(i)) {
+ gicv3_cpuif_update(&s->cpu[i]);
+ }
}
}
@@ -401,7 +414,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
}
for (i = 0; i < s->num_cpu; i++) {
- gicv3_cpu_realize(s, i);
+ if (qemu_get_cpu(i)) {
+ gicv3_cpu_realize(s, i);
+ }
}
}
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 8740a52c9f..913bf068be 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -24,10 +24,12 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
#include "qom/cpu.h"
#include "hw/intc/arm_gicv3_common.h"
#include "gicv3_internal.h"
#include "hw/arm/linux-boot-if.h"
+#include "hw/boards.h"
#include "sysemu/kvm.h"
@@ -363,10 +365,15 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->num_cpu; i++) {
CPUState *cpu = qemu_get_cpu(i);
+ MachineState *ms = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus = NULL;
uint64_t cpu_affid;
int last;
- arm_gicv3_common_cpu_realize(s, i);
+ if (cpu) {
+ arm_gicv3_common_cpu_realize(s, i);
+ }
/* Pre-construct the GICR_TYPER:
* For our implementation:
@@ -380,7 +387,19 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
* VLPIS == 0 (virtual LPIs not supported)
* PLPIS == 0 (physical LPIs not supported)
*/
- cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL);
+ if (cpu) {
+ cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL);
+ } else {
+ if (!mc->possible_cpu_arch_ids) {
+ error_report("MachineClass must implement possible_cpu_arch_ids "
+ "hook to support pre-sizing GICv3");
+ exit(1);
+ }
+
+ possible_cpus = mc->possible_cpu_arch_ids(ms);
+ cpu_affid = possible_cpus->cpus[i].arch_id;
+ }
+
last = (i == s->num_cpu - 1);
/* The CPU mp-affinity property is in MPIDR register format; squash
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 56aa5efede..a20aa693ea 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -1648,6 +1648,10 @@ static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs,
aff, targetlist);
for (i = 0; i < s->num_cpu; i++) {
+ if (!qemu_get_cpu(i)) {
+ continue;
+ }
+
GICv3CPUState *ocs = &s->cpu[i];
if (irm) {
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index f8d7be5479..8eea7c9dd9 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -341,6 +341,10 @@ static void kvm_arm_gicv3_put(GICv3State *s)
for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
GICv3CPUState *c = &s->cpu[ncpu];
+ if (!qemu_get_cpu(ncpu)) {
+ continue;
+ }
+
reg64 = c->gicr_propbaser;
regl = (uint32_t)reg64;
kvm_gicr_access(s, GICR_PROPBASER, ncpu, &regl, true);
@@ -366,6 +370,10 @@ static void kvm_arm_gicv3_put(GICv3State *s)
for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
GICv3CPUState *c = &s->cpu[ncpu];
+ if (!qemu_get_cpu(ncpu)) {
+ continue;
+ }
+
reg = c->gicr_ctlr;
kvm_gicr_access(s, GICR_CTLR, ncpu, &reg, true);
@@ -462,6 +470,10 @@ static void kvm_arm_gicv3_put(GICv3State *s)
GICv3CPUState *c = &s->cpu[ncpu];
int num_pri_bits;
+ if (!qemu_get_cpu(ncpu)) {
+ 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);
@@ -525,6 +537,10 @@ static void kvm_arm_gicv3_get(GICv3State *s)
/* Redistributor state (one per CPU) */
for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ if (!qemu_get_cpu(ncpu)) {
+ continue;
+ }
+
GICv3CPUState *c = &s->cpu[ncpu];
kvm_gicr_access(s, GICR_CTLR, ncpu, &reg, false);
@@ -560,6 +576,10 @@ static void kvm_arm_gicv3_get(GICv3State *s)
if (redist_typer & GICR_TYPER_PLPIS) {
for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ if (!qemu_get_cpu(ncpu)) {
+ continue;
+ }
+
GICv3CPUState *c = &s->cpu[ncpu];
kvm_gicr_access(s, GICR_PROPBASER, ncpu, &regl, false);
@@ -613,6 +633,10 @@ static void kvm_arm_gicv3_get(GICv3State *s)
*/
for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ if (!qemu_get_cpu(ncpu)) {
+ continue;
+ }
+
GICv3CPUState *c = &s->cpu[ncpu];
int num_pri_bits;
@@ -806,7 +830,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
}
for (i = 0; i < s->num_cpu; i++) {
- kvm_arm_gicv3_cpu_realize(s, i);
+ if (qemu_get_cpu(i)) {
+ kvm_arm_gicv3_cpu_realize(s, i);
+ }
}
/* 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 6880ebe07c..beef4c8002 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -168,8 +168,9 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE;
assert(vms->gic_version == 3);
+ GICv3State *s = ARM_GICV3_COMMON(vms->gic);
- return vms->smp_cpus > redist0_capacity ? 2 : 1;
+ return s->num_cpu > redist0_capacity ? 2 : 1;
}
#endif /* QEMU_ARM_VIRT_H */
--
2.19.1

View File

@ -0,0 +1,50 @@
From a7391f391336024986a5997e3beae8882c983ed0 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 12:55:17 +0800
Subject: [PATCH] intc/gicv3_common: Factor out arm_gicv3_common_cpu_realize
The CPU object of hotplugged CPU will be defer-created (during
hotplug session), so we must factor out realization code to let
it can be applied to individual CPU.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/intc/arm_gicv3_common.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 5edabb928f..798f295d7c 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -303,6 +303,16 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
}
}
+static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu)
+{
+ CPUState *cpu = qemu_get_cpu(ncpu);
+
+ s->cpu[ncpu].cpu = cpu;
+ s->cpu[ncpu].gic = s;
+ /* Store GICv3CPUState in CPUARMState gicv3state pointer */
+ gicv3_set_gicv3state(cpu, &s->cpu[ncpu]);
+}
+
static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
{
GICv3State *s = ARM_GICV3_COMMON(dev);
@@ -350,10 +360,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
uint64_t cpu_affid;
int last;
- s->cpu[i].cpu = cpu;
- s->cpu[i].gic = s;
- /* Store GICv3CPUState in CPUARMState gicv3state pointer */
- gicv3_set_gicv3state(cpu, &s->cpu[i]);
+ arm_gicv3_common_cpu_realize(s, i);
/* Pre-construct the GICR_TYPER:
* For our implementation:
--
2.19.1

View File

@ -0,0 +1,197 @@
From de97ff4a01008ad98f7d69adc4b84843fff3ce19 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 10:59:55 +0800
Subject: [PATCH] intc/gicv3_cpuif: Factor out gicv3_init_one_cpuif
The CPU object of hotplugged CPU will be defer-created (during
hotplug session), so we must factor out some code to let it can
be applied to individual CPU.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/intc/arm_gicv3.c | 5 +-
hw/intc/arm_gicv3_cpuif.c | 122 ++++++++++++++++++--------------------
hw/intc/gicv3_internal.h | 2 +-
3 files changed, 64 insertions(+), 65 deletions(-)
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 66eaa97198..2fe79f794d 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -367,6 +367,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
GICv3State *s = ARM_GICV3(dev);
ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s);
Error *local_err = NULL;
+ int i;
agc->parent_realize(dev, &local_err);
if (local_err) {
@@ -386,7 +387,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
return;
}
- gicv3_init_cpuif(s);
+ for (i = 0; i < s->num_cpu; i++) {
+ gicv3_init_one_cpuif(s, i);
+ }
}
static void arm_gicv3_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 3b212d91c8..56aa5efede 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -2597,78 +2597,74 @@ static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
gicv3_cpuif_update(cs);
}
-void gicv3_init_cpuif(GICv3State *s)
+void gicv3_init_one_cpuif(GICv3State *s, int ncpu)
{
/* Called from the GICv3 realize function; register our system
* registers with the CPU
*/
- int i;
-
- for (i = 0; i < s->num_cpu; i++) {
- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
- GICv3CPUState *cs = &s->cpu[i];
-
- /* Note that we can't just use the GICv3CPUState as an opaque pointer
- * in define_arm_cp_regs_with_opaque(), because when we're called back
- * it might be with code translated by CPU 0 but run by CPU 1, in
- * which case we'd get the wrong value.
- * So instead we define the regs with no ri->opaque info, and
- * get back to the GICv3CPUState from the CPUARMState.
- */
- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
- if (arm_feature(&cpu->env, ARM_FEATURE_EL2)
- && cpu->gic_num_lrs) {
- int j;
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(ncpu));
+ GICv3CPUState *cs = &s->cpu[ncpu];
+
+ /* Note that we can't just use the GICv3CPUState as an opaque pointer
+ * in define_arm_cp_regs_with_opaque(), because when we're called back
+ * it might be with code translated by CPU 0 but run by CPU 1, in
+ * which case we'd get the wrong value.
+ * So instead we define the regs with no ri->opaque info, and
+ * get back to the GICv3CPUState from the CPUARMState.
+ */
+ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+ if (arm_feature(&cpu->env, ARM_FEATURE_EL2)
+ && cpu->gic_num_lrs) {
+ int j;
- cs->maintenance_irq = cpu->gicv3_maintenance_interrupt;
+ cs->maintenance_irq = cpu->gicv3_maintenance_interrupt;
- cs->num_list_regs = cpu->gic_num_lrs;
- cs->vpribits = cpu->gic_vpribits;
- cs->vprebits = cpu->gic_vprebits;
+ cs->num_list_regs = cpu->gic_num_lrs;
+ cs->vpribits = cpu->gic_vpribits;
+ cs->vprebits = cpu->gic_vprebits;
- /* Check against architectural constraints: getting these
- * wrong would be a bug in the CPU code defining these,
- * and the implementation relies on them holding.
- */
- g_assert(cs->vprebits <= cs->vpribits);
- g_assert(cs->vprebits >= 5 && cs->vprebits <= 7);
- g_assert(cs->vpribits >= 5 && cs->vpribits <= 8);
+ /* Check against architectural constraints: getting these
+ * wrong would be a bug in the CPU code defining these,
+ * and the implementation relies on them holding.
+ */
+ g_assert(cs->vprebits <= cs->vpribits);
+ g_assert(cs->vprebits >= 5 && cs->vprebits <= 7);
+ g_assert(cs->vpribits >= 5 && cs->vpribits <= 8);
- define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo);
+ define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo);
- for (j = 0; j < cs->num_list_regs; j++) {
- /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs
- * are split into two cp15 regs, LR (the low part, with the
- * same encoding as the AArch64 LR) and LRC (the high part).
- */
- ARMCPRegInfo lr_regset[] = {
- { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 4, .crn = 12,
- .crm = 12 + (j >> 3), .opc2 = j & 7,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL2_RW,
- .readfn = ich_lr_read,
- .writefn = ich_lr_write,
- },
- { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32,
- .cp = 15, .opc1 = 4, .crn = 12,
- .crm = 14 + (j >> 3), .opc2 = j & 7,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL2_RW,
- .readfn = ich_lr_read,
- .writefn = ich_lr_write,
- },
- REGINFO_SENTINEL
- };
- define_arm_cp_regs(cpu, lr_regset);
- }
- if (cs->vprebits >= 6) {
- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo);
- }
- if (cs->vprebits == 7) {
- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo);
- }
+ for (j = 0; j < cs->num_list_regs; j++) {
+ /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs
+ * are split into two cp15 regs, LR (the low part, with the
+ * same encoding as the AArch64 LR) and LRC (the high part).
+ */
+ ARMCPRegInfo lr_regset[] = {
+ { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 12,
+ .crm = 12 + (j >> 3), .opc2 = j & 7,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL2_RW,
+ .readfn = ich_lr_read,
+ .writefn = ich_lr_write,
+ },
+ { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 4, .crn = 12,
+ .crm = 14 + (j >> 3), .opc2 = j & 7,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL2_RW,
+ .readfn = ich_lr_read,
+ .writefn = ich_lr_write,
+ },
+ REGINFO_SENTINEL
+ };
+ define_arm_cp_regs(cpu, lr_regset);
+ }
+ if (cs->vprebits >= 6) {
+ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo);
+ }
+ if (cs->vprebits == 7) {
+ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo);
}
- arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
}
+ arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 05303a55c8..cfbfe8a549 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -297,7 +297,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
-void gicv3_init_cpuif(GICv3State *s);
+void gicv3_init_one_cpuif(GICv3State *s, int ncpu);
/**
* gicv3_cpuif_update:
--
2.19.1

View File

@ -0,0 +1,45 @@
From f45964c7e0df4ef17457a9ea92bfd255064139e1 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Fri, 10 Apr 2020 12:49:12 +0800
Subject: [PATCH] intc/kvm_gicv3: Factor out kvm_arm_gicv3_cpu_realize
The CPU object of hotplugged CPU will be defer-created (during
hotplug session), so we must factor out realization code to let
it can be applied to individual CPU.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hw/intc/arm_gicv3_kvm.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index b1e74147ba..b2936938cb 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -761,6 +761,12 @@ static void vm_change_state_handler(void *opaque, int running,
}
}
+static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu)
+{
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(ncpu));
+
+ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+}
static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
{
@@ -791,9 +797,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
}
for (i = 0; i < s->num_cpu; i++) {
- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
-
- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+ kvm_arm_gicv3_cpu_realize(s, i);
}
/* Try to create the device via the device control API */
--
2.19.1

View File

@ -119,6 +119,34 @@ Patch0106: tests-acpi-add-empty-files.patch
Patch0107: tests-allow-empty-expected-files.patch
Patch0108: tests-Add-bios-tests-to-arm-virt.patch
Patch0109: tests-document-how-to-update-acpi-tables.patch
Patch0110: hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch
Patch0111: bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch
Patch0112: Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch
Patch0113: acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch
Patch0114: acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch
Patch0115: arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch
Patch0116: acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch
Patch0117: acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch
Patch0118: arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch
Patch0119: arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch
Patch0120: arm-virt-Add-CPU-hotplug-framework.patch
Patch0121: arm-virt-Add-CPU-topology-support.patch
Patch0122: test-numa-Adjust-aarch64-numa-test.patch
Patch0123: hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch
Patch0124: hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch
Patch0125: arm-virt-gic-Construct-irqs-connection-from-create_g.patch
Patch0126: intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch
Patch0127: intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch
Patch0128: intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch
Patch0129: hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch
Patch0130: accel-kvm-Add-pre-park-vCPU-support.patch
Patch0131: intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch
Patch0132: acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch
Patch0133: arm-virt-Add-cpu_hotplug_enabled-field.patch
Patch0134: arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch
Patch0135: arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch
Patch0136: arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch
Patch0137: arm-virt-Start-up-CPU-hot-plug.patch
BuildRequires: flex
@ -465,6 +493,9 @@ getent passwd qemu >/dev/null || \
%endif
%changelog
* Fri Apr 24 2020 Huawei Technologies Co., Ltd. <zhukeqian1@huawei.com>
- arm/virt: Add CPU hotplug support
* Wed Apr 22 2020 Huawei Technologies Co., Ltd. <zhukeqian1@huawei.com>
- backport patch to enable arm/virt memory hotplug

View File

@ -0,0 +1,58 @@
From 3ef97cc418d1061fc0ec70098270ce2d76005cc1 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
Date: Thu, 23 Apr 2020 20:54:18 +0800
Subject: [PATCH] test/numa: Adjust aarch64 numa test
We have supported topology for arm/virt in previous patch, which
changes the meaning of "thread-id", so we must modify test case.
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
---
tests/numa-test.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/tests/numa-test.c b/tests/numa-test.c
index 8de8581231..71cdd7b4f7 100644
--- a/tests/numa-test.c
+++ b/tests/numa-test.c
@@ -231,17 +231,17 @@ static void aarch64_numa_cpu(const void *data)
QObject *e;
QTestState *qts;
- cli = make_cli(data, "-smp 2 "
+ cli = make_cli(data, "-smp 2,cores=2 "
"-numa node,nodeid=0 -numa node,nodeid=1 "
- "-numa cpu,node-id=1,thread-id=0 "
- "-numa cpu,node-id=0,thread-id=1");
+ "-numa cpu,node-id=1,core-id=0 "
+ "-numa cpu,node-id=0,core-id=1");
qts = qtest_init(cli);
cpus = get_cpus(qts, &resp);
g_assert(cpus);
while ((e = qlist_pop(cpus))) {
QDict *cpu, *props;
- int64_t thread, node;
+ int64_t core, node;
cpu = qobject_to(QDict, e);
g_assert(qdict_haskey(cpu, "props"));
@@ -249,12 +249,12 @@ static void aarch64_numa_cpu(const void *data)
g_assert(qdict_haskey(props, "node-id"));
node = qdict_get_int(props, "node-id");
- g_assert(qdict_haskey(props, "thread-id"));
- thread = qdict_get_int(props, "thread-id");
+ g_assert(qdict_haskey(props, "core-id"));
+ core = qdict_get_int(props, "core-id");
- if (thread == 0) {
+ if (core == 0) {
g_assert_cmpint(node, ==, 1);
- } else if (thread == 1) {
+ } else if (core == 1) {
g_assert_cmpint(node, ==, 0);
} else {
g_assert(false);
--
2.19.1