]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: GICv3: Avoid broadcast kick on CPUs lacking TDIR
authorMarc Zyngier <maz@kernel.org>
Thu, 20 Nov 2025 17:25:23 +0000 (17:25 +0000)
committerOliver Upton <oupton@kernel.org>
Mon, 24 Nov 2025 22:29:14 +0000 (14:29 -0800)
CPUs lacking TDIR always trap ICV_DIR_EL1, no matter what, since
we have ICH_HCR_EL2.TC set permanently. For these CPUs, it is
useless to use a broadcast kick on SPI injection, as the sole
purpose of this is to set TDIR.

We can therefore skip this on these CPUs, which are challenged
enough not to be burdened by extra IPIs. As a consequence,
permanently set the TDIR bit in the shadow state to notify the
fast-path emulation code of the exit reason.

Tested-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-34-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/kvm/vgic/vgic.c

index 55847fbad4d0da0607d0de2bb4df0e7477149fd6..968aa9d89be6352fd28c5d17e1fb38ffefda26d7 100644 (file)
@@ -53,10 +53,14 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,
         * need to deal with SPIs that can be deactivated on another
         * CPU.
         *
+        * On systems that do not implement TDIR, force the bit in the
+        * shadow state anyway to avoid IPI-ing on these poor sods.
+        *
         * Note that we set the trap irrespective of EOIMode, as that
         * can change behind our back without any warning...
         */
-       if (irqs_active_outside_lrs(als)                     ||
+       if (!cpus_have_final_cap(ARM64_HAS_ICH_HCR_EL2_TDIR) ||
+           irqs_active_outside_lrs(als)                     ||
            atomic_read(&vcpu->kvm->arch.vgic.active_spis))
                cpuif->vgic_hcr |= ICH_HCR_EL2_TDIR;
 }
index 83969c18ef0354ec911579fb11e4f0224e1b996c..693ec005c996c8a0bd1bae150fe6a1e71acefe8c 100644 (file)
@@ -370,12 +370,15 @@ static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *owne
 static bool vgic_model_needs_bcst_kick(struct kvm *kvm)
 {
        /*
-        * A GICv3 (or GICv3-like) system exposing a GICv3 to the
-        * guest needs a broadcast kick to set TDIR globally, even if
-        * the bit doesn't really exist (we still need to check for
-        * the shadow bit in the DIR emulation fast-path).
+        * A GICv3 (or GICv3-like) system exposing a GICv3 to the guest
+        * needs a broadcast kick to set TDIR globally.
+        *
+        * For systems that do not have TDIR (ARM's own v8.0 CPUs), the
+        * shadow TDIR bit is always set, and so is the register's TC bit,
+        * so no need to kick the CPUs.
         */
-       return (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3);
+       return (cpus_have_final_cap(ARM64_HAS_ICH_HCR_EL2_TDIR) &&
+               kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3);
 }
 
 /*