Skip to content

Commit b321c31

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: vgic-v4: Make the doorbell request robust w.r.t preemption
Xiang reports that VMs occasionally fail to boot on GICv4.1 systems when running a preemptible kernel, as it is possible that a vCPU is blocked without requesting a doorbell interrupt. The issue is that any preemption that occurs between vgic_v4_put() and schedule() on the block path will mark the vPE as nonresident and *not* request a doorbell irq. This occurs because when the vcpu thread is resumed on its way to block, vcpu_load() will make the vPE resident again. Once the vcpu actually blocks, we don't request a doorbell anymore, and the vcpu won't be woken up on interrupt delivery. Fix it by tracking that we're entering WFI, and key the doorbell request on that flag. This allows us not to make the vPE resident when going through a preempt/schedule cycle, meaning we don't lose any state. Cc: stable@vger.kernel.org Fixes: 8e01d9a ("KVM: arm64: vgic-v4: Move the GICv4 residency flow to be driven by vcpu_load/put") Reported-by: Xiang Chen <chenxiang66@hisilicon.com> Suggested-by: Zenghui Yu <yuzenghui@huawei.com> Tested-by: Xiang Chen <chenxiang66@hisilicon.com> Co-developed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org> Acked-by: Zenghui Yu <yuzenghui@huawei.com> Link: https://lore.kernel.org/r/20230713070657.3873244-1-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent dcf89d1 commit b321c31

File tree

5 files changed

+13
-6
lines changed

5 files changed

+13
-6
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,8 @@ struct kvm_vcpu_arch {
727727
#define DBG_SS_ACTIVE_PENDING __vcpu_single_flag(sflags, BIT(5))
728728
/* PMUSERENR for the guest EL0 is on physical CPU */
729729
#define PMUSERENR_ON_CPU __vcpu_single_flag(sflags, BIT(6))
730+
/* WFI instruction trapped */
731+
#define IN_WFI __vcpu_single_flag(sflags, BIT(7))
730732

731733

732734
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */

arch/arm64/kvm/arm.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -718,13 +718,15 @@ void kvm_vcpu_wfi(struct kvm_vcpu *vcpu)
718718
*/
719719
preempt_disable();
720720
kvm_vgic_vmcr_sync(vcpu);
721-
vgic_v4_put(vcpu, true);
721+
vcpu_set_flag(vcpu, IN_WFI);
722+
vgic_v4_put(vcpu);
722723
preempt_enable();
723724

724725
kvm_vcpu_halt(vcpu);
725726
vcpu_clear_flag(vcpu, IN_WFIT);
726727

727728
preempt_disable();
729+
vcpu_clear_flag(vcpu, IN_WFI);
728730
vgic_v4_load(vcpu);
729731
preempt_enable();
730732
}
@@ -792,7 +794,7 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
792794
if (kvm_check_request(KVM_REQ_RELOAD_GICv4, vcpu)) {
793795
/* The distributor enable bits were changed */
794796
preempt_disable();
795-
vgic_v4_put(vcpu, false);
797+
vgic_v4_put(vcpu);
796798
vgic_v4_load(vcpu);
797799
preempt_enable();
798800
}

arch/arm64/kvm/vgic/vgic-v3.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
749749
{
750750
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
751751

752-
WARN_ON(vgic_v4_put(vcpu, false));
752+
WARN_ON(vgic_v4_put(vcpu));
753753

754754
vgic_v3_vmcr_sync(vcpu);
755755

arch/arm64/kvm/vgic/vgic-v4.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,14 +336,14 @@ void vgic_v4_teardown(struct kvm *kvm)
336336
its_vm->vpes = NULL;
337337
}
338338

339-
int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db)
339+
int vgic_v4_put(struct kvm_vcpu *vcpu)
340340
{
341341
struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
342342

343343
if (!vgic_supports_direct_msis(vcpu->kvm) || !vpe->resident)
344344
return 0;
345345

346-
return its_make_vpe_non_resident(vpe, need_db);
346+
return its_make_vpe_non_resident(vpe, !!vcpu_get_flag(vcpu, IN_WFI));
347347
}
348348

349349
int vgic_v4_load(struct kvm_vcpu *vcpu)
@@ -354,6 +354,9 @@ int vgic_v4_load(struct kvm_vcpu *vcpu)
354354
if (!vgic_supports_direct_msis(vcpu->kvm) || vpe->resident)
355355
return 0;
356356

357+
if (vcpu_get_flag(vcpu, IN_WFI))
358+
return 0;
359+
357360
/*
358361
* Before making the VPE resident, make sure the redistributor
359362
* corresponding to our current CPU expects us here. See the

include/kvm/arm_vgic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int irq,
431431

432432
int vgic_v4_load(struct kvm_vcpu *vcpu);
433433
void vgic_v4_commit(struct kvm_vcpu *vcpu);
434-
int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db);
434+
int vgic_v4_put(struct kvm_vcpu *vcpu);
435435

436436
/* CPU HP callbacks */
437437
void kvm_vgic_cpu_up(void);

0 commit comments

Comments
 (0)