hw/intc/arm_gicv5: Implement Activate command
Implement the equivalent of the GICv5 stream protocol's Activate command, which lets the cpuif tell the IRS to move its current highest priority pending interrupt into the Active state, and to clear the Pending state for an Edge handling mode interrupt. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-48-peter.maydell@linaro.org
Peter Maydell committed
Mar 27, 2026 at 11:16 UTC
89ce374897b5b5d9d123a3f2680266a9390f3677
3 files changed
+82
hw/intc/arm_gicv5.c
+58
@@ -1095,6 +1095,64 @@ uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain,
1095
}
1096
}
1097
1098
+void gicv5_activate(GICv5Common *cs, uint32_t id, GICv5Domain domain,
1099
+ GICv5IntType type, bool virtual)
1100
+{
1101
+ GICv5 *s = ARM_GICV5(cs);
1102
+ uint32_t iaffid;
1103
+
1104
+ trace_gicv5_activate(domain_name[domain], inttype_name(type), virtual, id);
1105
+
1106
+ if (virtual) {
1107
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_activate: tried to "
1108
+ "activate a virtual interrupt\n");
1109
+ return;
1110
+ }
1111
+
1112
+ switch (type) {
1113
+ case GICV5_LPI:
1114
+ {
1115
+ const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
1116
+ L2_ISTE_Handle h;
1117
+ uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h);
1118
+
1119
+ if (!l2_iste_p) {
1120
+ return;
1121
+ }
1122
+ *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, ACTIVE, true);
1123
+ if (FIELD_EX32(*l2_iste_p, L2_ISTE, HM) == GICV5_EDGE) {
1124
+ *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, PENDING, false);
1125
+ }
1126
+ iaffid = FIELD_EX32(*l2_iste_p, L2_ISTE, IAFFID);
1127
+ put_l2_iste(cs, cfg, &h);
1128
+ break;
1129
+ }
1130
+ case GICV5_SPI:
1131
+ {
1132
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
1133
+
1134
+ if (!spi) {
1135
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_activate: tried to "
1136
+ "activate unreachable SPI %d\n", id);
1137
+ return;
1138
+ }
1139
+
1140
+ spi->active = true;
1141
+ if (spi->hm == GICV5_EDGE) {
1142
+ spi->pending = false;
1143
+ }
1144
+ iaffid = spi->iaffid;
1145
+ break;
1146
+ }
1147
+ default:
1148
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_activate: tried to "
1149
+ "activate bad interrupt type %d\n", type);
1150
+ return;
1151
+ }
1152
+
1153
+ irs_recalc_hppi(s, domain, iaffid);
1154
+}
1155
+
1156
static void irs_map_l2_istr_write(GICv5 *s, GICv5Domain domain, uint64_t value)
1157
{
1158
GICv5Common *cs = ARM_GICV5_COMMON(s);
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_activate(const char *domain, const char *type, bool virtual, uint32_t id) "GICv5 IRS Activate %s %s virtual:%d ID %u"
245
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"
246
gicv5_irs_recalc_hppi_fail(const char *domain, uint32_t iaffid, const char *reason) "GICv5 IRS %s IAFFID %u: no HPPI: %s"
247
gicv5_irs_recalc_hppi(const char *domain, uint32_t iaffid, uint32_t id, uint8_t prio) "GICv5 IRS %s IAFFID %u: new HPPI ID 0x%x prio %u"
include/hw/intc/arm_gicv5_stream.h
+23
@@ -151,6 +151,29 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid,
151
uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain,
152
GICv5IntType type, bool virtual);
153
154
+/**
155
+ * gicv5_activate
156
+ * @cs: GIC IRS to send command to
157
+ * @id: interrupt ID
158
+ * @domain: interrupt domain to act on
159
+ * @type: interrupt type (LPI or SPI)
160
+ * @virtual: true if this is a virtual interrupt
161
+ *
162
+ * Activate the IRS's highest priority pending interrupt; matches the
163
+ * stream interface's Activate command.
164
+ *
165
+ * In the stream interface, the command has only the domain and
166
+ * virtual fields, because both the IRS and the CPUIF keep track of
167
+ * the IRS's current HPPI. In QEMU, we also have arguments here for
168
+ * @id and @type which are telling the IRS something that in hardware
169
+ * it already knows. This is because we have them to hand in the cpuif
170
+ * code, and it means we don't need to pass in an iaffid argument to
171
+ * tell the IRS which CPU we are so it can find the right element in
172
+ * its hppi[][] array.
173
+ */
174
+void gicv5_activate(GICv5Common *cs, uint32_t id, GICv5Domain domain,
175
+ GICv5IntType type, bool virtual);
176
+
177
/**
178
* gicv5_forward_interrupt
179
* @cpu: CPU interface to forward interrupt to