aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/intc/arm_gicv3.c6
-rw-r--r--hw/intc/arm_gicv3_common.c15
-rw-r--r--hw/intc/arm_gicv3_kvm.c4
-rw-r--r--hw/intc/arm_gicv3_redist.c40
-rw-r--r--include/hw/intc/arm_gicv3_common.h12
5 files changed, 46 insertions, 31 deletions
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index bcf54a5f0a..c6282984b1 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -387,12 +387,6 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
return;
}
- if (s->nb_redist_regions != 1) {
- error_setg(errp, "VGICv3 redist region number(%d) not equal to 1",
- s->nb_redist_regions);
- return;
- }
-
gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops);
gicv3_init_cpuif(s);
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 8de9205b38..9884d2e39b 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -254,6 +254,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
{
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
int i;
+ int cpuidx;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
@@ -282,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);
}
}
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index ab58c73306..5ec5ff9ef6 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -825,7 +825,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd, 0);
if (!multiple_redist_region_allowed) {
- kvm_arm_register_device(&s->iomem_redist[0], -1,
+ kvm_arm_register_device(&s->redist_regions[0].iomem, -1,
KVM_DEV_ARM_VGIC_GRP_ADDR,
KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd, 0);
} else {
@@ -838,7 +838,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
uint64_t addr_ormask =
i | ((uint64_t)s->redist_region_count[i] << 52);
- kvm_arm_register_device(&s->iomem_redist[i], -1,
+ kvm_arm_register_device(&s->redist_regions[i].iomem, -1,
KVM_DEV_ARM_VGIC_GRP_ADDR,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION,
s->dev_fd, addr_ormask);
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 7072bfcbb1..424e7e28a8 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -425,22 +425,24 @@ static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset,
MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
unsigned size, MemTxAttrs attrs)
{
- GICv3State *s = opaque;
+ GICv3RedistRegion *region = opaque;
+ GICv3State *s = region->gic;
GICv3CPUState *cs;
MemTxResult r;
int cpuidx;
assert((offset & (size - 1)) == 0);
- /* This region covers all the redistributor pages; there are
- * (for GICv3) two 64K pages per CPU. At the moment they are
- * all contiguous (ie in this one region), though we might later
- * want to allow splitting of redistributor pages into several
- * blocks so we can support more CPUs.
+ /*
+ * There are (for GICv3) two 64K redistributor pages per CPU.
+ * In some cases the redistributor pages for all CPUs are not
+ * contiguous (eg on the virt board they are split into two
+ * parts if there are too many CPUs to all fit in the same place
+ * in the memory map); if so then the GIC has multiple MemoryRegions
+ * for the redistributors.
*/
- cpuidx = offset / 0x20000;
- offset %= 0x20000;
- assert(cpuidx < s->num_cpu);
+ cpuidx = region->cpuidx + offset / GICV3_REDIST_SIZE;
+ offset %= GICV3_REDIST_SIZE;
cs = &s->cpu[cpuidx];
@@ -482,22 +484,24 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size, MemTxAttrs attrs)
{
- GICv3State *s = opaque;
+ GICv3RedistRegion *region = opaque;
+ GICv3State *s = region->gic;
GICv3CPUState *cs;
MemTxResult r;
int cpuidx;
assert((offset & (size - 1)) == 0);
- /* This region covers all the redistributor pages; there are
- * (for GICv3) two 64K pages per CPU. At the moment they are
- * all contiguous (ie in this one region), though we might later
- * want to allow splitting of redistributor pages into several
- * blocks so we can support more CPUs.
+ /*
+ * There are (for GICv3) two 64K redistributor pages per CPU.
+ * In some cases the redistributor pages for all CPUs are not
+ * contiguous (eg on the virt board they are split into two
+ * parts if there are too many CPUs to all fit in the same place
+ * in the memory map); if so then the GIC has multiple MemoryRegions
+ * for the redistributors.
*/
- cpuidx = offset / 0x20000;
- offset %= 0x20000;
- assert(cpuidx < s->num_cpu);
+ cpuidx = region->cpuidx + offset / GICV3_REDIST_SIZE;
+ offset %= GICV3_REDIST_SIZE;
cs = &s->cpu[cpuidx];
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index cb2b0d0ad4..fc38e4b7dc 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -215,13 +215,23 @@ struct GICv3CPUState {
bool seenbetter;
};
+/*
+ * The redistributor pages might be split into more than one region
+ * on some machine types if there are many CPUs.
+ */
+typedef struct GICv3RedistRegion {
+ GICv3State *gic;
+ MemoryRegion iomem;
+ uint32_t cpuidx; /* index of first CPU this region covers */
+} GICv3RedistRegion;
+
struct GICv3State {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem_dist; /* Distributor */
- MemoryRegion *iomem_redist; /* Redistributor Regions */
+ GICv3RedistRegion *redist_regions; /* Redistributor Regions */
uint32_t *redist_region_count; /* redistributor count within each region */
uint32_t nb_redist_regions; /* number of redist regions */