[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] xen/arm: ignore spurious interrupts from virtual timer



From: Mykola Kvach <mykola_kvach@xxxxxxxx>

If a spurious virtual timer interrupt occurs (i.e. the interrupt fires
but CNTV_CTL_EL0 does not report it as pending), Xen masks the virtual
timer and injects the vtimer IRQ into the guest. For Linux guests, the
timer interrupt is unmasked only after programming a new CVAL value from
the timer interrupt handler. When the interrupt is not reported as
pending, the handler can skip that programming step, leaving the timer
masked and stalling the affected CPU.

This patch mirrors the Linux arm generic timer handler: if the interrupt
fires but the pending bit is not set, treat it as spurious and ignore it.

This issue is reproducible under heavy load on the R-Car X5H board
(Cortex-A720AE r0p0).

Signed-off-by: Mykola Kvach <mykola_kvach@xxxxxxxx>
---
 xen/arch/arm/include/asm/perfc_defn.h |  7 ++++---
 xen/arch/arm/time.c                   | 11 ++++++++++-
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/include/asm/perfc_defn.h 
b/xen/arch/arm/include/asm/perfc_defn.h
index effd25b69e..f83989d95a 100644
--- a/xen/arch/arm/include/asm/perfc_defn.h
+++ b/xen/arch/arm/include/asm/perfc_defn.h
@@ -69,9 +69,10 @@ PERFCOUNTER(ppis,                 "#PPIs")
 PERFCOUNTER(spis,                 "#SPIs")
 PERFCOUNTER(guest_irqs,           "#GUEST-IRQS")
 
-PERFCOUNTER(hyp_timer_irqs,   "Hypervisor timer interrupts")
-PERFCOUNTER(virt_timer_irqs,  "Virtual timer interrupts")
-PERFCOUNTER(maintenance_irqs, "Maintenance interrupts")
+PERFCOUNTER(hyp_timer_irqs,             "Hypervisor timer interrupts")
+PERFCOUNTER(virt_timer_irqs,            "Virtual timer interrupts")
+PERFCOUNTER(virt_timer_spurious_irqs,   "Virtual timer spurious interrupts")
+PERFCOUNTER(maintenance_irqs,           "Maintenance interrupts")
 
 PERFCOUNTER(atomics_guest,    "atomics: guest access")
 PERFCOUNTER(atomics_guest_paused,   "atomics: guest paused")
diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index cc3fcf47b6..d18d6568bb 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -258,6 +258,8 @@ static void htimer_interrupt(int irq, void *dev_id)
 
 static void vtimer_interrupt(int irq, void *dev_id)
 {
+    register_t ctl;
+
     /*
      * Edge-triggered interrupts can be used for the virtual timer. Even
      * if the timer output signal is masked in the context switch, the
@@ -271,9 +273,16 @@ static void vtimer_interrupt(int irq, void *dev_id)
     if ( unlikely(is_idle_vcpu(current)) )
         return;
 
+    ctl = READ_SYSREG(CNTV_CTL_EL0);
+    if ( unlikely(!(ctl & CNTx_CTL_PENDING)) )
+    {
+        perfc_incr(virt_timer_spurious_irqs);
+        return;
+    }
+
     perfc_incr(virt_timer_irqs);
 
-    current->arch.virt_timer.ctl = READ_SYSREG(CNTV_CTL_EL0);
+    current->arch.virt_timer.ctl = ctl;
     WRITE_SYSREG(current->arch.virt_timer.ctl | CNTx_CTL_MASK, CNTV_CTL_EL0);
     vgic_inject_irq(current->domain, current, current->arch.virt_timer.irq, 
true);
 }
-- 
2.43.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.