The qdev link property array gives the IRS a pointer to each CPU that
is connected to it, but the CPU also needs a pointer to the IRS so
that it can issue commands. Set this up in a similar way to how we
do it for the GICv3: have the GIC's realize function call
gicv5_set_gicv5state() to set a pointer in the CPUARMState.
The CPU will only allow this link to be made if it actually
implements the GICv5 CPU interface; it will be the responsibility of
the board code to configure the CPU to have a GICv5 cpuif if it wants
to connect a GICv5 to it.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/intc/arm_gicv5_common.c | 9 +++++++++
include/hw/intc/arm_gicv5_stream.h | 32 ++++++++++++++++++++++++++++++
target/arm/cpu.c | 16 +++++++++++++++
target/arm/cpu.h | 2 ++
4 files changed, 59 insertions(+)
create mode 100644 include/hw/intc/arm_gicv5_stream.h
diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c
index 7f15e3c7c8..54d75db014 100644
--- a/hw/intc/arm_gicv5_common.c
+++ b/hw/intc/arm_gicv5_common.c
@@ -8,6 +8,7 @@
#include "qemu/osdep.h"
#include "hw/intc/arm_gicv5_common.h"
+#include "hw/intc/arm_gicv5_stream.h"
#include "hw/core/qdev-properties.h"
#include "qapi/error.h"
#include "trace.h"
@@ -129,6 +130,14 @@ static void gicv5_common_realize(DeviceState *dev, Error **errp)
return;
}
+ for (int i = 0; i < cs->num_cpus; i++) {
+ if (!gicv5_set_gicv5state(cs->cpus[i], cs)) {
+ error_setg(errp,
+ "CPU %d does not implement GICv5 CPU interface", i);
+ return;
+ }
+ }
+
address_space_init(&cs->dma_as, cs->dma, "gicv5-sysmem");
trace_gicv5_common_realize(cs->irsid, cs->num_cpus,
diff --git a/include/hw/intc/arm_gicv5_stream.h b/include/hw/intc/arm_gicv5_stream.h
new file mode 100644
index 0000000000..7257ddde90
--- /dev/null
+++ b/include/hw/intc/arm_gicv5_stream.h
@@ -0,0 +1,32 @@
+/*
+ * Interface between GICv5 CPU interface and GICv5 IRS
+ * Loosely modelled on the GICv5 Stream Protocol interface documented
+ * in the GICv5 specification.
+ *
+ * Copyright (c) 2025 Linaro Limited
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_INTC_ARM_GICV5_STREAM_H
+#define HW_INTC_ARM_GICV5_STREAM_H
+
+#include "target/arm/cpu-qom.h"
+
+typedef struct GICv5Common GICv5Common;
+
+/**
+ * gicv5_set_gicv5state
+ * @cpu: CPU object to tell about its IRS
+ * @cs: the GIC IRS it is connected to
+ *
+ * Set the CPU object's GICv5 pointer to point to this GIC IRS. The
+ * IRS must call this when it is realized, for each CPU it is
+ * connected to.
+ *
+ * Returns true on success, false if the CPU doesn't implement the
+ * GICv5 CPU interface.
+ */
+bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs);
+
+#endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index ccc47c8a9a..4044bce5b6 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -41,6 +41,7 @@
#include "hw/core/boards.h"
#ifdef CONFIG_TCG
#include "hw/intc/armv7m_nvic.h"
+#include "hw/intc/arm_gicv5_stream.h"
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */
#include "system/tcg.h"
@@ -1085,6 +1086,21 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
}
}
+#ifndef CONFIG_USER_ONLY
+bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs)
+{
+ /*
+ * Set this CPU's gicv5state pointer to point to the GIC that we are
+ * connected to.
+ */
+ if (!cpu_isar_feature(aa64_gcie, cpu)) {
+ return false;
+ }
+ cpu->env.gicv5state = cs;
+ return true;
+}
+#endif
+
uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz)
{
uint32_t Aff1 = idx / clustersz;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 657ff4ab20..16de0ebfa8 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -812,6 +812,8 @@ typedef struct CPUArchState {
const struct arm_boot_info *boot_info;
/* Store GICv3CPUState to access from this struct */
void *gicv3state;
+ /* Similarly, for a GICv5Common */
+ void *gicv5state;
#else /* CONFIG_USER_ONLY */
/* For usermode syscall translation. */
bool eabi;
--
2.43.0