hw/intc/arm_gicv5: Update SPI state for CLEAR/SET events
When an SPI irq line changes level, this causes what the spec describes as SET_LEVEL, SET_EDGE or CLEAR events. These also happen when the trigger mode is reconfigured, or when software requests a manual resample via the IRS_SPI_RESAMPLER register. SET_LEVEL and SET_EDGE events make the interrupt pending, and update its handler mode to match its trigger mode. CLEAR events make the interrupt no longer pending. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-29-peter.maydell@linaro.org
Peter Maydell committed
Mar 27, 2026 at 11:16 UTC
33185e1d64e6a0150504715dff4a507f2e07f974
2 files changed
+60
hw/intc/arm_gicv5.c
+59
@@ -946,6 +946,28 @@ static void irs_ist_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value)
946
}
947
}
948
949
+static void spi_sample(GICv5SPIState *spi)
950
+{
951
+ /*
952
+ * Sample the state of the SPI input line; this generates
953
+ * SET_EDGE, SET_LEVEL or CLEAR events which update the SPI's
954
+ * pending state and handling mode per R_HHKMN. The logic is the
955
+ * same for "the input line changed" (R_QBXXV) and "software asked
956
+ * us to resample" (R_DMTFM).
957
+ */
958
+ if (spi->level) {
959
+ /*
960
+ * SET_LEVEL or SET_EDGE: interrupt becomes pending, and the
961
+ * handling mode is updated to match the trigger mode.
962
+ */
963
+ spi->pending = true;
964
+ spi->hm = spi->tm == GICV5_TRIGGER_EDGE ? GICV5_EDGE : GICV5_LEVEL;
965
+ } else if (spi->tm == GICV5_TRIGGER_LEVEL) {
966
+ /* falling edges only trigger a CLEAR event for level-triggered */
967
+ spi->pending = false;
968
+ }
969
+}
970
+
971
static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
972
uint64_t *data, MemTxAttrs attrs)
973
{
@@ -1096,7 +1118,24 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
1118
{
1119
GICv5SPIState *spi = spi_for_selr(cs, domain);
1120
if (spi) {
1121
+ GICv5TriggerMode old_tm = spi->tm;
1122
spi->tm = FIELD_EX32(data, IRS_SPI_CFGR, TM);
1123
+ if (spi->tm != old_tm) {
1124
+ /*
1125
+ * R_KBPXL: updates to SPI trigger mode can generate CLEAR or
1126
+ * SET_LEVEL events. This is not the same logic as spi_sample().
1127
+ */
1128
+ if (spi->tm == GICV5_TRIGGER_LEVEL) {
1129
+ if (spi->level) {
1130
+ spi->pending = true;
1131
+ spi->hm = GICV5_LEVEL;
1132
+ } else {
1133
+ spi->pending = false;
1134
+ }
1135
+ } else if (spi->level) {
1136
+ spi->pending = false;
1137
+ }
1138
+ }
1139
}
1140
return true;
1141
}
@@ -1109,6 +1148,17 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
1148
}
1149
}
1150
return true;
1151
+ case A_IRS_SPI_RESAMPLER:
1152
+ {
1153
+ uint32_t id = FIELD_EX32(data, IRS_SPI_RESAMPLER, SPI_ID);
1154
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
1155
+
1156
+ if (spi) {
1157
+ spi_sample(spi);
1158
+ }
1159
+ trace_gicv5_spi_state(id, spi->level, spi->pending, spi->active);
1160
+ return true;
1161
+ }
1162
}
1163
1164
return false;
@@ -1259,8 +1309,17 @@ static void gicv5_set_spi(void *opaque, int irq, int level)
1309
/* These irqs are all SPIs; the INTID is irq + s->spi_base */
1310
GICv5Common *cs = ARM_GICV5_COMMON(opaque);
1311
uint32_t spi_id = irq + cs->spi_base;
1312
+ GICv5SPIState *spi = gicv5_raw_spi_state(cs, spi_id);
1313
+
1314
+ if (!spi || spi->level == level) {
1315
+ return;
1316
+ }
1317
1318
trace_gicv5_spi(spi_id, level);
1319
+
1320
+ spi->level = level;
1321
+ spi_sample(spi);
1322
+ trace_gicv5_spi_state(spi_id, spi->level, spi->pending, spi->active);
1323
}
1324
1325
static void gicv5_reset_hold(Object *obj, ResetType type)
hw/intc/trace-events
+1
@@ -241,6 +241,7 @@ gicv5_set_pending(const char *domain, const char *type, bool virtual, uint32_t i
241
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"
242
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"
243
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
244
+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"
245
246
# arm_gicv5_common.c
247
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"