The CPU system register ICC_IAFFIDR_EL1 is a read-only register that
tells the guest what the affinity ID of that CPU is.
Implement this register. In real hardware using the stream protocol,
the IRS tells the CPU its IAFFID using a DownstreamControl command as
part of the handshake process when the IRS-CPU link is brought
online. Our analogue of this is to pass the IAFFID as an extra
argument to gicv5_set_gicv5state(). (We could have the CPU call into
the GIC every time to ask for the value, but this would mean we had
to search the cpus[] array for the right CPU to return its IAFFID.)
Note that we don't put the IAFFID into the gicv5_cpuif sub-struct,
because that part of the CPU struct is zeroed on reset, and we must
keep the IAFFID across reset (we only set it up when the GIC device
is created).
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/intc/arm_gicv5_common.c | 5 +++--
include/hw/intc/arm_gicv5_stream.h | 3 ++-
target/arm/cpu.c | 5 +++--
target/arm/cpu.h | 2 ++
target/arm/tcg/gicv5-cpuif.c | 11 +++++++++++
5 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c
index 5510e6239a..0b5303f370 100644
--- a/hw/intc/arm_gicv5_common.c
+++ b/hw/intc/arm_gicv5_common.c
@@ -175,9 +175,10 @@ static void gicv5_common_realize(DeviceState *dev, Error **errp)
}
for (int i = 0; i < cs->num_cpus; i++) {
- if (!gicv5_set_gicv5state(cs->cpus[i], cs)) {
+ if (!gicv5_set_gicv5state(cs->cpus[i], cs, cs->cpu_iaffids[i])) {
error_setg(errp,
- "CPU %d does not implement GICv5 CPU interface", i);
+ "CPU %d (IAFFID 0x%x) does not implement GICv5 CPU interface",
+ i, cs->cpu_iaffids[i]);
return;
}
}
diff --git a/include/hw/intc/arm_gicv5_stream.h b/include/hw/intc/arm_gicv5_stream.h
index 670423fdad..136b6339ee 100644
--- a/include/hw/intc/arm_gicv5_stream.h
+++ b/include/hw/intc/arm_gicv5_stream.h
@@ -20,6 +20,7 @@ typedef struct GICv5Common GICv5Common;
* gicv5_set_gicv5state
* @cpu: CPU object to tell about its IRS
* @cs: the GIC IRS it is connected to
+ * @iaffid: the IAFFID of this CPU
*
* 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
@@ -28,7 +29,7 @@ typedef struct GICv5Common GICv5Common;
* Returns true on success, false if the CPU doesn't implement the
* GICv5 CPU interface.
*/
-bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs);
+bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs, uint32_t iaffid);
/*
* The architected Stream Protocol is asynchronous; commands can be
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 4044bce5b6..ceb303a55a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1087,16 +1087,17 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
}
#ifndef CONFIG_USER_ONLY
-bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs)
+bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs, uint32_t iaffid)
{
/*
* Set this CPU's gicv5state pointer to point to the GIC that we are
- * connected to.
+ * connected to, and record our IAFFID.
*/
if (!cpu_isar_feature(aa64_gcie, cpu)) {
return false;
}
cpu->env.gicv5state = cs;
+ cpu->env.gicv5_iaffid = iaffid;
return true;
}
#endif
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 1fdfd91ba4..a32c5f3ab1 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -819,6 +819,8 @@ typedef struct CPUArchState {
void *gicv3state;
/* Similarly, for a GICv5Common */
void *gicv5state;
+ /* For GICv5, this CPU's IAFFID */
+ uint64_t gicv5_iaffid;
#else /* CONFIG_USER_ONLY */
/* For usermode syscall translation. */
bool eabi;
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index 8cf09791c1..005e2fa8d2 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -226,6 +226,17 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, gicv5_cpuif.icc_icsr_el1),
.resetvalue = 0,
},
+ { .name = "ICC_IAFFIDR_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 5,
+ .access = PL1_R, .type = ARM_CP_NO_RAW,
+ /* ICC_IAFFIDR_EL1 holds the IAFFID only, in its low bits */
+ .fieldoffset = offsetof(CPUARMState, gicv5_iaffid),
+ /*
+ * The field is a constant value set in gicv5_set_gicv5state(),
+ * so don't allow it to be overwritten by reset.
+ */
+ .resetfn = arm_cp_reset_ignore,
+ },
};
void define_gicv5_cpuif_regs(ARMCPU *cpu)
--
2.43.0