Skip to content

Commit 70450a9

Browse files
committed
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]>
1 parent 6c1b752 commit 70450a9

File tree

1 file changed

+13
-7
lines changed

1 file changed

+13
-7
lines changed

virt/kvm/arm/arch_timer.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,9 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
9999
}
100100
vtimer = vcpu_vtimer(vcpu);
101101

102-
if (!vtimer->irq.level) {
103-
vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
104-
if (kvm_timer_irq_can_fire(vtimer))
105-
kvm_timer_update_irq(vcpu, true, vtimer);
106-
}
102+
vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
103+
if (kvm_timer_irq_can_fire(vtimer))
104+
kvm_timer_update_irq(vcpu, true, vtimer);
107105

108106
if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
109107
kvm_vtimer_update_mask_user(vcpu);
@@ -324,12 +322,20 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
324322
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
325323
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
326324
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
325+
bool level;
327326

328327
if (unlikely(!timer->enabled))
329328
return;
330329

331-
if (kvm_timer_should_fire(vtimer) != vtimer->irq.level)
332-
kvm_timer_update_irq(vcpu, !vtimer->irq.level, vtimer);
330+
/*
331+
* The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
332+
* of its lifecycle is offloaded to the hardware, and we therefore may
333+
* not have lowered the irq.level value before having to signal a new
334+
* interrupt, but have to signal an interrupt every time the level is
335+
* asserted.
336+
*/
337+
level = kvm_timer_should_fire(vtimer);
338+
kvm_timer_update_irq(vcpu, level, vtimer);
333339

334340
if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
335341
kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);

0 commit comments

Comments
 (0)