qemu/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch
Keqian Zhu 1c823f0431 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>
2020-06-01 09:13:39 +00:00

358 lines
12 KiB
Diff

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