aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-11-16 09:56:28 +0100
committerRichard Henderson <richard.henderson@linaro.org>2021-11-16 09:56:28 +0100
commit3e595538b8338ea7789d1d4003b0504258b6aa31 (patch)
treed1b967ca12d9740b783483850cfefab32c8de579 /hw
parent757b8dd4e970038538b2e027120ab4594bebdebc (diff)
parent1adf528ec3bdf62ea3b580b7ad562534a3676ff5 (diff)
downloadqemu-3e595538b8338ea7789d1d4003b0504258b6aa31.zip
qemu-3e595538b8338ea7789d1d4003b0504258b6aa31.tar.gz
qemu-3e595538b8338ea7789d1d4003b0504258b6aa31.tar.bz2
Merge tag 'pull-target-arm-20211115-1' of https://git.linaro.org/people/pmaydell/qemu-arm into staging
target-arm queue: * Support multiple redistributor regions for TCG GICv3 * Send RTC_CHANGE QMP event from pl031 # gpg: Signature made Mon 15 Nov 2021 07:53:40 PM CET # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] * tag 'pull-target-arm-20211115-1' of https://git.linaro.org/people/pmaydell/qemu-arm: hw/rtc/pl031: Send RTC_CHANGE QMP event hw/intc/arm_gicv3: Support multiple redistributor regions hw/intc/arm_gicv3: Set GICR_TYPER.Last correctly when nb_redist_regions > 1 hw/intc/arm_gicv3: Move checking of redist-region-count to arm_gicv3_common_realize Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/intc/arm_gicv3.c12
-rw-r--r--hw/intc/arm_gicv3_common.c56
-rw-r--r--hw/intc/arm_gicv3_kvm.c10
-rw-r--r--hw/intc/arm_gicv3_redist.c40
-rw-r--r--hw/rtc/meson.build2
-rw-r--r--hw/rtc/pl031.c10
6 files changed, 71 insertions, 59 deletions
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 3f24707..c628298 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -387,17 +387,7 @@ 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, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- 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 223db16..9884d2e 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)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 5c09f00..5ec5ff9 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -787,11 +787,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
return;
}
- gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
for (i = 0; i < s->num_cpu; i++) {
ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
@@ -829,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 {
@@ -842,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 7072bfc..424e7e2 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/hw/rtc/meson.build b/hw/rtc/meson.build
index 7cecdee..8fd8d8f 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -2,7 +2,7 @@
softmmu_ss.add(when: 'CONFIG_DS1338', if_true: files('ds1338.c'))
softmmu_ss.add(when: 'CONFIG_M41T80', if_true: files('m41t80.c'))
softmmu_ss.add(when: 'CONFIG_M48T59', if_true: files('m48t59.c'))
-softmmu_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
+specific_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
softmmu_ss.add(when: 'CONFIG_TWL92230', if_true: files('twl92230.c'))
softmmu_ss.add(when: ['CONFIG_ISA_BUS', 'CONFIG_M48T59'], if_true: files('m48t59-isa.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-rtc.c'))
diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c
index 2bbb206..e7ced90 100644
--- a/hw/rtc/pl031.c
+++ b/hw/rtc/pl031.c
@@ -24,6 +24,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
+#include "qapi/qapi-events-misc-target.h"
#define RTC_DR 0x00 /* Data read register */
#define RTC_MR 0x04 /* Match register */
@@ -136,10 +137,17 @@ static void pl031_write(void * opaque, hwaddr offset,
trace_pl031_write(offset, value);
switch (offset) {
- case RTC_LR:
+ case RTC_LR: {
+ struct tm tm;
+
s->tick_offset += value - pl031_get_count(s);
+
+ qemu_get_timedate(&tm, s->tick_offset);
+ qapi_event_send_rtc_change(qemu_timedate_diff(&tm));
+
pl031_set_alarm(s);
break;
+ }
case RTC_MR:
s->mr = value;
pl031_set_alarm(s);