The IRS_PE_CR0, IRS_PE_SELR, IRS_PE_STATUSR registers allow software to set and query per-CPU config. Software writes the AFFID of a CPU to IRS_PE_SELR, and can then read and write the 1ofN config for that CPU to IRS_PE_CR0, and read the CPU's online status from IRS_PE_STATUSR.
For QEMU, we do not implement 1-of-N interrupt routing, so IRS_PE_CR0 can be RAZ/WI. Our CPUs are always online and selecting a new one via SELR is instantaneous, so IRS_PE_STATUSR will return either ONLINE | V | IDLE if a valid AFFID was written to SELR, or just IDLE if an invalid AFFID was written. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Message-id: [email protected] --- hw/intc/arm_gicv5.c | 39 ++++++++++++++++++++++++++++++ hw/intc/arm_gicv5_common.c | 1 + include/hw/intc/arm_gicv5_common.h | 1 + 3 files changed, 41 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 7b0d9e16c4..a95a9dc16b 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -968,6 +968,21 @@ static void spi_sample(GICv5SPIState *spi) } } +static bool irs_pe_selr_valid(GICv5Common *cs, GICv5Domain domain) +{ + /* + * Return true if IRS_PE_SELR has a valid AFFID in it. We don't + * expect the guest to do this except perhaps once at startup, so + * do a simple linear scan through the cpu_iaffids array. + */ + for (int i = 0; i < cs->num_cpu_iaffids; i++) { + if (cs->irs_pe_selr[domain] == cs->cpu_iaffids[i]) { + return true; + } + } + return false; +} + static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, uint64_t *data, MemTxAttrs attrs) { @@ -1091,6 +1106,24 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, /* Sync is a no-op for QEMU: we are always IDLE */ *data = R_IRS_SYNC_STATUSR_IDLE_MASK; return true; + case A_IRS_PE_SELR: + *data = cs->irs_pe_selr[domain]; + return true; + case A_IRS_PE_CR0: + /* We don't implement 1ofN, so this is RAZ/WI for us */ + *data = 0; + return true; + case A_IRS_PE_STATUSR: + /* + * Our CPUs are always online, so we're really just reporting + * whether the guest wrote a valid AFFID to IRS_PE_SELR + */ + v = R_IRS_PE_STATUSR_IDLE_MASK; + if (irs_pe_selr_valid(cs, domain)) { + v |= R_IRS_PE_STATUSR_V_MASK | R_IRS_PE_STATUSR_ONLINE_MASK; + } + *data = v; + return true; } return false; @@ -1179,6 +1212,12 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset, case A_IRS_SYNCR: /* Sync is a no-op for QEMU: ignore write */ return true; + case A_IRS_PE_SELR: + cs->irs_pe_selr[domain] = data; + return true; + case A_IRS_PE_CR0: + /* We don't implement 1ofN, so this is RAZ/WI for us */ + return true; } return false; diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c index 69622e41c0..180fe338a4 100644 --- a/hw/intc/arm_gicv5_common.c +++ b/hw/intc/arm_gicv5_common.c @@ -66,6 +66,7 @@ static void gicv5_common_reset_hold(Object *obj, ResetType type) memset(cs->irs_ist_cfgr, 0, sizeof(cs->irs_ist_cfgr)); memset(cs->irs_cr0, 0, sizeof(cs->irs_cr0)); memset(cs->irs_cr1, 0, sizeof(cs->irs_cr1)); + memset(cs->irs_pe_selr, 0, sizeof(cs->irs_pe_selr)); if (cs->spi) { GICv5Domain mp_domain; diff --git a/include/hw/intc/arm_gicv5_common.h b/include/hw/intc/arm_gicv5_common.h index f259d2d642..59ac1c3880 100644 --- a/include/hw/intc/arm_gicv5_common.h +++ b/include/hw/intc/arm_gicv5_common.h @@ -88,6 +88,7 @@ struct GICv5Common { uint32_t irs_spi_selr[NUM_GICV5_DOMAINS]; uint32_t irs_cr0[NUM_GICV5_DOMAINS]; uint32_t irs_cr1[NUM_GICV5_DOMAINS]; + uint32_t irs_pe_selr[NUM_GICV5_DOMAINS]; /* * Pointer to an array of state information for the SPIs. Array -- 2.43.0
