summaryrefslogtreecommitdiffstats
path: root/hw/intc/arm_gicv3_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc/arm_gicv3_common.c')
-rw-r--r--hw/intc/arm_gicv3_common.c56
1 files changed, 35 insertions, 21 deletions
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 223db16fec..9884d2e39b 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -250,21 +250,11 @@ static const VMStateDescription vmstate_gicv3 = {
};
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
- const MemoryRegionOps *ops, Error **errp)
+ const MemoryRegionOps *ops)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
- int rdist_capacity = 0;
int i;
-
- for (i = 0; i < s->nb_redist_regions; i++) {
- rdist_capacity += s->redist_region_count[i];
- }
- if (rdist_capacity < s->num_cpu) {
- error_setg(errp, "Capacity of the redist regions(%d) "
- "is less than number of vcpus(%d)",
- rdist_capacity, s->num_cpu);
- return;
- }
+ int cpuidx;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
@@ -293,14 +283,20 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
"gicv3_dist", 0x10000);
sysbus_init_mmio(sbd, &s->iomem_dist);
- s->iomem_redist = g_new0(MemoryRegion, s->nb_redist_regions);
+ s->redist_regions = g_new0(GICv3RedistRegion, s->nb_redist_regions);
+ cpuidx = 0;
for (i = 0; i < s->nb_redist_regions; i++) {
char *name = g_strdup_printf("gicv3_redist_region[%d]", i);
+ GICv3RedistRegion *region = &s->redist_regions[i];
+
+ region->gic = s;
+ region->cpuidx = cpuidx;
+ cpuidx += s->redist_region_count[i];
- memory_region_init_io(&s->iomem_redist[i], OBJECT(s),
- ops ? &ops[1] : NULL, s, name,
+ memory_region_init_io(&region->iomem, OBJECT(s),
+ ops ? &ops[1] : NULL, region, name,
s->redist_region_count[i] * GICV3_REDIST_SIZE);
- sysbus_init_mmio(sbd, &s->iomem_redist[i]);
+ sysbus_init_mmio(sbd, &region->iomem);
g_free(name);
}
}
@@ -308,7 +304,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;
+ 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
@@ -350,12 +346,22 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
return;
}
+ rdist_capacity = 0;
+ for (i = 0; i < s->nb_redist_regions; i++) {
+ rdist_capacity += s->redist_region_count[i];
+ }
+ if (rdist_capacity < s->num_cpu) {
+ error_setg(errp, "Capacity of the redist regions(%d) "
+ "is less than number of vcpus(%d)",
+ rdist_capacity, s->num_cpu);
+ return;
+ }
+
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
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 +381,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 +389,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)