The GIC CD* insns that update interrupt state also work for SPIs. Instead of ignoring the GICV5_SPI type in gicv5_set_priority() and friends, update the state in our SPI state array.
Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 59 ++++++++++++++++++++++++++++++ include/hw/intc/arm_gicv5_common.h | 40 ++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 3c6ef17573..4d99200122 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -478,6 +478,18 @@ void gicv5_set_priority(GICv5Common *cs, uint32_t id, "priority of a virtual interrupt\n"); return; } + if (type == GICV5_SPI) { + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain); + + if (!spi) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_priority: tried to set " + "priority of unreachable SPI %d\n", id); + return; + } + + spi->priority = priority; + return; + } if (type != GICV5_LPI) { qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_priority: tried to set " "priority of bad interrupt type %d\n", type); @@ -508,6 +520,18 @@ void gicv5_set_enabled(GICv5Common *cs, uint32_t id, "enable state of a virtual interrupt\n"); return; } + if (type == GICV5_SPI) { + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain); + + if (!spi) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_enabled: tried to set " + "enable state of unreachable SPI %d\n", id); + return; + } + + spi->enabled = true; + return; + } if (type != GICV5_LPI) { qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_enabled: tried to set " "enable state of bad interrupt type %d\n", type); @@ -538,6 +562,18 @@ void gicv5_set_pending(GICv5Common *cs, uint32_t id, "pending state of a virtual interrupt\n"); return; } + if (type == GICV5_SPI) { + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain); + + if (!spi) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set " + "pending state of unreachable SPI %d\n", id); + return; + } + + spi->pending = true; + return; + } if (type != GICV5_LPI) { qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set " "pending state of bad interrupt type %d\n", type); @@ -568,6 +604,17 @@ void gicv5_set_handling(GICv5Common *cs, uint32_t id, "handling mode of a virtual interrupt\n"); return; } + if (type == GICV5_SPI) { + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain); + + if (!spi) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set " + "priority of unreachable SPI %d\n", id); + } + + spi->hm = handling; + return; + } if (type != GICV5_LPI) { qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set " "handling mode of bad interrupt type %d\n", type); @@ -607,6 +654,18 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid, * IRM=1 the same as IRM=0. */ } + if (type == GICV5_SPI) { + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain); + + if (!spi) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set " + "target of unreachable SPI %d\n", id); + return; + } + + spi->iaffid = iaffid; + return; + } if (type != GICV5_LPI) { qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set " "target of bad interrupt type %d\n", type); diff --git a/include/hw/intc/arm_gicv5_common.h b/include/hw/intc/arm_gicv5_common.h index c29eab2951..1a1d360c68 100644 --- a/include/hw/intc/arm_gicv5_common.h +++ b/include/hw/intc/arm_gicv5_common.h @@ -191,4 +191,44 @@ static inline bool gicv5_domain_implemented(GICv5Common *cs, GICv5Domain domain) */ const char *gicv5_class_name(void); +/** + * gicv5_raw_spi_state + * @cs: GIC object + * @id: INTID of SPI to look up + * + * Return pointer to the GICv5SPIState for this SPI, or NULL if the + * interrupt ID is out of range. This does not do a check that the + * SPI is assigned to the right domain: generally you should call it + * via some other wrapper that performs an appropriate further check. + */ +static inline GICv5SPIState *gicv5_raw_spi_state(GICv5Common *cs, uint32_t id) +{ + if (id < cs->spi_base || id >= cs->spi_base + cs->spi_irs_range) { + return NULL; + } + + return cs->spi + (id - cs->spi_base); +} + +/** + * gicv5_spi_state: + * @cs: GIC object + * @id: INTID of SPI to look up + * @domain: domain to check + * + * Return pointer to the GICv5SPIState for this SPI, or NULL if the + * interrupt is unreachable (which can be because the INTID is out + * of range, or because the SPI is configured for a different domain). + */ +static inline GICv5SPIState *gicv5_spi_state(GICv5Common *cs, uint32_t id, + GICv5Domain domain) +{ + GICv5SPIState *spi = gicv5_raw_spi_state(cs, id); + + if (!spi || spi->domain != domain) { + return NULL; + } + return spi; +} + #endif -- 2.43.0
