aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-09-30 16:08:41 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-11-15 16:12:59 +0000
commit046164155abe7594ad1d8729dbe150e95badeaed (patch)
treea8ce4072f992439e3919bc16c2ca1f29b0a7a7df /hw
parent01b5ab8cc08ab0afb6574f46a4d966725a00a1de (diff)
downloadqemu-046164155abe7594ad1d8729dbe150e95badeaed.zip
qemu-046164155abe7594ad1d8729dbe150e95badeaed.tar.gz
qemu-046164155abe7594ad1d8729dbe150e95badeaed.tar.bz2
hw/intc/arm_gicv3: Set GICR_TYPER.Last correctly when nb_redist_regions > 1
The 'Last' bit in the GICR_TYPER GICv3 redistributor register is supposed to be set to 1 if this is the last redistributor in a series of contiguous redistributor pages. Currently we set Last only for the redistributor for CPU (num_cpu - 1). This only works if there is a single redistributor region; if there are multiple redistributor regions then we need to set the Last bit for the last redistributor in each region. This doesn't cause any problems currently because only the KVM GICv3 supports multiple redistributor regions, and it ignores the value in GICv3State::gicr_typer. But we need to fix this before we can enable support for multiple regions in the emulated GICv3. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/intc/arm_gicv3_common.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 8e47809..8de9205 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -297,7 +297,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
{
GICv3State *s = ARM_GICV3_COMMON(dev);
- int i, rdist_capacity;
+ int i, rdist_capacity, cpuidx;
/* revision property is actually reserved and currently used only in order
* to keep the interface compatible with GICv2 code, avoiding extra
@@ -355,7 +355,6 @@ 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;
s->cpu[i].cpu = cpu;
s->cpu[i].gic = s;
@@ -375,7 +374,6 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
* PLPIS == 0 (physical LPIs not supported)
*/
cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL);
- last = (i == s->num_cpu - 1);
/* The CPU mp-affinity property is in MPIDR register format; squash
* the affinity bytes into 32 bits as the GICR_TYPER has them.
@@ -384,13 +382,22 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
(cpu_affid & 0xFFFFFF);
s->cpu[i].gicr_typer = (cpu_affid << 32) |
(1 << 24) |
- (i << 8) |
- (last << 4);
+ (i << 8);
if (s->lpi_enable) {
s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
}
}
+
+ /*
+ * Now go through and set GICR_TYPER.Last for the final
+ * redistributor in each region.
+ */
+ cpuidx = 0;
+ for (i = 0; i < s->nb_redist_regions; i++) {
+ cpuidx += s->redist_region_count[i];
+ s->cpu[cpuidx - 1].gicr_typer |= GICR_TYPER_LAST;
+ }
}
static void arm_gicv3_finalize(Object *obj)