diff mbox

[Xen-devel,v4,07/10] xen/arm: call gic_clear_lrs on entry to the hypervisor

Message ID 1395232325-19226-7-git-send-email-stefano.stabellini@eu.citrix.com
State New
Headers show

Commit Message

Stefano Stabellini March 19, 2014, 12:32 p.m. UTC
This change is needed by other patches later on. It is going to make
sure that the calculation in Xen of the highest priority interrupt
currently inflight is correct and accurate and not based on stale data.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 xen/arch/arm/gic.c        |   12 +++++-------
 xen/arch/arm/traps.c      |   10 ++++++++++
 xen/include/asm-arm/gic.h |    1 +
 3 files changed, 16 insertions(+), 7 deletions(-)

Comments

Julien Grall March 19, 2014, 1:56 p.m. UTC | #1
On 03/19/2014 12:32 PM, Stefano Stabellini wrote:
> This change is needed by other patches later on. It is going to make
> sure that the calculation in Xen of the highest priority interrupt
> currently inflight is correct and accurate and not based on stale data.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Julien Grall <julien.grall@linaro.org>
Ian Campbell March 21, 2014, 1:14 p.m. UTC | #2
On Wed, 2014-03-19 at 12:32 +0000, Stefano Stabellini wrote:

Can this not be folded back into the patch which added this function?

> This change is needed by other patches later on. It is going to make
> sure that the calculation in Xen of the highest priority interrupt
> currently inflight is correct and accurate and not based on stale data.

Hrm, can we not do this on demand just at the point where we are about
to make such a calculation? There are going to be lots of hypervisor
entries which don't want to do anything at all with interrupts, aren't
there?

Ian.
Stefano Stabellini March 21, 2014, 4:34 p.m. UTC | #3
On Fri, 21 Mar 2014, Ian Campbell wrote:
> On Wed, 2014-03-19 at 12:32 +0000, Stefano Stabellini wrote:
> 
> Can this not be folded back into the patch which added this function?

Yes, it can.


> > This change is needed by other patches later on. It is going to make
> > sure that the calculation in Xen of the highest priority interrupt
> > currently inflight is correct and accurate and not based on stale data.
> 
> Hrm, can we not do this on demand just at the point where we are about
> to make such a calculation? There are going to be lots of hypervisor
> entries which don't want to do anything at all with interrupts, aren't
> there?

The alternative would be calling gic_clear_lrs at the beginning of
gic_inject and gic_events_need_delivery, that is called by
local_events_need_delivery*.  It could be called multiple times before
returning to guest.

However gic_clear_lrs only iterates over the LRs in lr_mask, so even
calling it multiple times shouldn't cause more work, the only slow down
would be due to the spin_lock.
Ian Campbell March 21, 2014, 4:39 p.m. UTC | #4
On Fri, 2014-03-21 at 16:34 +0000, Stefano Stabellini wrote:
> On Fri, 21 Mar 2014, Ian Campbell wrote:
> > On Wed, 2014-03-19 at 12:32 +0000, Stefano Stabellini wrote:
> > 
> > Can this not be folded back into the patch which added this function?
> 
> Yes, it can.
> 
> 
> > > This change is needed by other patches later on. It is going to make
> > > sure that the calculation in Xen of the highest priority interrupt
> > > currently inflight is correct and accurate and not based on stale data.
> > 
> > Hrm, can we not do this on demand just at the point where we are about
> > to make such a calculation? There are going to be lots of hypervisor
> > entries which don't want to do anything at all with interrupts, aren't
> > there?
> 
> The alternative would be calling gic_clear_lrs at the beginning of
> gic_inject and gic_events_need_delivery, that is called by
> local_events_need_delivery*.  It could be called multiple times before
> returning to guest.

We could probably invent some sort of "once per h/v entry" construct,
but ick.

What I was actually thinking of though was to do it even further up --
e.g. in the function which makes the interrupt pending in the first
place. I suppose that is called too infrequently though in the absence
of maintenance interrupts.

