}
}
+static void spi_sample(GICv5SPIState *spi)
+{
+ /*
+ * Sample the state of the SPI input line; this generates
+ * SET_EDGE, SET_LEVEL or CLEAR events which update the SPI's
+ * pending state and handling mode per R_HHKMN. The logic is the
+ * same for "the input line changed" (R_QBXXV) and "software asked
+ * us to resample" (R_DMTFM).
+ */
+ if (spi->level) {
+ /*
+ * SET_LEVEL or SET_EDGE: interrupt becomes pending, and the
+ * handling mode is updated to match the trigger mode.
+ */
+ spi->pending = true;
+ spi->hm = spi->tm == GICV5_TRIGGER_EDGE ? GICV5_EDGE : GICV5_LEVEL;
+ } else if (spi->tm == GICV5_TRIGGER_LEVEL) {
+ /* falling edges only trigger a CLEAR event for level-triggered */
+ spi->pending = false;
+ }
+}
+
static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
uint64_t *data, MemTxAttrs attrs)
{
{
GICv5SPIState *spi = spi_for_selr(cs, domain);
if (spi) {
+ GICv5TriggerMode old_tm = spi->tm;
spi->tm = FIELD_EX32(data, IRS_SPI_CFGR, TM);
+ if (spi->tm != old_tm) {
+ /*
+ * R_KBPXL: updates to SPI trigger mode can generate CLEAR or
+ * SET_LEVEL events. This is not the same logic as spi_sample().
+ */
+ if (spi->tm == GICV5_TRIGGER_LEVEL) {
+ if (spi->level) {
+ spi->pending = true;
+ spi->hm = GICV5_LEVEL;
+ } else {
+ spi->pending = false;
+ }
+ } else if (spi->level) {
+ spi->pending = false;
+ }
+ }
}
return true;
}
}
}
return true;
+ case A_IRS_SPI_RESAMPLER:
+ {
+ uint32_t id = FIELD_EX32(data, IRS_SPI_RESAMPLER, SPI_ID);
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
+
+ if (spi) {
+ spi_sample(spi);
+ }
+ trace_gicv5_spi_state(id, spi->level, spi->pending, spi->active);
+ return true;
+ }
}
return false;
/* These irqs are all SPIs; the INTID is irq + s->spi_base */
GICv5Common *cs = ARM_GICV5_COMMON(opaque);
uint32_t spi_id = irq + cs->spi_base;
+ GICv5SPIState *spi = gicv5_raw_spi_state(cs, spi_id);
+
+ if (!spi || spi->level == level) {
+ return;
+ }
trace_gicv5_spi(spi_id, level);
+
+ spi->level = level;
+ spi_sample(spi);
+ trace_gicv5_spi_state(spi_id, spi->level, spi->pending, spi->active);
}
static void gicv5_reset_hold(Object *obj, ResetType type)
gicv5_set_handling(const char *domain, const char *type, bool virtual, uint32_t id, int handling) "GICv5 IRS SetHandling %s %s virtual:%d ID %u handling %d"
gicv5_set_target(const char *domain, const char *type, bool virtual, uint32_t id, uint32_t iaffid, int irm) "GICv5 IRS SetTarget %s %s virtual:%d ID %u IAFFID %u routingmode %d"
gicv5_request_config(const char *domain, const char *type, bool virtual, uint32_t id, uint64_t icsr) "GICv5 IRS RequestConfig %s %s virtual:%d ID %u ICSR 0x%" PRIx64
+gicv5_spi_state(uint32_t spi_id, bool level, bool pending, bool active) "GICv5 IRS SPI ID %u now level %d pending %d active %d"
# arm_gicv5_common.c
gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u CPUs, SPI base %u, SPI IRS range %u, SPI range %u"