@samitouri / QOSamiQemu / commits / 33185e1d64

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"