diff mbox series

[PULL,03/18] hw/intc/arm_gic: Fix deactivation of SPI lines

Message ID 20240622120643.3797539-4-peter.maydell@linaro.org (mailing list archive)
State New, archived
Headers show
Series [PULL,01/18] hw/net/can/xlnx-versal-canfd: Fix sorting of the tx queue | expand

Commit Message

Peter Maydell June 22, 2024, 12:06 p.m. UTC
From: "Edgar E. Iglesias" <edgar.iglesias@amd.com>

Julien reported that he has seen strange behaviour when running
Xen on QEMU using GICv2. When Xen migrates a guest's vCPU from
one pCPU to another while the vCPU is handling an interrupt, the
guest is unable to properly deactivate interrupts.

Looking at it a little closer, our GICv2 model treats
deactivation of SPI lines as if they were PPI's, i.e banked per
CPU core. The state for active interrupts should only be banked
for PPI lines, not for SPI lines.

Make deactivation of SPI lines unbanked, similar to how we
handle writes to GICD_ICACTIVER.

Reported-by: Julien Grall <julien@xen.org>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20240605143044.2029444-2-edgar.iglesias@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/gic_internal.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
index 8d29b40ca10..8ddbf554c69 100644
--- a/hw/intc/gic_internal.h
+++ b/hw/intc/gic_internal.h
@@ -280,6 +280,8 @@  static inline void gic_set_active(GICState *s, int irq, int cpu)
 
 static inline void gic_clear_active(GICState *s, int irq, int cpu)
 {
+    unsigned int cm;
+
     if (gic_is_vcpu(cpu)) {
         uint32_t *entry = gic_get_lr_entry(s, irq, cpu);
         GICH_LR_CLEAR_ACTIVE(*entry);
@@ -301,11 +303,13 @@  static inline void gic_clear_active(GICState *s, int irq, int cpu)
              * the GIC is secure.
              */
             if (!s->security_extn || GIC_DIST_TEST_GROUP(phys_irq, 1 << rcpu)) {
-                GIC_DIST_CLEAR_ACTIVE(phys_irq, 1 << rcpu);
+                cm = phys_irq < GIC_INTERNAL ? 1 << rcpu : ALL_CPU_MASK;
+                GIC_DIST_CLEAR_ACTIVE(phys_irq, cm);
             }
         }
     } else {
-        GIC_DIST_CLEAR_ACTIVE(irq, 1 << cpu);
+        cm = irq < GIC_INTERNAL ? 1 << cpu : ALL_CPU_MASK;
+        GIC_DIST_CLEAR_ACTIVE(irq, cm);
     }
 }