358 lines
12 KiB
Diff
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, ®l, 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, ®, 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, ®, 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, ®l, 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
|