ARM: evtchn: Handle level triggered IRQs correctly
authorAndre Przywara <andre.przywara@linaro.org>
Fri, 5 Jan 2018 17:57:32 +0000 (17:57 +0000)
committerStefano Stabellini <sstabellini@kernel.org>
Tue, 27 Mar 2018 19:44:06 +0000 (12:44 -0700)
The event channel IRQ has level triggered semantics, however the current
VGIC treats everything as edge triggered.
To correctly process those IRQs, we have to lower the (virtual) IRQ line
at some point in time, depending on whether the interrupt condition
still prevails.
Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
line match its status, and call this function upon every hypervisor
entry.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>
xen/arch/arm/domain.c
xen/arch/arm/traps.c
xen/include/asm-arm/event.h

index ff97f2bc76dff719a0804645fcb803820cb1eccb..9688e62f7804604e627333642168225c7342d49c 100644 (file)
@@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
     vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
 }
 
+void vcpu_update_evtchn_irq(struct vcpu *v)
+{
+    bool pending = vcpu_info(v, evtchn_upcall_pending);
+
+    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
+}
+
 /* The ARM spec declares that even if local irqs are masked in
  * the CPSR register, an irq should wake up a cpu from WFI anyway.
  * For this reason we need to check for irqs that need delivery,
index 26384466935a38a9d1f8faff674ee928867907f9..5c18e918b0e10df19969fecadb1bc74e6b517334 100644 (file)
@@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
          * trap and how it can be optimised.
          */
         vtimer_update_irqs(current);
+        vcpu_update_evtchn_irq(current);
 #endif
 
         vgic_sync_from_lrs(current);
index c7a415ef579627a019946f84be790d45bd1bd3b4..2f51864043727c40197f481a768d55e29d920f9d 100644 (file)
@@ -6,6 +6,7 @@
 
 void vcpu_kick(struct vcpu *v);
 void vcpu_mark_events_pending(struct vcpu *v);
+void vcpu_update_evtchn_irq(struct vcpu *v);
 void vcpu_block_unless_event_pending(struct vcpu *v);
 
 static inline int vcpu_event_delivery_is_enabled(struct vcpu *v)