]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
arm64: KVM: Always set ICH_HCR_EL2.EN if GICv4 is enabled
authorMarc Zyngier <marc.zyngier@arm.com>
Wed, 13 Mar 2019 18:07:50 +0000 (18:07 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Tue, 19 Mar 2019 17:56:34 +0000 (17:56 +0000)
The normal interrupt flow is not to enable the vgic when no virtual
interrupt is to be injected (i.e. the LRs are empty). But when a guest
is likely to use GICv4 for LPIs, we absolutely need to switch it on
at all times. Otherwise, VLPIs only get delivered when there is something
in the LRs, which doesn't happen very often.

Reported-by: Nianyao Tang <tangnianyao@huawei.com>
Tested-by: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
virt/kvm/arm/hyp/vgic-v3-sr.c
virt/kvm/arm/vgic/vgic.c

index 264d92da32403810ea316912f9cba05eea040215..370bd6c5e6cb3e0e2a88bd985c38fd77a6277812 100644 (file)
@@ -222,7 +222,7 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
                }
        }
 
-       if (used_lrs) {
+       if (used_lrs || cpu_if->its_vpe.its_vm) {
                int i;
                u32 elrsr;
 
@@ -247,7 +247,7 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
        u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
        int i;
 
-       if (used_lrs) {
+       if (used_lrs || cpu_if->its_vpe.its_vm) {
                write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
                for (i = 0; i < used_lrs; i++)
index abd9c735267784a3085b797d33133a579dc629c6..3af69f2a38667308cf45e13e26540b379cbffb7c 100644 (file)
@@ -867,15 +867,21 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
         * either observe the new interrupt before or after doing this check,
         * and introducing additional synchronization mechanism doesn't change
         * this.
+        *
+        * Note that we still need to go through the whole thing if anything
+        * can be directly injected (GICv4).
         */
-       if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
+       if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head) &&
+           !vgic_supports_direct_msis(vcpu->kvm))
                return;
 
        DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
-       raw_spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
-       vgic_flush_lr_state(vcpu);
-       raw_spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+       if (!list_empty(&vcpu->arch.vgic_cpu.ap_list_head)) {
+               raw_spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+               vgic_flush_lr_state(vcpu);
+               raw_spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+       }
 
        if (can_access_vgic_from_kernel())
                vgic_restore_state(vcpu);