Patch "KVM: arm/arm64: vgic: Don't populate multiple LRs with the same vintid" has been added to the 4.14-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
KVM: arm/arm64: vgic: Don't populate multiple LRs with the same vintid
to the 4.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
kvm-arm-arm64-vgic-don-t-populate-multiple-lrs-with-the-same-vintid.patch
and it can be found in the queue-4.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
16ca6a607d84bef0129698d8d808f501afd08d43Mon Sep 17 00:00:00 2001
From: Marc Zyngier <[email protected]>
Date: Tue, 6 Mar 2018 21:48:01 +0000
Subject: KVM: arm/arm64: vgic: Don't populate multiple LRs with the same vintid
From: Marc Zyngier <[email protected]>
commit 16ca6a607d84bef0129698d8d808f501afd08d43 upstream.
The vgic code is trying to be clever when injecting GICv2 SGIs, and will happily populate LRs with the same interrupt number if they come from multiple vcpus (after all, they are distinct interrupt sources).
Unfortunately, this is against the letter of the architecture, and the GICv2 architecture spec says "Each valid interrupt stored in the List registers must have a unique VirtualID for that virtual CPU interface.". GICv3 has similar (although slightly ambiguous) restrictions.
This results in guests locking up when using GICv2-on-GICv3, for example. The obvious fix is to stop trying so hard, and inject a single vcpu per SGI per guest entry. After all, pending SGIs with multiple source vcpus are pretty rare, and are mostly seen in scenario where the physical CPUs are severely overcomitted.
But as we now only inject a single instance of a multi-source SGI per vcpu entry, we may delay those interrupts for longer than strictly necessary, and run the risk of injecting lower priority interrupts in the meantime.
In order to address this, we adopt a three stage strategy:
- If we encounter a multi-source SGI in the AP list while computing its depth, we force the list to be sorted
- When populating the LRs, we prevent the injection of any interrupt of lower priority than that of the first multi-source SGI we've injected.
- Finally, the injection of a multi-source SGI triggers the request of a maintenance interrupt when there will be no pending interrupt in the LRs (HCR_NPIE).
At the point where the last pending interrupt in the LRs switches from Pending to Active, the maintenance interrupt will be delivered, allowing us to add the remaining SGIs using the same process.
--- include/linux/irqchip/arm-gic-v3.h | 1 include/linux/irqchip/arm-gic.h | 1 virt/kvm/arm/vgic/vgic-v2.c | 9 ++++- virt/kvm/arm/vgic/vgic-v3.c | 9 ++++- virt/kvm/arm/vgic/vgic.c | 61 ++++++++++++++++++++++++++++--------- virt/kvm/arm/vgic/vgic.h | 2 + 6 files changed, 67 insertions(+), 16 deletions(-)
include/linux/irqchip/arm-gic-v3.h +1 -0
@@ -501,6 +501,7 @@#define ICH_HCR_EN (1 << 0)#define ICH_HCR_UIE (1 << 1) +#define ICH_HCR_NPIE (1 << 3)#define ICH_HCR_TC (1 << 10)#define ICH_HCR_TALL0 (1 << 11)#define ICH_HCR_TALL1 (1 << 12)
include/linux/irqchip/arm-gic.h +1 -0
@@ -84,6 +84,7 @@#define GICH_HCR_EN (1 << 0)#define GICH_HCR_UIE (1 << 1) +#define GICH_HCR_NPIE (1 << 3)#define GICH_LR_VIRTUALID (0x3ff << 0)#define GICH_LR_PHYSID_CPUID_SHIFT (10)
virt/kvm/arm/vgic/vgic-v2.c +8 -1
@@ -37,6 +37,13 @@ void vgic_v2_init_lrs(void)vgic_v2_write_lr (i,0 ); } +void vgic_v2_set_npie (struct kvm_vcpu *vcpu) +{ +struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2; + + cpuif->vgic_hcr |=GICH_HCR_NPIE ; +} +void vgic_v2_set_underflow (struct kvm_vcpu *vcpu) {struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
@@ -63,7 +70,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcstruct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2;int lr; - cpuif->vgic_hcr &= ~GICH_HCR_UIE ; + cpuif->vgic_hcr &= ~(GICH_HCR_UIE |GICH_HCR_NPIE );for (lr =0 ; lr < vgic_cpu->used_lrs; lr++) {u32 val = cpuif->vgic_lr[lr];
virt/kvm/arm/vgic/vgic-v3.c +8 -1
@@ -25,6 +25,13 @@ static bool group0_trap;static bool group1_trap;static bool common_trap; +void vgic_v3_set_npie (struct kvm_vcpu *vcpu) +{ +struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3; + + cpuif->vgic_hcr |=ICH_HCR_NPIE ; +} +void vgic_v3_set_underflow (struct kvm_vcpu *vcpu) {struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -45,7 +52,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcu32 model = vcpu->kvm->arch.vgic.vgic_model;int lr; - cpuif->vgic_hcr &= ~ICH_HCR_UIE ; + cpuif->vgic_hcr &= ~(ICH_HCR_UIE |ICH_HCR_NPIE );for (lr =0 ; lr < vgic_cpu->used_lrs; lr++) {u64 val = cpuif->vgic_lr[lr];
virt/kvm/arm/vgic/vgic.c +47 -14
103 lines not on this page · raw message
virt/kvm/arm/vgic/vgic.h +2 -0
@@ -150,6 +150,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcvoid vgic_v2_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr);void vgic_v2_clear_lr (struct kvm_vcpu *vcpu,int lr);void vgic_v2_set_underflow (struct kvm_vcpu *vcpu); +void vgic_v2_set_npie (struct kvm_vcpu *vcpu);int vgic_v2_has_attr_regs (struct kvm_device *dev,struct kvm_device_attr *attr);int vgic_v2_dist_uaccess (struct kvm_vcpu *vcpu,bool is_write,int offset,u32 *val);
@@ -179,6 +180,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcvoid vgic_v3_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr);void vgic_v3_clear_lr (struct kvm_vcpu *vcpu,int lr);void vgic_v3_set_underflow (struct kvm_vcpu *vcpu); +void vgic_v3_set_npie (struct kvm_vcpu *vcpu);void vgic_v3_set_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v3_get_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v3_enable (struct kvm_vcpu *vcpu);
Patches currently in stable-queue which might be from [email protected] are
queue-4.14/kvm-arm-arm64-vgic-don-t-populate-multiple-lrs-with-the-same-vintid.patch queue-4.14/kvm-arm-arm64-vgic-v3-tighten-synchronization-for-guests-using-v2-on-v3.patch queue-4.14/kvm-arm-arm64-reduce-verbosity-of-kvm-init-log.patch