[PATCH 23/65] hw/intc/arm_gicv5: Make gicv5_set_* update SPI state

Peter Maydell posted 65 patches 1 month, 2 weeks ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>, Pierrick Bouvier <pierrick.bouvier@linaro.org>, Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Eduardo Habkost <eduardo@habkost.net>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>
There is a newer version of this series
[PATCH 23/65] hw/intc/arm_gicv5: Make gicv5_set_* update SPI state
Posted by Peter Maydell 1 month, 2 weeks ago
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 <peter.maydell@linaro.org>
---
 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
Re: [PATCH 23/65] hw/intc/arm_gicv5: Make gicv5_set_* update SPI state
Posted by Jonathan Cameron via qemu development 1 month ago
On Mon, 23 Feb 2026 17:01:30 +0000
Peter Maydell <peter.maydell@linaro.org> wrote:

> 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 <peter.maydell@linaro.org>
For this one I wonder if the resulting code structure is reflecting
more about how the patch series evolves rather than a more ideal
version where the SPI and LPI are treated as to 'equalish' options.
So to me a switch statement with two good legs and a default one
that rejects all other types of interrupt (so the 1 remaining one!)

Not that important however.

> ---
>  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) {

To me it feels a bit like this would be readable as a switch statement
given 2 out of 3 types are handled.

If you do go that way, then introducing the switch in the earlier patch
probably makes sense to minimize churn.

> +        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;
> +    }