]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: Fix arch timer interrupts for GICv3-on-GICv5 guests
authorSascha Bischoff <sascha.bischoff@arm.com>
Wed, 20 May 2026 09:19:49 +0000 (10:19 +0100)
committerMarc Zyngier <maz@kernel.org>
Sat, 23 May 2026 14:07:41 +0000 (15:07 +0100)
When running on a GICv5 host, we push an arch-timer-specific interrupt
domain for the timer interrupts. This interrupt domain is used to mask
the host interrupt when a GICv5 guest is running. However, this
interrupt domain is still in place when running with a GICv3 guest on
GICv5 hardware. The result is that some interrupt state changes are
not correctly propragated to the host irqchip driver for legacy
guests.

Explicitly pass irqchip state changes though to the host irqchip
driver when running a GICv3-based guest on a GICv5 host. This bypasses
all masking, and thereby operates just as a native GICv3 guest would,
with the exception of having an additional irq domain in the
hierarchy.

Fixes: 9491c63b6cd7 ("KVM: arm64: gic-v5: Enlighten arch timer for GICv5")
Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Link: https://lore.kernel.org/r/20260520091949.542365-19-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/arch_timer.c

index f003df76fdda7caa2933851625c8cf14fdf6768b..53b67b4d0bf244a4b438678c2434b416cffb7130 100644 (file)
@@ -1294,7 +1294,12 @@ static int timer_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
 static int timer_irq_set_irqchip_state(struct irq_data *d,
                                       enum irqchip_irq_state which, bool val)
 {
-       if (which != IRQCHIP_STATE_ACTIVE || !irqd_is_forwarded_to_vcpu(d))
+       bool passthrough = which != IRQCHIP_STATE_ACTIVE ||
+               !irqd_is_forwarded_to_vcpu(d) ||
+               (kvm_vgic_global_state.type == VGIC_V5 &&
+                vgic_is_v3(kvm_get_running_vcpu()->kvm));
+
+       if (passthrough)
                return irq_chip_set_parent_state(d, which, val);
 
        if (val)
@@ -1307,15 +1312,7 @@ static int timer_irq_set_irqchip_state(struct irq_data *d,
 
 static void timer_irq_eoi(struct irq_data *d)
 {
-       /*
-        * On a GICv5 host, we still need to call EOI on the parent for
-        * PPIs. The host driver already handles irqs which are forwarded to
-        * vcpus, and skips the GIC CDDI while still doing the GIC CDEOI. This
-        * is required to emulate the EOIMode=1 on GICv5 hardware. Failure to
-        * call EOI unsurprisingly results in *BAD* lock-ups.
-        */
-       if (!irqd_is_forwarded_to_vcpu(d) ||
-           kvm_vgic_global_state.type == VGIC_V5)
+       if (!irqd_is_forwarded_to_vcpu(d))
                irq_chip_eoi_parent(d);
 }