aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kvm/vgic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kvm/vgic.c')
-rw-r--r--arch/arm/kvm/vgic.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
index 8f32702108b2..2d5e29f1c28f 100644
--- a/arch/arm/kvm/vgic.c
+++ b/arch/arm/kvm/vgic.c
@@ -71,6 +71,7 @@
71#define ACCESS_WRITE_VALUE (3 << 1) 71#define ACCESS_WRITE_VALUE (3 << 1)
72#define ACCESS_WRITE_MASK(x) ((x) & (3 << 1)) 72#define ACCESS_WRITE_MASK(x) ((x) & (3 << 1))
73 73
74static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
74static void vgic_update_state(struct kvm *kvm); 75static void vgic_update_state(struct kvm *kvm);
75static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg); 76static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg);
76 77
@@ -353,6 +354,7 @@ static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu,
353 if (mmio->is_write) { 354 if (mmio->is_write) {
354 if (offset < 4) /* Force SGI enabled */ 355 if (offset < 4) /* Force SGI enabled */
355 *reg |= 0xffff; 356 *reg |= 0xffff;
357 vgic_retire_disabled_irqs(vcpu);
356 vgic_update_state(vcpu->kvm); 358 vgic_update_state(vcpu->kvm);
357 return true; 359 return true;
358 } 360 }
@@ -804,6 +806,34 @@ static void vgic_update_state(struct kvm *kvm)
804 (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT) 806 (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
805#define MK_LR_PEND(src, irq) \ 807#define MK_LR_PEND(src, irq) \
806 (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq)) 808 (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq))
809
810/*
811 * An interrupt may have been disabled after being made pending on the
812 * CPU interface (the classic case is a timer running while we're
813 * rebooting the guest - the interrupt would kick as soon as the CPU
814 * interface gets enabled, with deadly consequences).
815 *
816 * The solution is to examine already active LRs, and check the
817 * interrupt is still enabled. If not, just retire it.
818 */
819static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
820{
821 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
822 int lr;
823
824 for_each_set_bit(lr, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
825 int irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
826
827 if (!vgic_irq_is_enabled(vcpu, irq)) {
828 vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
829 clear_bit(lr, vgic_cpu->lr_used);
830 vgic_cpu->vgic_lr[lr] &= ~GICH_LR_STATE;
831 if (vgic_irq_is_active(vcpu, irq))
832 vgic_irq_clear_active(vcpu, irq);
833 }
834 }
835}
836
807/* 837/*
808 * Queue an interrupt to a CPU virtual interface. Return true on success, 838 * Queue an interrupt to a CPU virtual interface. Return true on success,
809 * or false if it wasn't possible to queue it. 839 * or false if it wasn't possible to queue it.