KVM: arm/arm64: Don't cache the timer IRQ level

"Linux Kernel Mailing List" <[email protected]> Sat, 10 Feb 2018 22:00:23 +0000 (UTC)
Newsgroups gmane.linux.kernel.commits.head
Message-ID <[email protected]>
Web:        https://git.kernel.org/torvalds/c/70450a9fbe0658e864f882d4351e5bae018b2647
Commit:     70450a9fbe0658e864f882d4351e5bae018b2647
Parent:     6c1b7521f4a07cc63bbe2dfe290efed47cdb780a
Refname:    refs/heads/master
Author:     Christoffer Dall <[email protected]>
AuthorDate: Mon Sep 4 11:56:37 2017 +0200
Committer:  Christoffer Dall <[email protected]>
CommitDate: Tue Jan 2 10:05:46 2018 +0100

    KVM: arm/arm64: Don't cache the timer IRQ level
    
    The timer logic was designed after a strict idea of modeling an
    interrupt line level in software, meaning that only transitions in the
    level need to be reported to the VGIC.  This works well for the timer,
    because the arch timer code is in complete control of the device and can
    track the transitions of the line.
    
    However, as we are about to support using the HW bit in the VGIC not
    just for the timer, but also for VFIO which cannot track transitions of
    the interrupt line, we have to decide on an interface between the GIC
    and other subsystems for level triggered mapped interrupts, which both
    the timer and VFIO can use.
    
    VFIO only sees an asserting transition of the physical interrupt line,
    and tells the VGIC when that happens.  That means that part of the
    interrupt flow is offloaded to the hardware.
    
    To use the same interface for VFIO devices and the timer, we therefore
    have to change the timer (we cannot change VFIO because it doesn't know
    the details of the device it is assigning to a VM).
    
    Luckily, changing the timer is simple, we just need to stop 'caching'
    the line level, but instead let the VGIC know the state of the timer
    every time there is a potential change in the line level, and when the
    line level should be asserted from the timer ISR.  The VGIC can ignore
    extra notifications using its validate mechanism.
    
    Reviewed-by: Marc Zyngier <[email protected]>
    Reviewed-by: Andre Przywara <[email protected]>
    Reviewed-by: Julien Thierry <[email protected]>
    Signed-off-by: Christoffer Dall <[email protected]>
---
 virt/kvm/arm/arch_timer.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f9555b1e7f15..9376fe03bf2e 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -99,11 +99,9 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 	}
 	vtimer = vcpu_vtimer(vcpu);
 
-	if (!vtimer->irq.level) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		if (kvm_timer_irq_can_fire(vtimer))
-			kvm_timer_update_irq(vcpu, true, vtimer);
-	}
+	vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
+	if (kvm_timer_irq_can_fire(vtimer))
+		kvm_timer_update_irq(vcpu, true, vtimer);
 
 	if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
 		kvm_vtimer_update_mask_user(vcpu);
@@ -324,12 +322,20 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	bool level;
 
 	if (unlikely(!timer->enabled))
 		return;
 
-	if (kvm_timer_should_fire(vtimer) != vtimer->irq.level)
-		kvm_timer_update_irq(vcpu, !vtimer->irq.level, vtimer);
+	/*
+	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
+	 * of its lifecycle is offloaded to the hardware, and we therefore may
+	 * not have lowered the irq.level value before having to signal a new
+	 * interrupt, but have to signal an interrupt every time the level is
+	 * asserted.
+	 */
+	level = kvm_timer_should_fire(vtimer);
+	kvm_timer_update_irq(vcpu, level, vtimer);
 
 	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
 		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html