In order to remove the crude hack where we sneak the masked bit
into the timer's control register, make use of the forwarded
interrupt API to save/restore the active state of the interrupt.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 include/kvm/arm_arch_timer.h |  3 +++
 virt/kvm/arm/arch_timer.c    | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 6d9aedd..6a69f42 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -53,6 +53,9 @@ struct arch_timer_cpu {
        /* Background timer active */
        bool                            armed;
 
+       /* Is interrupt active at the distributor level */
+       u32                             irq_active;
+
        /* Timer IRQ */
        const struct kvm_irq_level      *irq;
 #endif
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 22fa819..57817c5 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -63,7 +63,7 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
-       timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK;
+       timer->irq_active = IRQ_FWD_STATE_ACTIVE;
        kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
                            timer->irq->irq,
                            timer->irq->level);
@@ -117,6 +117,16 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
         * populate the CPU timer again.
         */
        timer_disarm(timer);
+
+       if (timer->irq_active) {
+               int ret;
+
+               ret = irq_set_fwd_state(host_vtimer_irq,
+                                       timer->irq_active,
+                                       IRQ_FWD_STATE_ACTIVE);
+               if (ret)
+                       kvm_err("unable to restore timer state");
+       }
 }
 
 /**
@@ -130,8 +140,16 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
        cycle_t cval, now;
+       int ret;
        u64 ns;
 
+       ret = irq_get_fwd_state(host_vtimer_irq, &timer->irq_active,
+                               IRQ_FWD_STATE_ACTIVE);
+       if (ret)
+               kvm_err("unable to retrieve timer state");
+       if (timer->irq_active)
+               irq_set_fwd_state(host_vtimer_irq, 0, IRQ_FWD_STATE_ACTIVE);
+
        if ((timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) ||
                !(timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE))
                return;
@@ -166,6 +184,12 @@ void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
         * vcpu timer irq number when the vcpu is reset.
         */
        timer->irq = irq;
+
+       /*
+        * Tell the VGIC that the virtual interrupt is tied to a
+        * physical interrupt. We do that once per VCPU.
+        */
+       vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq);
 }
 
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
@@ -290,6 +314,10 @@ int kvm_timer_hyp_init(void)
        }
 
        kvm_info("%s IRQ%d\n", np->name, ppi);
+
+       /* Tell the GIC we're forwarding the interrupt to a guest */
+       irqd_set_irq_forwarded(irq_get_irq_data(host_vtimer_irq));
+
        on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
 
        goto out;
@@ -305,6 +333,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
        timer_disarm(timer);
+       vgic_unmap_phys_irq(vcpu, timer->irq->irq, host_vtimer_irq);
 }
 
 int kvm_timer_init(struct kvm *kvm)
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to