summaryrefslogtreecommitdiff
path: root/virt/kvm/arm/arch_timer.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2015-10-21 17:46:56 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2015-10-21 17:46:56 +0200
commitad355e383d826e3506c3caaa0fe991fd112de47b (patch)
tree1f1da23f174f30a2cb1b7d8c2e8b8ace1fd00032 /virt/kvm/arm/arch_timer.c
parentb10d92a54dac25a6152f1aa1ffc95c12908035ce (diff)
parent0d997491f814c87310a6ad7be30a9049c7150489 (diff)
Merge tag 'kvm-arm-for-v4.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into kvm-master
A late round of KVM/ARM fixes for v4.3-rc7, fixing: - A bug where level-triggered interrupts lowered from userspace are still routed to the guest - A memory leak an a failed initialization path - A build error under certain configurations - Several timer bugs introduced with moving the timer to the active state handling instead of the masking trick.
Diffstat (limited to 'virt/kvm/arm/arch_timer.c')
-rw-r--r--virt/kvm/arm/arch_timer.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 48c6e1ac6827..b9d3a32cbc04 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -137,6 +137,8 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+ bool phys_active;
+ int ret;
/*
* We're about to run this vcpu again, so there is no need to
@@ -151,6 +153,23 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
*/
if (kvm_timer_should_fire(vcpu))
kvm_timer_inject_irq(vcpu);
+
+ /*
+ * We keep track of whether the edge-triggered interrupt has been
+ * signalled to the vgic/guest, and if so, we mask the interrupt and
+ * the physical distributor to prevent the timer from raising a
+ * physical interrupt whenever we run a guest, preventing forward
+ * VCPU progress.
+ */
+ if (kvm_vgic_get_phys_irq_active(timer->map))
+ phys_active = true;
+ else
+ phys_active = false;
+
+ ret = irq_set_irqchip_state(timer->map->irq,
+ IRQCHIP_STATE_ACTIVE,
+ phys_active);
+ WARN_ON(ret);
}
/**