> 
> However gic_clear_lrs only iterates over the LRs in lr_mask, so even
> calling it multiple times shouldn't cause more work, the only slow down
> would be due to the spin_lock.
Stefano Stabellini March 24, 2014, 12:24 p.m. UTC | #5
On Fri, 21 Mar 2014, Ian Campbell wrote:
> On Fri, 2014-03-21 at 16:34 +0000, Stefano Stabellini wrote:
> > On Fri, 21 Mar 2014, Ian Campbell wrote:
> > > On Wed, 2014-03-19 at 12:32 +0000, Stefano Stabellini wrote:
> > > 
> > > Can this not be folded back into the patch which added this function?
> > 
> > Yes, it can.
> > 
> > 
> > > > This change is needed by other patches later on. It is going to make
> > > > sure that the calculation in Xen of the highest priority interrupt
> > > > currently inflight is correct and accurate and not based on stale data.
> > > 
> > > Hrm, can we not do this on demand just at the point where we are about
> > > to make such a calculation? There are going to be lots of hypervisor
> > > entries which don't want to do anything at all with interrupts, aren't
> > > there?
> > 
> > The alternative would be calling gic_clear_lrs at the beginning of
> > gic_inject and gic_events_need_delivery, that is called by
> > local_events_need_delivery*.  It could be called multiple times before
> > returning to guest.
> 
> We could probably invent some sort of "once per h/v entry" construct,
> but ick.
> 
> What I was actually thinking of though was to do it even further up --
> e.g. in the function which makes the interrupt pending in the first
> place. I suppose that is called too infrequently though in the absence
> of maintenance interrupts.

Yes, that function would not be called often enough: in order to
calculate correctly if events need delivery, we need to know the current
value of GICV_PMR.Priority, that is aliased by GICH_VMCR and can be
changed by the guest without traps, and the current active highest
priority interrupt in the LRs.  As a consequence I think that
gic_events_need_delivery needs to be called at least once before
returning to guest.
diff mbox

Patch

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index a5a4da3..3f061cf 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -67,8 +67,6 @@  static DEFINE_PER_CPU(u8, gic_cpu_id);
 /* Maximum cpu interface per GIC */
 #define NR_GIC_CPU_IF 8
 
-static void gic_clear_lrs(struct vcpu *v);
-
 static unsigned int gic_cpu_mask(const cpumask_t *cpumask)
 {
     unsigned int cpu;
@@ -130,7 +128,6 @@  void gic_restore_state(struct vcpu *v)
     GICH[GICH_HCR] = GICH_HCR_EN;
     isb();
 
-    gic_clear_lrs(v);
     gic_restore_pending_irqs(v);
 }
 
@@ -701,14 +698,15 @@  out:
     return;
 }
 
-static void gic_clear_lrs(struct vcpu *v)
+void gic_clear_lrs(struct vcpu *v)
 {
     struct pending_irq *p;
     int i = 0, irq;
     uint32_t lr;
     bool_t inflight;
+    unsigned long flags;
 
-    ASSERT(!local_irq_is_enabled());
+    spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
     while ((i = find_next_bit((const long unsigned int *) &this_cpu(lr_mask),
                               nr_lrs, i)) < nr_lrs) {
@@ -744,6 +742,8 @@  static void gic_clear_lrs(struct vcpu *v)
 
         i++;
     }
+
+    spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
 }
 
 static void gic_restore_pending_irqs(struct vcpu *v)
@@ -786,8 +786,6 @@  int gic_events_need_delivery(void)
 
 void gic_inject(void)
 {
-    gic_clear_lrs(current);
-
     if ( vcpu_info(current, evtchn_upcall_pending) )
         vgic_vcpu_inject_irq(current, current->domain->arch.evtchn_irq);
 
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 21c7b26..dd936be 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -68,6 +68,7 @@  static int debug_stack_lines = 40;
 
 integer_param("debug_stack_lines", debug_stack_lines);
 
+static void enter_hypervisor_head(void);
 
 void __cpuinit init_traps(void)
 {
@@ -1543,6 +1544,8 @@  asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
 {
     union hsr hsr = { .bits = READ_SYSREG32(ESR_EL2) };
 
+    enter_hypervisor_head();
+
     switch (hsr.ec) {
     case HSR_EC_WFI_WFE:
         if ( !check_conditional_instr(regs, hsr) )
@@ -1620,11 +1623,13 @@  asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
 
 asmlinkage void do_trap_irq(struct cpu_user_regs *regs)
 {
+    enter_hypervisor_head();
     gic_interrupt(regs, 0);
 }
 
 asmlinkage void do_trap_fiq(struct cpu_user_regs *regs)
 {
+    enter_hypervisor_head();
     gic_interrupt(regs, 1);
 }
 
@@ -1642,6 +1647,11 @@  asmlinkage void leave_hypervisor_tail(void)
     }
 }
 
+static void enter_hypervisor_head(void)
+{
+    gic_clear_lrs(current);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 4834cd6..5a9dc77 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -220,6 +220,7 @@  extern unsigned int gic_number_lines(void);
 /* IRQ translation function for the device tree */
 int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
                   unsigned int *out_hwirq, unsigned int *out_type);
+void gic_clear_lrs(struct vcpu *v);
 
 #endif /* __ASSEMBLY__ */
 #endif