xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Fix multiple issues with the interrupts on ARM
@ 2013-06-24 23:04 Julien Grall
  2013-06-24 23:04 ` [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ Julien Grall
                   ` (5 more replies)
  0 siblings, 6 replies; 46+ messages in thread
From: Julien Grall @ 2013-06-24 23:04 UTC (permalink / raw)
  To: xen-devel; +Cc: Julien Grall, patches, ian.campbell, Stefano.Stabellini

Hello,

This patch series aims to fix different issues on Xen on ARM with the
arndale and the versatile express:
  - Handle correctly one shot IRQ (fixed by patch 3)
  - Make timers work with heavy load (fixed by patch 2)
  - Make ethernet card works on the TC2 (fixed by patch 5)

Some of these patches (2 and 5) are proof of concept. I would be happy if
someone find a better solution :).

Cheers,

Julien Grall (4):
  xen/arm: Physical IRQ is not always equal to virtual IRQ
  xen/arm: Don't reinject the IRQ if it's already in LRs
  xen/arm: Rename gic_irq_{startup,shutdown} to gic_irq_{mask,unmask}
  xen/arm: Only enable physical IRQs when the guest asks

Stefano Stabellini (1):
  xen/arm: Keep count of inflight interrupts

 xen/arch/arm/domain_build.c  |   14 +++++
 xen/arch/arm/gic.c           |  119 ++++++++++++++++++++++++++++++------------
 xen/arch/arm/vgic.c          |   11 ++--
 xen/include/asm-arm/domain.h |    2 +
 xen/include/asm-arm/gic.h    |    7 +++
 xen/include/asm-arm/irq.h    |    6 +++
 6 files changed, 122 insertions(+), 37 deletions(-)

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ
  2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
@ 2013-06-24 23:04 ` Julien Grall
  2013-06-25 13:16   ` Stefano Stabellini
  2013-06-24 23:04 ` [PATCH 2/5] xen/arm: Keep count of inflight interrupts Julien Grall
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-24 23:04 UTC (permalink / raw)
  To: xen-devel; +Cc: patches, ian.campbell, Julien Grall, Stefano.Stabellini

From: Julien Grall <julien.grall@linaro.org>

When Xen needs to EOI a physical IRQ, we must use the IRQ number
in irq_desc instead of the virtual IRQ.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
 xen/arch/arm/gic.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 177560e..0fee3f2 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -810,7 +810,7 @@ static void gic_irq_eoi(void *info)
 
 static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
 {
-    int i = 0, virq;
+    int i = 0, virq, pirq;
     uint32_t lr;
     struct vcpu *v = current;
     uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
@@ -846,6 +846,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
             /* Assume only one pcpu needs to EOI the irq */
             cpu = p->desc->arch.eoi_cpu;
             eoi = 1;
+            pirq = p->desc->irq;
         }
         list_del_init(&p->inflight);
         spin_unlock_irq(&v->arch.vgic.lock);
@@ -854,10 +855,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
             /* this is not racy because we can't receive another irq of the
              * same type until we EOI it.  */
             if ( cpu == smp_processor_id() )
-                gic_irq_eoi((void*)(uintptr_t)virq);
+                gic_irq_eoi((void*)(uintptr_t)pirq);
             else
                 on_selected_cpus(cpumask_of(cpu),
-                                 gic_irq_eoi, (void*)(uintptr_t)virq, 0);
+                                 gic_irq_eoi, (void*)(uintptr_t)pirq, 0);
         }
 
         i++;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
  2013-06-24 23:04 ` [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ Julien Grall
@ 2013-06-24 23:04 ` Julien Grall
  2013-06-25 16:12   ` Ian Campbell
  2013-06-24 23:04 ` [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs Julien Grall
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-24 23:04 UTC (permalink / raw)
  To: xen-devel
  Cc: patches, Stefano Stabellini, ian.campbell, Julien Grall,
	Stefano.Stabellini

From: Stefano Stabellini <stefano.stabellini@citrix.com>

For guest's timers (both virtual and physical), Xen will inject virtual
interrupt. Linux handles timer interrupt as:
  1) Receive the interrupt and ack it
  2) Handle the current event timer
  3) Set the next event timer
  4) EOI the interrupt

It's unlikely possible to reinject another interrupt before
the previous one is EOIed because the next deadline is shorter than the time
to execute code until EOI it.

Signed-off-by: Stefano Stabellini <stefano.stabellini@citrix.com>
Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
 xen/arch/arm/gic.c           |   35 +++++++++++++++++++++++------------
 xen/arch/arm/vgic.c          |    1 +
 xen/include/asm-arm/domain.h |    2 ++
 3 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 0fee3f2..21575df 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -817,7 +817,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
 
     while ((i = find_next_bit((const long unsigned int *) &eisr,
                               64, i)) < 64) {
-        struct pending_irq *p;
+        struct pending_irq *p, *n;
         int cpu, eoi;
 
         cpu = -1;
@@ -826,13 +826,32 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
         spin_lock_irq(&gic.lock);
         lr = GICH[GICH_LR + i];
         virq = lr & GICH_LR_VIRTUAL_MASK;
+
+        p = irq_to_pending(v, virq);
+        if ( p->desc != NULL ) {
+            p->desc->status &= ~IRQ_INPROGRESS;
+            /* Assume only one pcpu needs to EOI the irq */
+            cpu = p->desc->arch.eoi_cpu;
+            eoi = 1;
+            pirq = p->desc->irq;
+        }
+        if ( !atomic_dec_and_test(&p->inflight_cnt) )
+        {
+            /* Physical IRQ can't be reinject */
+            WARN_ON(p->desc != NULL);
+            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
+            spin_unlock_irq(&gic.lock);
+            i++;
+            continue;
+        }
+
         GICH[GICH_LR + i] = 0;
         clear_bit(i, &this_cpu(lr_mask));
 
         if ( !list_empty(&v->arch.vgic.lr_pending) ) {
-            p = list_entry(v->arch.vgic.lr_pending.next, typeof(*p), lr_queue);
-            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
-            list_del_init(&p->lr_queue);
+            n = list_entry(v->arch.vgic.lr_pending.next, typeof(*n), lr_queue);
+            gic_set_lr(i, n->irq, GICH_LR_PENDING, n->priority);
+            list_del_init(&n->lr_queue);
             set_bit(i, &this_cpu(lr_mask));
         } else {
             gic_inject_irq_stop();
@@ -840,14 +859,6 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
         spin_unlock_irq(&gic.lock);
 
         spin_lock_irq(&v->arch.vgic.lock);
-        p = irq_to_pending(v, virq);
-        if ( p->desc != NULL ) {
-            p->desc->status &= ~IRQ_INPROGRESS;
-            /* Assume only one pcpu needs to EOI the irq */
-            cpu = p->desc->arch.eoi_cpu;
-            eoi = 1;
-            pirq = p->desc->irq;
-        }
         list_del_init(&p->inflight);
         spin_unlock_irq(&v->arch.vgic.lock);
 
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 7eaccb7..2d91dce 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -672,6 +672,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
 
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
+    atomic_inc(&n->inflight_cnt);
     /* vcpu offline or irq already pending */
     if (test_bit(_VPF_down, &v->pause_flags) || !list_empty(&n->inflight))
     {
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 339b6e6..fa0b776 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -8,6 +8,7 @@
 #include <asm/p2m.h>
 #include <asm/vfp.h>
 #include <public/hvm/params.h>
+#include <asm/atomic.h>
 
 /* Represents state corresponding to a block of 32 interrupts */
 struct vgic_irq_rank {
@@ -21,6 +22,7 @@ struct vgic_irq_rank {
 struct pending_irq
 {
     int irq;
+    atomic_t inflight_cnt;
     struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */
     uint8_t priority;
     /* inflight is used to append instances of pending_irq to
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
  2013-06-24 23:04 ` [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ Julien Grall
  2013-06-24 23:04 ` [PATCH 2/5] xen/arm: Keep count of inflight interrupts Julien Grall
@ 2013-06-24 23:04 ` Julien Grall
  2013-06-25 13:24   ` Stefano Stabellini
  2013-06-24 23:04 ` [PATCH 4/5] xen/arm: Rename gic_irq_{startup, shutdown} to gic_irq_{mask, unmask} Julien Grall
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-24 23:04 UTC (permalink / raw)
  To: xen-devel; +Cc: patches, ian.campbell, Julien Grall, Stefano.Stabellini

From: Julien Grall <julien.grall@linaro.org>

When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
  - Disable the IRQ
  - Call the interrupt handler
  - Conditionnally enable the IRQ
  - EOI the IRQ

When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
EOI it twice if it's a physical IRQ.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
 xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
 xen/arch/arm/vgic.c       |    3 ++-
 xen/include/asm-arm/gic.h |    3 +++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 21575df..bf05716 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
     return rc;
 }
 
+/* Check if an IRQ was already injected to the current VCPU */
+bool_t gic_irq_injected(unsigned int irq)
+{
+    bool_t found = 0;
+    int i = 0;
+    unsigned int virq;
+
+    spin_lock_irq(&gic.lock);
+
+    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
+                               nr_lrs, i)) < nr_lrs )
+    {
+        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
+
+        if ( virq == irq )
+        {
+            found = 1;
+            break;
+        }
+        i++;
+    }
+
+    spin_unlock_irq(&gic.lock);
+
+    return found;
+}
+
 static inline void gic_set_lr(int lr, unsigned int virtual_irq,
         unsigned int state, unsigned int priority)
 {
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 2d91dce..cea9233 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -369,8 +369,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
     while ( (i = find_next_bit((const long unsigned int *) &r, 32, i)) < 32 ) {
         irq = i + (32 * n);
         p = irq_to_pending(v, irq);
-        if ( !list_empty(&p->inflight) )
+        if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
             gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
+
         i++;
     }
 }
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 513c1fc..f9e9ef1 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -197,6 +197,9 @@ extern unsigned int gic_number_lines(void);
 int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
                   unsigned int *out_hwirq, unsigned int *out_type);
 
+/* Check if an IRQ was already injected to the current VCPU */
+bool_t gic_irq_injected(unsigned int irq);
+
 #endif /* __ASSEMBLY__ */
 #endif
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH 4/5] xen/arm: Rename gic_irq_{startup, shutdown} to gic_irq_{mask, unmask}
  2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
                   ` (2 preceding siblings ...)
  2013-06-24 23:04 ` [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs Julien Grall
@ 2013-06-24 23:04 ` Julien Grall
  2013-06-24 23:04 ` [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks Julien Grall
  2013-07-31 13:08 ` [PATCH 0/5] Fix multiple issues with the interrupts on ARM Andrii Anisov
  5 siblings, 0 replies; 46+ messages in thread
From: Julien Grall @ 2013-06-24 23:04 UTC (permalink / raw)
  To: xen-devel; +Cc: Julien Grall, patches, ian.campbell, Stefano.Stabellini

Also implement enable/disable as mask/unmask irq.

Signed-off-by: Julien Grall <julien.grall@citrix.com>
---
 xen/arch/arm/gic.c |   27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index bf05716..b16ba8c 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -103,7 +103,7 @@ void gic_restore_state(struct vcpu *v)
     gic_restore_pending_irqs(v);
 }
 
-static unsigned int gic_irq_startup(struct irq_desc *desc)
+static void gic_irq_unmask(struct irq_desc *desc)
 {
     uint32_t enabler;
     int irq = desc->irq;
@@ -111,11 +111,9 @@ static unsigned int gic_irq_startup(struct irq_desc *desc)
     /* Enable routing */
     enabler = GICD[GICD_ISENABLER + irq / 32];
     GICD[GICD_ISENABLER + irq / 32] = enabler | (1u << (irq % 32));
-
-    return 0;
 }
 
-static void gic_irq_shutdown(struct irq_desc *desc)
+static void gic_irq_mask(struct irq_desc *desc)
 {
     uint32_t enabler;
     int irq = desc->irq;
@@ -125,14 +123,11 @@ static void gic_irq_shutdown(struct irq_desc *desc)
     GICD[GICD_ICENABLER + irq / 32] = enabler | (1u << (irq % 32));
 }
 
-static void gic_irq_enable(struct irq_desc *desc)
-{
-
-}
-
-static void gic_irq_disable(struct irq_desc *desc)
+static unsigned int gic_irq_startup(struct irq_desc *desc)
 {
+    gic_irq_unmask(desc);
 
+    return 0;
 }
 
 static void gic_irq_ack(struct irq_desc *desc)
@@ -166,9 +161,9 @@ static void gic_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
 static hw_irq_controller gic_host_irq_type = {
     .typename = "gic",
     .startup = gic_irq_startup,
-    .shutdown = gic_irq_shutdown,
-    .enable = gic_irq_enable,
-    .disable = gic_irq_disable,
+    .shutdown = gic_irq_mask,
+    .enable = gic_irq_unmask,
+    .disable = gic_irq_mask,
     .ack = gic_irq_ack,
     .end = gic_host_irq_end,
     .set_affinity = gic_irq_set_affinity,
@@ -176,9 +171,9 @@ static hw_irq_controller gic_host_irq_type = {
 static hw_irq_controller gic_guest_irq_type = {
     .typename = "gic",
     .startup = gic_irq_startup,
-    .shutdown = gic_irq_shutdown,
-    .enable = gic_irq_enable,
-    .disable = gic_irq_disable,
+    .shutdown = gic_irq_mask,
+    .enable = gic_irq_unmask,
+    .disable = gic_irq_mask,
     .ack = gic_irq_ack,
     .end = gic_guest_irq_end,
     .set_affinity = gic_irq_set_affinity,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
                   ` (3 preceding siblings ...)
  2013-06-24 23:04 ` [PATCH 4/5] xen/arm: Rename gic_irq_{startup, shutdown} to gic_irq_{mask, unmask} Julien Grall
@ 2013-06-24 23:04 ` Julien Grall
  2013-06-25 16:19   ` Stefano Stabellini
  2013-06-25 16:28   ` Ian Campbell
  2013-07-31 13:08 ` [PATCH 0/5] Fix multiple issues with the interrupts on ARM Andrii Anisov
  5 siblings, 2 replies; 46+ messages in thread
From: Julien Grall @ 2013-06-24 23:04 UTC (permalink / raw)
  To: xen-devel; +Cc: Julien Grall, patches, ian.campbell, Stefano.Stabellini

If the guest VCPU receives an interrupts when it's disabled, it will throw
away the IRQ with EOIed it. This is result to lost IRQ forever.
Directly EOIed the interrupt doesn't help because the IRQ could be fired
again and result to an infinited loop.

It happens during dom0 boot on the versatile express TC2 with the ethernet
card.

Let the interrupt disabled when Xen setups the route and enable it when Linux
asks to enable it.

Signed-off-by: Julien Grall <julien.grall@citrix.com>
---
 xen/arch/arm/domain_build.c |   14 ++++++++++++++
 xen/arch/arm/gic.c          |   25 +++++++++++++++++++++++--
 xen/arch/arm/vgic.c         |    7 +++----
 xen/include/asm-arm/gic.h   |    4 ++++
 xen/include/asm-arm/irq.h   |    6 ++++++
 5 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index f5befbd..0470a2d 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
         }
 
         DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
+
+        /*
+         * Only map SGI interrupt in the guest as XEN won't handle
+         * it correctly.
+         * TODO: Fix it
+         */
+        if ( !irq_is_sgi(irq.irq) )
+        {
+            printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has "
+                   "XEN doesn't handle properly non-SGI interrupt\n",
+                   i, dt_node_full_name(dev));
+            continue;
+        }
+
         /* Don't check return because the IRQ can be use by multiple device */
         gic_route_irq_to_guest(d, &irq, dt_node_name(dev));
     }
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index b16ba8c..e7d082a 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = {
     .set_affinity = gic_irq_set_affinity,
 };
 
+void gic_irq_enable(struct irq_desc *desc)
+{
+    spin_lock_irq(&desc->lock);
+    spin_lock(&gic.lock);
+
+    desc->handler->enable(desc);
+
+    spin_unlock(&gic.lock);
+    spin_unlock_irq(&desc->lock);
+}
+
 /* needs to be called with gic.lock held */
 static void gic_set_irq_properties(unsigned int irq, bool_t level,
         unsigned int cpu_mask, unsigned int priority)
@@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq,
     desc->status &= ~IRQ_DISABLED;
     dsb();
 
-    desc->handler->startup(desc);
-
     return 0;
 }
 
@@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
 
     rc = __setup_irq(desc, irq->irq, new);
 
+    desc->handler->startup(desc);
+
     spin_unlock_irqrestore(&desc->lock, flags);
 
     return rc;
@@ -711,6 +722,7 @@ void gic_inject(void)
         gic_inject_irq_start();
 }
 
+/* TODO: Handle properly non SGI-interrupt */
 int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
                            const char * devname)
 {
@@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
     unsigned long flags;
     int retval;
     bool_t level;
+    struct pending_irq *p;
+    /* XXX: handler other VCPU than 0 */
+    struct vcpu *v = d->vcpu[0];
 
     action = xmalloc(struct irqaction);
     if (!action)
         return -ENOMEM;
 
+    /* XXX: Here we assume a 1:1 interrupt mapping between the host and dom0 */
+    BUG_ON(irq->irq >= (d->arch.vgic.nr_lines + NR_LOCAL_IRQS));
+    p = irq_to_pending(v, irq->irq);
+
     action->dev_id = d;
     action->name = devname;
     action->free_on_release = 1;
@@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
         goto out;
     }
 
+    p->desc = desc;
+
 out:
     spin_unlock(&gic.lock);
     spin_unlock_irqrestore(&desc->lock, flags);
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index cea9233..4f3d816 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -372,6 +372,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
         if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
             gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
 
+        if ( p->desc != NULL )
+            gic_irq_enable(p->desc);
+
         i++;
     }
 }
@@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
 
     n->irq = irq;
     n->priority = priority;
-    if (!virtual)
-        n->desc = irq_to_desc(irq);
-    else
-        n->desc = NULL;
 
     /* the irq is enabled */
     if ( rank->ienable & (1 << (irq % 32)) )
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index f9e9ef1..f7f3c1e 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -134,6 +134,7 @@
 
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
+#include <xen/irq.h>
 
 extern int domain_vgic_init(struct domain *d);
 extern void domain_vgic_free(struct domain *d);
@@ -154,6 +155,9 @@ extern void gic_inject(void);
 extern void gic_clear_pending_irqs(struct vcpu *v);
 extern int gic_events_need_delivery(void);
 
+/* Helper to enable an IRQ and take all the needed locks */
+extern void gic_irq_enable(struct irq_desc *desc);
+
 extern void __cpuinit init_maintenance_interrupt(void);
 extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq,
         unsigned int state, unsigned int priority);
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 80ff68d..346dc1d 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -46,6 +46,12 @@ int __init request_dt_irq(const struct dt_irq *irq,
                           void *dev_id);
 int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new);
 
+#define FIRST_SGI_IRQ   32
+static inline bool_t irq_is_sgi(unsigned int irq)
+{
+    return (irq >= FIRST_SGI_IRQ);
+}
+
 #endif /* _ASM_HW_IRQ_H */
 /*
  * Local variables:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ
  2013-06-24 23:04 ` [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ Julien Grall
@ 2013-06-25 13:16   ` Stefano Stabellini
  2013-06-25 15:21     ` Julien Grall
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 13:16 UTC (permalink / raw)
  To: Julien Grall; +Cc: Stefano.Stabellini, ian.campbell, patches, xen-devel

On Tue, 25 Jun 2013, Julien Grall wrote:
> From: Julien Grall <julien.grall@linaro.org>
> 
> When Xen needs to EOI a physical IRQ, we must use the IRQ number
> in irq_desc instead of the virtual IRQ.
> 
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> ---
>  xen/arch/arm/gic.c |    7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 177560e..0fee3f2 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -810,7 +810,7 @@ static void gic_irq_eoi(void *info)
>  
>  static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
>  {
> -    int i = 0, virq;
> +    int i = 0, virq, pirq;
>      uint32_t lr;
>      struct vcpu *v = current;
>      uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
> @@ -846,6 +846,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>              /* Assume only one pcpu needs to EOI the irq */
>              cpu = p->desc->arch.eoi_cpu;
>              eoi = 1;
> +            pirq = p->desc->irq;
>          }
>          list_del_init(&p->inflight);
>          spin_unlock_irq(&v->arch.vgic.lock);
> @@ -854,10 +855,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>              /* this is not racy because we can't receive another irq of the
>               * same type until we EOI it.  */
>              if ( cpu == smp_processor_id() )
> -                gic_irq_eoi((void*)(uintptr_t)virq);
> +                gic_irq_eoi((void*)(uintptr_t)pirq);
>              else
>                  on_selected_cpus(cpumask_of(cpu),
> -                                 gic_irq_eoi, (void*)(uintptr_t)virq, 0);
> +                                 gic_irq_eoi, (void*)(uintptr_t)pirq, 0);
>          }

I think that virq and pirq are guaranteed to always be the same, at
least at the moment. Look at vgic_vcpu_inject_irq: it takes just one irq
parameter, that is both the physical and the virtual irq number.
Unless we change the vgic_vcpu_inject_irq interface to allow virq !=
pirq, I don't think this patch makes much sense.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-24 23:04 ` [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs Julien Grall
@ 2013-06-25 13:24   ` Stefano Stabellini
  2013-06-25 13:55     ` Julien Grall
  2013-06-25 16:14     ` Ian Campbell
  0 siblings, 2 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 13:24 UTC (permalink / raw)
  To: Julien Grall; +Cc: Stefano.Stabellini, ian.campbell, patches, xen-devel

On Tue, 25 Jun 2013, Julien Grall wrote:
> From: Julien Grall <julien.grall@linaro.org>
> 
> When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
>   - Disable the IRQ
>   - Call the interrupt handler
>   - Conditionnally enable the IRQ
>   - EOI the IRQ
> 
> When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
> still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
> EOI it twice if it's a physical IRQ.
> 
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> ---
>  xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
>  xen/arch/arm/vgic.c       |    3 ++-
>  xen/include/asm-arm/gic.h |    3 +++
>  3 files changed, 32 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 21575df..bf05716 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>      return rc;
>  }
>  
> +/* Check if an IRQ was already injected to the current VCPU */
> +bool_t gic_irq_injected(unsigned int irq)

Can you rename it to something more specific, like gic_irq_inlr?

> +{
> +    bool_t found = 0;
> +    int i = 0;
> +    unsigned int virq;
> +
> +    spin_lock_irq(&gic.lock);
> +
> +    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
> +                               nr_lrs, i)) < nr_lrs )
> +    {
> +        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
> +
> +        if ( virq == irq )
> +        {
> +            found = 1;
> +            break;
> +        }
> +        i++;
> +    }

Instead of reading back all the GICH_LR registers, can't just just read
the ones that have a corresponding bit set in lr_mask?

Also you should be able to avoid having to read the GICH_LR registers by
simply checking if the irq is in the lr_queue list: if an irq is in
inflight but not in lr_queue, it means that it is in one of the LRs.



> +    spin_unlock_irq(&gic.lock);
> +
> +    return found;
> +}
> +
>  static inline void gic_set_lr(int lr, unsigned int virtual_irq,
>          unsigned int state, unsigned int priority)
>  {
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 2d91dce..cea9233 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -369,8 +369,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>      while ( (i = find_next_bit((const long unsigned int *) &r, 32, i)) < 32 ) {
>          irq = i + (32 * n);
>          p = irq_to_pending(v, irq);
> -        if ( !list_empty(&p->inflight) )
> +        if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
>              gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
> +
>          i++;
>      }
>  }
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 513c1fc..f9e9ef1 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -197,6 +197,9 @@ extern unsigned int gic_number_lines(void);
>  int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
>                    unsigned int *out_hwirq, unsigned int *out_type);
>  
> +/* Check if an IRQ was already injected to the current VCPU */
> +bool_t gic_irq_injected(unsigned int irq);
> +
>  #endif /* __ASSEMBLY__ */
>  #endif
>  
> -- 
> 1.7.10.4
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 13:24   ` Stefano Stabellini
@ 2013-06-25 13:55     ` Julien Grall
  2013-06-25 16:36       ` Stefano Stabellini
  2013-06-25 16:14     ` Ian Campbell
  1 sibling, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-25 13:55 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: patches, ian.campbell, xen-devel

On 06/25/2013 02:24 PM, Stefano Stabellini wrote:

> On Tue, 25 Jun 2013, Julien Grall wrote:
>> From: Julien Grall <julien.grall@linaro.org>
>>
>> When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
>>   - Disable the IRQ
>>   - Call the interrupt handler
>>   - Conditionnally enable the IRQ
>>   - EOI the IRQ
>>
>> When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
>> still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
>> EOI it twice if it's a physical IRQ.
>>
>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>> ---
>>  xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
>>  xen/arch/arm/vgic.c       |    3 ++-
>>  xen/include/asm-arm/gic.h |    3 +++
>>  3 files changed, 32 insertions(+), 1 deletion(-)
>>
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index 21575df..bf05716 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>>      return rc;
>>  }
>>  
>> +/* Check if an IRQ was already injected to the current VCPU */
>> +bool_t gic_irq_injected(unsigned int irq)
> 
> Can you rename it to something more specific, like gic_irq_inlr?
> 
>> +{
>> +    bool_t found = 0;
>> +    int i = 0;
>> +    unsigned int virq;
>> +
>> +    spin_lock_irq(&gic.lock);
>> +
>> +    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
>> +                               nr_lrs, i)) < nr_lrs )
>> +    {
>> +        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
>> +
>> +        if ( virq == irq )
>> +        {
>> +            found = 1;
>> +            break;
>> +        }
>> +        i++;
>> +    }
> 
> Instead of reading back all the GICH_LR registers, can't just just read
> the ones that have a corresponding bit set in lr_mask?

It's already the case, I use find_next_bit to find the next used LRs.

> Also you should be able to avoid having to read the GICH_LR registers by
> simply checking if the irq is in the lr_queue list: if an irq is in
> inflight but not in lr_queue, it means that it is in one of the LRs.


No. When a disabled IRQ is injected to the VCPU, Xen puts it in inflight
but not in lr_queue. We don't have a way to know whether the IRQ is
really in LRs or not.

-- 
Julien

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ
  2013-06-25 13:16   ` Stefano Stabellini
@ 2013-06-25 15:21     ` Julien Grall
  2013-06-25 16:06       ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-25 15:21 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: patches, ian.campbell, xen-devel

On 06/25/2013 02:16 PM, Stefano Stabellini wrote:

> On Tue, 25 Jun 2013, Julien Grall wrote:
>> From: Julien Grall <julien.grall@linaro.org>
>>
>> When Xen needs to EOI a physical IRQ, we must use the IRQ number
>> in irq_desc instead of the virtual IRQ.
>>
>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>> ---
>>  xen/arch/arm/gic.c |    7 ++++---
>>  1 file changed, 4 insertions(+), 3 deletions(-)
>>
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index 177560e..0fee3f2 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -810,7 +810,7 @@ static void gic_irq_eoi(void *info)
>>  
>>  static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
>>  {
>> -    int i = 0, virq;
>> +    int i = 0, virq, pirq;
>>      uint32_t lr;
>>      struct vcpu *v = current;
>>      uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
>> @@ -846,6 +846,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>>              /* Assume only one pcpu needs to EOI the irq */
>>              cpu = p->desc->arch.eoi_cpu;
>>              eoi = 1;
>> +            pirq = p->desc->irq;
>>          }
>>          list_del_init(&p->inflight);
>>          spin_unlock_irq(&v->arch.vgic.lock);
>> @@ -854,10 +855,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>>              /* this is not racy because we can't receive another irq of the
>>               * same type until we EOI it.  */
>>              if ( cpu == smp_processor_id() )
>> -                gic_irq_eoi((void*)(uintptr_t)virq);
>> +                gic_irq_eoi((void*)(uintptr_t)pirq);
>>              else
>>                  on_selected_cpus(cpumask_of(cpu),
>> -                                 gic_irq_eoi, (void*)(uintptr_t)virq, 0);
>> +                                 gic_irq_eoi, (void*)(uintptr_t)pirq, 0);
>>          }
> 
> I think that virq and pirq are guaranteed to always be the same, at
> least at the moment. Look at vgic_vcpu_inject_irq: it takes just one irq
> parameter, that is both the physical and the virtual irq number.

> Unless we change the vgic_vcpu_inject_irq interface to allow virq !=
> pirq, I don't think this patch makes much sense.


Right. I wrote this patch because it easier to forget to modify some
part when non-1:1 IRQ mappings will be created :).

-- 
Julien

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ
  2013-06-25 15:21     ` Julien Grall
@ 2013-06-25 16:06       ` Ian Campbell
  0 siblings, 0 replies; 46+ messages in thread
From: Ian Campbell @ 2013-06-25 16:06 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, patches, Stefano Stabellini

On Tue, 2013-06-25 at 16:21 +0100, Julien Grall wrote:
> On 06/25/2013 02:16 PM, Stefano Stabellini wrote:
> 
> > On Tue, 25 Jun 2013, Julien Grall wrote:
> >> From: Julien Grall <julien.grall@linaro.org>
> >>
> >> When Xen needs to EOI a physical IRQ, we must use the IRQ number
> >> in irq_desc instead of the virtual IRQ.
> >>
> >> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >> ---
> >>  xen/arch/arm/gic.c |    7 ++++---
> >>  1 file changed, 4 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >> index 177560e..0fee3f2 100644
> >> --- a/xen/arch/arm/gic.c
> >> +++ b/xen/arch/arm/gic.c
> >> @@ -810,7 +810,7 @@ static void gic_irq_eoi(void *info)
> >>  
> >>  static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
> >>  {
> >> -    int i = 0, virq;
> >> +    int i = 0, virq, pirq;
> >>      uint32_t lr;
> >>      struct vcpu *v = current;
> >>      uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
> >> @@ -846,6 +846,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >>              /* Assume only one pcpu needs to EOI the irq */
> >>              cpu = p->desc->arch.eoi_cpu;
> >>              eoi = 1;
> >> +            pirq = p->desc->irq;
> >>          }
> >>          list_del_init(&p->inflight);
> >>          spin_unlock_irq(&v->arch.vgic.lock);
> >> @@ -854,10 +855,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >>              /* this is not racy because we can't receive another irq of the
> >>               * same type until we EOI it.  */
> >>              if ( cpu == smp_processor_id() )
> >> -                gic_irq_eoi((void*)(uintptr_t)virq);
> >> +                gic_irq_eoi((void*)(uintptr_t)pirq);
> >>              else
> >>                  on_selected_cpus(cpumask_of(cpu),
> >> -                                 gic_irq_eoi, (void*)(uintptr_t)virq, 0);
> >> +                                 gic_irq_eoi, (void*)(uintptr_t)pirq, 0);
> >>          }
> > 
> > I think that virq and pirq are guaranteed to always be the same, at
> > least at the moment. Look at vgic_vcpu_inject_irq: it takes just one irq
> > parameter, that is both the physical and the virtual irq number.
> 
> > Unless we change the vgic_vcpu_inject_irq interface to allow virq !=
> > pirq, I don't think this patch makes much sense.

But what is the downside?

> Right. I wrote this patch because it easier to forget to modify some
> part when non-1:1 IRQ mappings will be created :).

I'd be tempted to make this change on that basis, it is correct both
before and after any change to vgic_vcpu_inject_irq and doesn't appear
to be expensive or anything. Not to mention that it is semantically
correct.


Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-24 23:04 ` [PATCH 2/5] xen/arm: Keep count of inflight interrupts Julien Grall
@ 2013-06-25 16:12   ` Ian Campbell
  2013-06-25 16:58     ` Stefano Stabellini
  0 siblings, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-25 16:12 UTC (permalink / raw)
  To: Julien Grall; +Cc: Stefano.Stabellini, Stefano Stabellini, patches, xen-devel

On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> From: Stefano Stabellini <stefano.stabellini@citrix.com>
> 
> For guest's timers (both virtual and physical), Xen will inject virtual
> interrupt. Linux handles timer interrupt as:

We should be wary of developing things based on the way which Linux
happens to do things. On x86 we have several time modes, which can be
selected based upon guest behaviour (described in
docs/man/xl.cfg.pod.5). Do we need to do something similar here?

>   1) Receive the interrupt and ack it
>   2) Handle the current event timer
>   3) Set the next event timer
>   4) EOI the interrupt
> 
> It's unlikely possible to reinject another interrupt before

I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
not sure if that is what you meant.

> the previous one is EOIed because the next deadline is shorter than the time
> to execute code until EOI it.

If we get into this situation once is there any danger that we will get
into it repeatedly and overflow the count?

Overall I'm not convinced this is the right approach to get the
behaviour we want. Isn't this interrupt level triggered, with the level
being determined by a comparison of two registers? IOW can't we
determine whether to retrigger the interrupt or not by examining the
state of our emulated versions of those registers? A generic mechanism
to callback into the appropriate emulator on EOI plus a little bit of
logic in the vtimer code is all it ought to take.

> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@citrix.com>
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> ---
>  xen/arch/arm/gic.c           |   35 +++++++++++++++++++++++------------
>  xen/arch/arm/vgic.c          |    1 +
>  xen/include/asm-arm/domain.h |    2 ++
>  3 files changed, 26 insertions(+), 12 deletions(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 0fee3f2..21575df 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -817,7 +817,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>  
>      while ((i = find_next_bit((const long unsigned int *) &eisr,
>                                64, i)) < 64) {
> -        struct pending_irq *p;
> +        struct pending_irq *p, *n;
>          int cpu, eoi;
>  
>          cpu = -1;
> @@ -826,13 +826,32 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>          spin_lock_irq(&gic.lock);
>          lr = GICH[GICH_LR + i];
>          virq = lr & GICH_LR_VIRTUAL_MASK;
> +
> +        p = irq_to_pending(v, virq);
> +        if ( p->desc != NULL ) {
> +            p->desc->status &= ~IRQ_INPROGRESS;
> +            /* Assume only one pcpu needs to EOI the irq */
> +            cpu = p->desc->arch.eoi_cpu;
> +            eoi = 1;
> +            pirq = p->desc->irq;
> +        }
> +        if ( !atomic_dec_and_test(&p->inflight_cnt) )
> +        {
> +            /* Physical IRQ can't be reinject */
> +            WARN_ON(p->desc != NULL);
> +            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> +            spin_unlock_irq(&gic.lock);
> +            i++;
> +            continue;
> +        }
> +
>          GICH[GICH_LR + i] = 0;
>          clear_bit(i, &this_cpu(lr_mask));
>  
>          if ( !list_empty(&v->arch.vgic.lr_pending) ) {
> -            p = list_entry(v->arch.vgic.lr_pending.next, typeof(*p), lr_queue);
> -            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> -            list_del_init(&p->lr_queue);
> +            n = list_entry(v->arch.vgic.lr_pending.next, typeof(*n), lr_queue);
> +            gic_set_lr(i, n->irq, GICH_LR_PENDING, n->priority);
> +            list_del_init(&n->lr_queue);
>              set_bit(i, &this_cpu(lr_mask));
>          } else {
>              gic_inject_irq_stop();
> @@ -840,14 +859,6 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>          spin_unlock_irq(&gic.lock);
>  
>          spin_lock_irq(&v->arch.vgic.lock);
> -        p = irq_to_pending(v, virq);
> -        if ( p->desc != NULL ) {
> -            p->desc->status &= ~IRQ_INPROGRESS;
> -            /* Assume only one pcpu needs to EOI the irq */
> -            cpu = p->desc->arch.eoi_cpu;
> -            eoi = 1;
> -            pirq = p->desc->irq;
> -        }
>          list_del_init(&p->inflight);
>          spin_unlock_irq(&v->arch.vgic.lock);
>  
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 7eaccb7..2d91dce 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -672,6 +672,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
>  
>      spin_lock_irqsave(&v->arch.vgic.lock, flags);
>  
> +    atomic_inc(&n->inflight_cnt);
>      /* vcpu offline or irq already pending */
>      if (test_bit(_VPF_down, &v->pause_flags) || !list_empty(&n->inflight))
>      {
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 339b6e6..fa0b776 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -8,6 +8,7 @@
>  #include <asm/p2m.h>
>  #include <asm/vfp.h>
>  #include <public/hvm/params.h>
> +#include <asm/atomic.h>
>  
>  /* Represents state corresponding to a block of 32 interrupts */
>  struct vgic_irq_rank {
> @@ -21,6 +22,7 @@ struct vgic_irq_rank {
>  struct pending_irq
>  {
>      int irq;
> +    atomic_t inflight_cnt;
>      struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */
>      uint8_t priority;
>      /* inflight is used to append instances of pending_irq to

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 13:24   ` Stefano Stabellini
  2013-06-25 13:55     ` Julien Grall
@ 2013-06-25 16:14     ` Ian Campbell
  1 sibling, 0 replies; 46+ messages in thread
From: Ian Campbell @ 2013-06-25 16:14 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, xen-devel, patches

On Tue, 2013-06-25 at 14:24 +0100, Stefano Stabellini wrote:
> On Tue, 25 Jun 2013, Julien Grall wrote:
> > From: Julien Grall <julien.grall@linaro.org>
> > 
> > When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
> >   - Disable the IRQ
> >   - Call the interrupt handler
> >   - Conditionnally enable the IRQ
> >   - EOI the IRQ
> > 
> > When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
> > still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
> > EOI it twice if it's a physical IRQ.
> > 
> > Signed-off-by: Julien Grall <julien.grall@linaro.org>
> > ---
> >  xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
> >  xen/arch/arm/vgic.c       |    3 ++-
> >  xen/include/asm-arm/gic.h |    3 +++
> >  3 files changed, 32 insertions(+), 1 deletion(-)
> > 
> > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> > index 21575df..bf05716 100644
> > --- a/xen/arch/arm/gic.c
> > +++ b/xen/arch/arm/gic.c
> > @@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
> >      return rc;
> >  }
> >  
> > +/* Check if an IRQ was already injected to the current VCPU */
> > +bool_t gic_irq_injected(unsigned int irq)
> 
> Can you rename it to something more specific, like gic_irq_inlr?
> 
> > +{
> > +    bool_t found = 0;
> > +    int i = 0;
> > +    unsigned int virq;
> > +
> > +    spin_lock_irq(&gic.lock);
> > +
> > +    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
> > +                               nr_lrs, i)) < nr_lrs )
> > +    {
> > +        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
> > +
> > +        if ( virq == irq )
> > +        {
> > +            found = 1;
> > +            break;
> > +        }
> > +        i++;
> > +    }
> 
> Instead of reading back all the GICH_LR registers, can't just just read
> the ones that have a corresponding bit set in lr_mask?
> 
> Also you should be able to avoid having to read the GICH_LR registers by
> simply checking if the irq is in the lr_queue list: if an irq is in
> inflight but not in lr_queue, it means that it is in one of the LRs.

This sounds roughly equivalent to what I was about to suggest which was
a bool in the irq descriptor.

In any case we should certainly try and avoid walking all the LRs via
some means.

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-24 23:04 ` [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks Julien Grall
@ 2013-06-25 16:19   ` Stefano Stabellini
  2013-06-25 16:55     ` Julien Grall
  2013-12-02 17:26     ` Ian Campbell
  2013-06-25 16:28   ` Ian Campbell
  1 sibling, 2 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 16:19 UTC (permalink / raw)
  To: Julien Grall
  Cc: Julien Grall, Stefano.Stabellini, ian.campbell, patches,
	xen-devel

On Tue, 25 Jun 2013, Julien Grall wrote:
> If the guest VCPU receives an interrupts when it's disabled, it will throw
                                   ^interrupt

> away the IRQ with EOIed it.

What does this mean? I cannot parse the sentence.


> This is result to lost IRQ forever.
> Directly EOIed the interrupt doesn't help because the IRQ could be fired
> again and result to an infinited loop.
> 
> It happens during dom0 boot on the versatile express TC2 with the ethernet
> card.
> 
> Let the interrupt disabled when Xen setups the route and enable it when Linux
> asks to enable it.

Is the problem that Xen keeps the interrupt enabled even when Linux
disables it at the gic level? Is this what this patch is trying to
address?


> Signed-off-by: Julien Grall <julien.grall@citrix.com>
> ---
>  xen/arch/arm/domain_build.c |   14 ++++++++++++++
>  xen/arch/arm/gic.c          |   25 +++++++++++++++++++++++--
>  xen/arch/arm/vgic.c         |    7 +++----
>  xen/include/asm-arm/gic.h   |    4 ++++
>  xen/include/asm-arm/irq.h   |    6 ++++++
>  5 files changed, 50 insertions(+), 6 deletions(-)
> 
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index f5befbd..0470a2d 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
>          }
>  
>          DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
> +
> +        /*
> +         * Only map SGI interrupt in the guest as XEN won't handle
> +         * it correctly.
> +         * TODO: Fix it
> +         */
> +        if ( !irq_is_sgi(irq.irq) )
> +        {
> +            printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has "
> +                   "XEN doesn't handle properly non-SGI interrupt\n",
> +                   i, dt_node_full_name(dev));

do you mean SPI?


> +            continue;
> +        }
> +
>          /* Don't check return because the IRQ can be use by multiple device */
>          gic_route_irq_to_guest(d, &irq, dt_node_name(dev));
>      }
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index b16ba8c..e7d082a 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = {
>      .set_affinity = gic_irq_set_affinity,
>  };
>  
> +void gic_irq_enable(struct irq_desc *desc)
> +{
> +    spin_lock_irq(&desc->lock);
> +    spin_lock(&gic.lock);
> +
> +    desc->handler->enable(desc);
> +
> +    spin_unlock(&gic.lock);
> +    spin_unlock_irq(&desc->lock);
> +}

This function looks a bit too similar to gic_irq_mask and friends,
except that it takes two locks.

To make that obvious it's probably better to call it gic_irq_enable_safe
or gic_irq_enable_locked.


>  /* needs to be called with gic.lock held */
>  static void gic_set_irq_properties(unsigned int irq, bool_t level,
>          unsigned int cpu_mask, unsigned int priority)
> @@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq,
>      desc->status &= ~IRQ_DISABLED;
>      dsb();
>  
> -    desc->handler->startup(desc);
> -
>      return 0;
>  }
>  
> @@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>  
>      rc = __setup_irq(desc, irq->irq, new);
>  
> +    desc->handler->startup(desc);
> +
>      spin_unlock_irqrestore(&desc->lock, flags);
>  
>      return rc;

This two changes make it so guest irqs are not enabled by default, good.


> @@ -711,6 +722,7 @@ void gic_inject(void)
>          gic_inject_irq_start();
>  }
>  
> +/* TODO: Handle properly non SGI-interrupt */
>  int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>                             const char * devname)
>  {
> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>      unsigned long flags;
>      int retval;
>      bool_t level;
> +    struct pending_irq *p;
> +    /* XXX: handler other VCPU than 0 */
> +    struct vcpu *v = d->vcpu[0];
>  
>      action = xmalloc(struct irqaction);
>      if (!action)
>          return -ENOMEM;
>  
> +    /* XXX: Here we assume a 1:1 interrupt mapping between the host and dom0 */
> +    BUG_ON(irq->irq >= (d->arch.vgic.nr_lines + NR_LOCAL_IRQS));
> +    p = irq_to_pending(v, irq->irq);
> +
>      action->dev_id = d;
>      action->name = devname;
>      action->free_on_release = 1;
> @@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>          goto out;
>      }
>  
> +    p->desc = desc;
> +
>  out:
>      spin_unlock(&gic.lock);
>      spin_unlock_irqrestore(&desc->lock, flags);
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index cea9233..4f3d816 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -372,6 +372,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>          if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
>              gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
>  
> +        if ( p->desc != NULL )
> +            gic_irq_enable(p->desc);
> +
>          i++;
>      }
>  }

Should we add a gic_irq_disable call when the guest disables irqs?


> @@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
>  
>      n->irq = irq;
>      n->priority = priority;
> -    if (!virtual)
> -        n->desc = irq_to_desc(irq);
> -    else
> -        n->desc = NULL;
>  
>      /* the irq is enabled */
>      if ( rank->ienable & (1 << (irq % 32)) )

I don't quite understand why are you changing where the "desc"
assignement is done.
If it is a cleanup you shouldn't mix it with a patch like this that is
supposed to fix a specific issue. Otherwise please explain why you need
this change.


> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index f9e9ef1..f7f3c1e 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -134,6 +134,7 @@
>  
>  #ifndef __ASSEMBLY__
>  #include <xen/device_tree.h>
> +#include <xen/irq.h>
>  
>  extern int domain_vgic_init(struct domain *d);
>  extern void domain_vgic_free(struct domain *d);
> @@ -154,6 +155,9 @@ extern void gic_inject(void);
>  extern void gic_clear_pending_irqs(struct vcpu *v);
>  extern int gic_events_need_delivery(void);
>  
> +/* Helper to enable an IRQ and take all the needed locks */
> +extern void gic_irq_enable(struct irq_desc *desc);
> +
>  extern void __cpuinit init_maintenance_interrupt(void);
>  extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq,
>          unsigned int state, unsigned int priority);
> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
> index 80ff68d..346dc1d 100644
> --- a/xen/include/asm-arm/irq.h
> +++ b/xen/include/asm-arm/irq.h
> @@ -46,6 +46,12 @@ int __init request_dt_irq(const struct dt_irq *irq,
>                            void *dev_id);
>  int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new);
>  
> +#define FIRST_SGI_IRQ   32
> +static inline bool_t irq_is_sgi(unsigned int irq)
> +{
> +    return (irq >= FIRST_SGI_IRQ);
> +}

Aren't SGIs supposed to be between 0 and 15? Aren't you talking about
SPIs here?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-24 23:04 ` [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks Julien Grall
  2013-06-25 16:19   ` Stefano Stabellini
@ 2013-06-25 16:28   ` Ian Campbell
  2013-06-25 17:38     ` Julien Grall
  1 sibling, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-25 16:28 UTC (permalink / raw)
  To: Julien Grall; +Cc: Julien Grall, Stefano.Stabellini, patches, xen-devel

On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> If the guest VCPU receives an interrupts when it's disabled, it will throw
> away the IRQ with EOIed it.

Did you mean "without EOIing it" or perhaps "having EOIed it"?

>  This is result to lost IRQ forever.

"This results in losing the IRQ forever".

> Directly EOIed the interrupt doesn't help because the IRQ could be fired

EOIing in this context.

> again and result to an infinited loop.

                        infinite

> It happens during dom0 boot on the versatile express TC2 with the ethernet
> card.
> 
> Let the interrupt disabled when Xen setups the route and enable it when Linux

  "Lets ... when Xen sets up the route..."

> asks to enable it.
> 
> Signed-off-by: Julien Grall <julien.grall@citrix.com>
> ---
>  xen/arch/arm/domain_build.c |   14 ++++++++++++++
>  xen/arch/arm/gic.c          |   25 +++++++++++++++++++++++--
>  xen/arch/arm/vgic.c         |    7 +++----
>  xen/include/asm-arm/gic.h   |    4 ++++
>  xen/include/asm-arm/irq.h   |    6 ++++++
>  5 files changed, 50 insertions(+), 6 deletions(-)
> 
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index f5befbd..0470a2d 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
>          }
>  
>          DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
> +
> +        /*
> +         * Only map SGI interrupt in the guest as XEN won't handle
> +         * it correctly.
> +         * TODO: Fix it
> +         */
> +        if ( !irq_is_sgi(irq.irq) )
> +        {
> +            printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has "

s/has/as/ I think.

Did you really mean SGI here? I'd have thought from the context that you
would mean SPIs. SGIs aren't anything to do with any real devices almost
by definition -- if you saw on in the device tree I'd be very surprised!

> +                   "XEN doesn't handle properly non-SGI interrupt\n",
> +                   i, dt_node_full_name(dev));
> +            continue;
> +        }
> +
>          /* Don't check return because the IRQ can be use by multiple device */
>          gic_route_irq_to_guest(d, &irq, dt_node_name(dev));
>      }
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index b16ba8c..e7d082a 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = {
>      .set_affinity = gic_irq_set_affinity,
>  };
>  
> +void gic_irq_enable(struct irq_desc *desc)
> +{
> +    spin_lock_irq(&desc->lock);
> +    spin_lock(&gic.lock);
> +
> +    desc->handler->enable(desc);
> +
> +    spin_unlock(&gic.lock);
> +    spin_unlock_irq(&desc->lock);
> +}
> +
>  /* needs to be called with gic.lock held */
>  static void gic_set_irq_properties(unsigned int irq, bool_t level,
>          unsigned int cpu_mask, unsigned int priority)
> @@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq,
>      desc->status &= ~IRQ_DISABLED;
>      dsb();
>  
> -    desc->handler->startup(desc);
> -
>      return 0;
>  }
>  
> @@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>  
>      rc = __setup_irq(desc, irq->irq, new);
>  
> +    desc->handler->startup(desc);
> +
>      spin_unlock_irqrestore(&desc->lock, flags);
>  
>      return rc;
> @@ -711,6 +722,7 @@ void gic_inject(void)
>          gic_inject_irq_start();
>  }
>  
> +/* TODO: Handle properly non SGI-interrupt */
>  int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>                             const char * devname)
>  {
> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>      unsigned long flags;
>      int retval;
>      bool_t level;
> +    struct pending_irq *p;
> +    /* XXX: handler other VCPU than 0 */

That should be something like "XXX: handle VCPUs other than 0".

This only matters if we can route SGIs or PPIs to the guest though I
think, since they are the only banked interrupts? For SPIs we actually
want to actively avoid doing this multiple times, don't we?

For the banked interrupts I think we just need a loop here, or for
p->desc to not be part of the pending_irq struct but actually part of
some separate per-domain datastructure, since it would be very weird to
have a domain where the PPIs differed between CPUs. (I'm not sure if
that is allowed by the hardware, I bet it is, but it would be a
pathological case IMHO...).

I think a perdomain irq_desc * array is probably the right answer,
unless someone can convincingly argue that PPI routing differing between
VCPUs in a guest is a useful thing...

> +    struct vcpu *v = d->vcpu[0];
>  
>      action = xmalloc(struct irqaction);
>      if (!action)
>          return -ENOMEM;
>  
> +    /* XXX: Here we assume a 1:1 interrupt mapping between the host and dom0 */
> +    BUG_ON(irq->irq >= (d->arch.vgic.nr_lines + NR_LOCAL_IRQS));
> +    p = irq_to_pending(v, irq->irq);
> +
>      action->dev_id = d;
>      action->name = devname;
>      action->free_on_release = 1;
> @@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>          goto out;
>      }
>  
> +    p->desc = desc;
> +
>  out:
>      spin_unlock(&gic.lock);
>      spin_unlock_irqrestore(&desc->lock, flags);
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index cea9233..4f3d816 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -372,6 +372,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>          if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
>              gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
>  
> +        if ( p->desc != NULL )
> +            gic_irq_enable(p->desc);
> +
>          i++;
>      }
>  }
> @@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
>  
>      n->irq = irq;
>      n->priority = priority;
> -    if (!virtual)
> -        n->desc = irq_to_desc(irq);
> -    else
> -        n->desc = NULL;
>  
>      /* the irq is enabled */
>      if ( rank->ienable & (1 << (irq % 32)) )
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index f9e9ef1..f7f3c1e 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -134,6 +134,7 @@
>  
>  #ifndef __ASSEMBLY__
>  #include <xen/device_tree.h>
> +#include <xen/irq.h>
>  
>  extern int domain_vgic_init(struct domain *d);
>  extern void domain_vgic_free(struct domain *d);
> @@ -154,6 +155,9 @@ extern void gic_inject(void);
>  extern void gic_clear_pending_irqs(struct vcpu *v);
>  extern int gic_events_need_delivery(void);
>  
> +/* Helper to enable an IRQ and take all the needed locks */
> +extern void gic_irq_enable(struct irq_desc *desc);
> +
>  extern void __cpuinit init_maintenance_interrupt(void);
>  extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq,
>          unsigned int state, unsigned int priority);
> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
> index 80ff68d..346dc1d 100644
> --- a/xen/include/asm-arm/irq.h
> +++ b/xen/include/asm-arm/irq.h
> @@ -46,6 +46,12 @@ int __init request_dt_irq(const struct dt_irq *irq,
>                            void *dev_id);
>  int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new);
>  
> +#define FIRST_SGI_IRQ   32
> +static inline bool_t irq_is_sgi(unsigned int irq)
> +{
> +    return (irq >= FIRST_SGI_IRQ);
> +}
> +
>  #endif /* _ASM_HW_IRQ_H */
>  /*
>   * Local variables:

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 13:55     ` Julien Grall
@ 2013-06-25 16:36       ` Stefano Stabellini
  2013-06-25 16:46         ` Ian Campbell
  2013-06-25 16:48         ` Julien Grall
  0 siblings, 2 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 16:36 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, ian.campbell, patches, Stefano Stabellini

On Tue, 25 Jun 2013, Julien Grall wrote:
> On 06/25/2013 02:24 PM, Stefano Stabellini wrote:
> 
> > On Tue, 25 Jun 2013, Julien Grall wrote:
> >> From: Julien Grall <julien.grall@linaro.org>
> >>
> >> When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
> >>   - Disable the IRQ
> >>   - Call the interrupt handler
> >>   - Conditionnally enable the IRQ
> >>   - EOI the IRQ
> >>
> >> When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
> >> still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
> >> EOI it twice if it's a physical IRQ.
> >>
> >> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >> ---
> >>  xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
> >>  xen/arch/arm/vgic.c       |    3 ++-
> >>  xen/include/asm-arm/gic.h |    3 +++
> >>  3 files changed, 32 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >> index 21575df..bf05716 100644
> >> --- a/xen/arch/arm/gic.c
> >> +++ b/xen/arch/arm/gic.c
> >> @@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
> >>      return rc;
> >>  }
> >>  
> >> +/* Check if an IRQ was already injected to the current VCPU */
> >> +bool_t gic_irq_injected(unsigned int irq)
> > 
> > Can you rename it to something more specific, like gic_irq_inlr?
> > 
> >> +{
> >> +    bool_t found = 0;
> >> +    int i = 0;
> >> +    unsigned int virq;
> >> +
> >> +    spin_lock_irq(&gic.lock);
> >> +
> >> +    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
> >> +                               nr_lrs, i)) < nr_lrs )
> >> +    {
> >> +        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
> >> +
> >> +        if ( virq == irq )
> >> +        {
> >> +            found = 1;
> >> +            break;
> >> +        }
> >> +        i++;
> >> +    }
> > 
> > Instead of reading back all the GICH_LR registers, can't just just read
> > the ones that have a corresponding bit set in lr_mask?
> 
> It's already the case, I use find_next_bit to find the next used LRs.
> 
> > Also you should be able to avoid having to read the GICH_LR registers by
> > simply checking if the irq is in the lr_queue list: if an irq is in
> > inflight but not in lr_queue, it means that it is in one of the LRs.
> 
> 
> No. When a disabled IRQ is injected to the VCPU, Xen puts it in inflight
> but not in lr_queue. We don't have a way to know whether the IRQ is
> really in LRs or not.

I think it's time we introduce a "status" member in struct irq_desc, so
that we are not dependent on the information in the GICH_LR registers or
the queue a pending_irq has been added to.
I would implement it as a bitfield:

int status;
#define GIC_IRQ_ENABLED  (1<<0)
#define GIC_IRQ_INFLIGHT (1<<1)
#define GIC_IRQ_INLR     (1<<2)

This way you should just go through the inflight queue and check whether
status & GIC_IRQ_INLR.

At the moment we just want to represent this basic state machine:

irq guest asserted -> inflight -> injected (inlr) -> unasserted (maintenance interrupt)

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 16:36       ` Stefano Stabellini
@ 2013-06-25 16:46         ` Ian Campbell
  2013-06-25 17:05           ` Stefano Stabellini
  2013-06-25 16:48         ` Julien Grall
  1 sibling, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-25 16:46 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, patches, xen-devel

On Tue, 2013-06-25 at 17:36 +0100, Stefano Stabellini wrote:
> I think it's time we introduce a "status" member in struct irq_desc, so
> that we are not dependent on the information in the GICH_LR registers or
> the queue a pending_irq has been added to.

Yes please, I find this one of the hardest things to keep straight in my
head (not helped by my inability to remember which of pending and
inflight is which...)

> I would implement it as a bitfield:
> 
> int status;
> #define GIC_IRQ_ENABLED  (1<<0)
> #define GIC_IRQ_INFLIGHT (1<<1)
> #define GIC_IRQ_INLR     (1<<2)
> 
> This way you should just go through the inflight queue and check whether
> status & GIC_IRQ_INLR.

Since some of this stuff happens in interrupt context you probably want
test_bit/set_bit et al rather than regular boolean logic, don't you?

> At the moment we just want to represent this basic state machine:
> 
> irq guest asserted -> inflight -> injected (inlr) -> unasserted (maintenance interrupt)

Can we model the states after the active/pending states which the gic
has? It might make a bunch of stuff clearer?

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 16:36       ` Stefano Stabellini
  2013-06-25 16:46         ` Ian Campbell
@ 2013-06-25 16:48         ` Julien Grall
  2013-06-25 16:59           ` Stefano Stabellini
  1 sibling, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-25 16:48 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: patches, ian.campbell, xen-devel

On 06/25/2013 05:36 PM, Stefano Stabellini wrote:

> On Tue, 25 Jun 2013, Julien Grall wrote:
>> On 06/25/2013 02:24 PM, Stefano Stabellini wrote:
>>
>>> On Tue, 25 Jun 2013, Julien Grall wrote:
>>>> From: Julien Grall <julien.grall@linaro.org>
>>>>
>>>> When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
>>>>   - Disable the IRQ
>>>>   - Call the interrupt handler
>>>>   - Conditionnally enable the IRQ
>>>>   - EOI the IRQ
>>>>
>>>> When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
>>>> still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
>>>> EOI it twice if it's a physical IRQ.
>>>>
>>>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>>>> ---
>>>>  xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
>>>>  xen/arch/arm/vgic.c       |    3 ++-
>>>>  xen/include/asm-arm/gic.h |    3 +++
>>>>  3 files changed, 32 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>>>> index 21575df..bf05716 100644
>>>> --- a/xen/arch/arm/gic.c
>>>> +++ b/xen/arch/arm/gic.c
>>>> @@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>>>>      return rc;
>>>>  }
>>>>  
>>>> +/* Check if an IRQ was already injected to the current VCPU */
>>>> +bool_t gic_irq_injected(unsigned int irq)
>>>
>>> Can you rename it to something more specific, like gic_irq_inlr?
>>>
>>>> +{
>>>> +    bool_t found = 0;
>>>> +    int i = 0;
>>>> +    unsigned int virq;
>>>> +
>>>> +    spin_lock_irq(&gic.lock);
>>>> +
>>>> +    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
>>>> +                               nr_lrs, i)) < nr_lrs )
>>>> +    {
>>>> +        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
>>>> +
>>>> +        if ( virq == irq )
>>>> +        {
>>>> +            found = 1;
>>>> +            break;
>>>> +        }
>>>> +        i++;
>>>> +    }
>>>
>>> Instead of reading back all the GICH_LR registers, can't just just read
>>> the ones that have a corresponding bit set in lr_mask?
>>
>> It's already the case, I use find_next_bit to find the next used LRs.
>>
>>> Also you should be able to avoid having to read the GICH_LR registers by
>>> simply checking if the irq is in the lr_queue list: if an irq is in
>>> inflight but not in lr_queue, it means that it is in one of the LRs.
>>
>>
>> No. When a disabled IRQ is injected to the VCPU, Xen puts it in inflight
>> but not in lr_queue. We don't have a way to know whether the IRQ is
>> really in LRs or not.
> 
> I think it's time we introduce a "status" member in struct irq_desc, so

Do you mean struct irq_pending?

> that we are not dependent on the information in the GICH_LR registers or
> the queue a pending_irq has been added to.
> I would implement it as a bitfield:
> 
> int status;
> #define GIC_IRQ_ENABLED  (1<<0)
> #define GIC_IRQ_INFLIGHT (1<<1)
> #define GIC_IRQ_INLR     (1<<2)
> 
> This way you should just go through the inflight queue and check whether
> status & GIC_IRQ_INLR.
> 
> At the moment we just want to represent this basic state machine:
> 
> irq guest asserted -> inflight -> injected (inlr) -> unasserted (maintenance interrupt)


Sounds good to me. I will try to implement this approach.

Moreover, it will fix another issue with this patch. I have just noticed
that it's possible to reinject an IRQ on different vCPU even if it's
injected on another vCPU.

-- 
Julien

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-25 16:19   ` Stefano Stabellini
@ 2013-06-25 16:55     ` Julien Grall
  2013-06-25 17:07       ` Stefano Stabellini
  2013-12-02 17:26     ` Ian Campbell
  1 sibling, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-25 16:55 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, patches, ian.campbell, xen-devel

On 06/25/2013 05:19 PM, Stefano Stabellini wrote:

> On Tue, 25 Jun 2013, Julien Grall wrote:
>> If the guest VCPU receives an interrupts when it's disabled, it will throw
>                                    ^interrupt
> 
>> away the IRQ with EOIed it.
> 
> What does this mean? I cannot parse the sentence.

"it will throw away the IRQ without EOIing".

> 
>> This is result to lost IRQ forever.
>> Directly EOIed the interrupt doesn't help because the IRQ could be fired
>> again and result to an infinited loop.
>>
>> It happens during dom0 boot on the versatile express TC2 with the ethernet
>> card.
>>
>> Let the interrupt disabled when Xen setups the route and enable it when Linux
>> asks to enable it.
> 
> Is the problem that Xen keeps the interrupt enabled even when Linux
> disables it at the gic level? Is this what this patch is trying to
> address?

This patch only delays the physical IRQ activation until Linux will
enable it. This patch avoids to lose IRQ when a VCPU is disabled.

I tried to also disable the IRQ when Linux asks to disable it but the
versatile express platform hang.

> 
>> Signed-off-by: Julien Grall <julien.grall@citrix.com>
>> ---
>>  xen/arch/arm/domain_build.c |   14 ++++++++++++++
>>  xen/arch/arm/gic.c          |   25 +++++++++++++++++++++++--
>>  xen/arch/arm/vgic.c         |    7 +++----
>>  xen/include/asm-arm/gic.h   |    4 ++++
>>  xen/include/asm-arm/irq.h   |    6 ++++++
>>  5 files changed, 50 insertions(+), 6 deletions(-)
>>
>> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
>> index f5befbd..0470a2d 100644
>> --- a/xen/arch/arm/domain_build.c
>> +++ b/xen/arch/arm/domain_build.c
>> @@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
>>          }
>>  
>>          DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
>> +
>> +        /*
>> +         * Only map SGI interrupt in the guest as XEN won't handle
>> +         * it correctly.
>> +         * TODO: Fix it
>> +         */
>> +        if ( !irq_is_sgi(irq.irq) )
>> +        {
>> +            printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has "
>> +                   "XEN doesn't handle properly non-SGI interrupt\n",
>> +                   i, dt_node_full_name(dev));
> 
> do you mean SPI?
> 
> 
>> +            continue;
>> +        }
>> +
>>          /* Don't check return because the IRQ can be use by multiple device */
>>          gic_route_irq_to_guest(d, &irq, dt_node_name(dev));
>>      }
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index b16ba8c..e7d082a 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = {
>>      .set_affinity = gic_irq_set_affinity,
>>  };
>>  
>> +void gic_irq_enable(struct irq_desc *desc)
>> +{
>> +    spin_lock_irq(&desc->lock);
>> +    spin_lock(&gic.lock);
>> +
>> +    desc->handler->enable(desc);
>> +
>> +    spin_unlock(&gic.lock);
>> +    spin_unlock_irq(&desc->lock);
>> +}
> 
> This function looks a bit too similar to gic_irq_mask and friends,
> except that it takes two locks.
> 
> To make that obvious it's probably better to call it gic_irq_enable_safe
> or gic_irq_enable_locked.
> 
> 
>>  /* needs to be called with gic.lock held */
>>  static void gic_set_irq_properties(unsigned int irq, bool_t level,
>>          unsigned int cpu_mask, unsigned int priority)
>> @@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq,
>>      desc->status &= ~IRQ_DISABLED;
>>      dsb();
>>  
>> -    desc->handler->startup(desc);
>> -
>>      return 0;
>>  }
>>  
>> @@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>>  
>>      rc = __setup_irq(desc, irq->irq, new);
>>  
>> +    desc->handler->startup(desc);
>> +
>>      spin_unlock_irqrestore(&desc->lock, flags);
>>  
>>      return rc;
> 
> This two changes make it so guest irqs are not enabled by default, good.
> 
> 
>> @@ -711,6 +722,7 @@ void gic_inject(void)
>>          gic_inject_irq_start();
>>  }
>>  
>> +/* TODO: Handle properly non SGI-interrupt */
>>  int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>                             const char * devname)
>>  {
>> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>      unsigned long flags;
>>      int retval;
>>      bool_t level;
>> +    struct pending_irq *p;
>> +    /* XXX: handler other VCPU than 0 */
>> +    struct vcpu *v = d->vcpu[0];
>>  
>>      action = xmalloc(struct irqaction);
>>      if (!action)
>>          return -ENOMEM;
>>  
>> +    /* XXX: Here we assume a 1:1 interrupt mapping between the host and dom0 */
>> +    BUG_ON(irq->irq >= (d->arch.vgic.nr_lines + NR_LOCAL_IRQS));
>> +    p = irq_to_pending(v, irq->irq);
>> +
>>      action->dev_id = d;
>>      action->name = devname;
>>      action->free_on_release = 1;
>> @@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>          goto out;
>>      }
>>  
>> +    p->desc = desc;
>> +
>>  out:
>>      spin_unlock(&gic.lock);
>>      spin_unlock_irqrestore(&desc->lock, flags);
>> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
>> index cea9233..4f3d816 100644
>> --- a/xen/arch/arm/vgic.c
>> +++ b/xen/arch/arm/vgic.c
>> @@ -372,6 +372,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>>          if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
>>              gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
>>  
>> +        if ( p->desc != NULL )
>> +            gic_irq_enable(p->desc);
>> +
>>          i++;
>>      }
>>  }
> 
> Should we add a gic_irq_disable call when the guest disables irqs?
> 
> 
>> @@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
>>  
>>      n->irq = irq;
>>      n->priority = priority;
>> -    if (!virtual)
>> -        n->desc = irq_to_desc(irq);
>> -    else
>> -        n->desc = NULL;
>>  
>>      /* the irq is enabled */
>>      if ( rank->ienable & (1 << (irq % 32)) )
> 
> I don't quite understand why are you changing where the "desc"
> assignement is done.
> If it is a cleanup you shouldn't mix it with a patch like this that is
> supposed to fix a specific issue. Otherwise please explain why you need
> this change.
> 
> 
>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>> index f9e9ef1..f7f3c1e 100644
>> --- a/xen/include/asm-arm/gic.h
>> +++ b/xen/include/asm-arm/gic.h
>> @@ -134,6 +134,7 @@
>>  
>>  #ifndef __ASSEMBLY__
>>  #include <xen/device_tree.h>
>> +#include <xen/irq.h>
>>  
>>  extern int domain_vgic_init(struct domain *d);
>>  extern void domain_vgic_free(struct domain *d);
>> @@ -154,6 +155,9 @@ extern void gic_inject(void);
>>  extern void gic_clear_pending_irqs(struct vcpu *v);
>>  extern int gic_events_need_delivery(void);
>>  
>> +/* Helper to enable an IRQ and take all the needed locks */
>> +extern void gic_irq_enable(struct irq_desc *desc);
>> +
>>  extern void __cpuinit init_maintenance_interrupt(void);
>>  extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq,
>>          unsigned int state, unsigned int priority);
>> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
>> index 80ff68d..346dc1d 100644
>> --- a/xen/include/asm-arm/irq.h
>> +++ b/xen/include/asm-arm/irq.h
>> @@ -46,6 +46,12 @@ int __init request_dt_irq(const struct dt_irq *irq,
>>                            void *dev_id);
>>  int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new);
>>  
>> +#define FIRST_SGI_IRQ   32
>> +static inline bool_t irq_is_sgi(unsigned int irq)
>> +{
>> +    return (irq >= FIRST_SGI_IRQ);
>> +}
> 
> Aren't SGIs supposed to be between 0 and 15? Aren't you talking about
> SPIs here?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-25 16:12   ` Ian Campbell
@ 2013-06-25 16:58     ` Stefano Stabellini
  2013-06-25 17:46       ` Julien Grall
  2013-06-26 10:58       ` Ian Campbell
  0 siblings, 2 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 16:58 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Julien Grall, Stefano Stabellini, patches, Stefano.Stabellini,
	xen-devel

On Tue, 25 Jun 2013, Ian Campbell wrote:
> On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > 
> > For guest's timers (both virtual and physical), Xen will inject virtual
> > interrupt. Linux handles timer interrupt as:
> 
> We should be wary of developing things based on the way which Linux
> happens to do things. On x86 we have several time modes, which can be
> selected based upon guest behaviour (described in
> docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> 
> >   1) Receive the interrupt and ack it
> >   2) Handle the current event timer
> >   3) Set the next event timer
> >   4) EOI the interrupt
> > 
> > It's unlikely possible to reinject another interrupt before
> 
> I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> not sure if that is what you meant.
> 
> > the previous one is EOIed because the next deadline is shorter than the time
> > to execute code until EOI it.
> 
> If we get into this situation once is there any danger that we will get
> into it repeatedly and overflow the count?
> 
> Overall I'm not convinced this is the right approach to get the
> behaviour we want. Isn't this interrupt level triggered, with the level
> being determined by a comparison of two registers? IOW can't we
> determine whether to retrigger the interrupt or not by examining the
> state of our emulated versions of those registers? A generic mechanism
> to callback into the appropriate emulator on EOI plus a little bit of
> logic in the vtimer code is all it ought to take.

AFAICT this what could happen:

- vtimer fires
- xen mask the vtimer
- xen adds the vtimer to the LR for the guest
- xen EOIs the vtimer
- the guest receive the vtimer interrupt
- the guest set the next deadline in the past
- the guest enables the vtimer
## an unexpected vtimer interrupt is received by Xen but the current
## one is still being serviced 
- the guest eoi the vtimer

as a result the guest looses an interrupt.
Julien, is that correct?

If that is the case, this can only happen once, right?  In that case
rather than an atomic_t we could just have a bit in the status field I
proposed before. It should be enough for us to keep track of the case
when the irq is supposed to stay high even after the guest EOIs it. (Of
course that means that we need to re-inject it into the guest).


> > Signed-off-by: Stefano Stabellini <stefano.stabellini@citrix.com>
> > Signed-off-by: Julien Grall <julien.grall@linaro.org>
> > ---
> >  xen/arch/arm/gic.c           |   35 +++++++++++++++++++++++------------
> >  xen/arch/arm/vgic.c          |    1 +
> >  xen/include/asm-arm/domain.h |    2 ++
> >  3 files changed, 26 insertions(+), 12 deletions(-)
> > 
> > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> > index 0fee3f2..21575df 100644
> > --- a/xen/arch/arm/gic.c
> > +++ b/xen/arch/arm/gic.c
> > @@ -817,7 +817,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >  
> >      while ((i = find_next_bit((const long unsigned int *) &eisr,
> >                                64, i)) < 64) {
> > -        struct pending_irq *p;
> > +        struct pending_irq *p, *n;
> >          int cpu, eoi;
> >  
> >          cpu = -1;
> > @@ -826,13 +826,32 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >          spin_lock_irq(&gic.lock);
> >          lr = GICH[GICH_LR + i];
> >          virq = lr & GICH_LR_VIRTUAL_MASK;
> > +
> > +        p = irq_to_pending(v, virq);
> > +        if ( p->desc != NULL ) {
> > +            p->desc->status &= ~IRQ_INPROGRESS;

Now that I am thinking about this, shouldn't this be protected by taking
the desc->lock?

> > +            /* Assume only one pcpu needs to EOI the irq */
> > +            cpu = p->desc->arch.eoi_cpu;
> > +            eoi = 1;
> > +            pirq = p->desc->irq;
> > +        }
> > +        if ( !atomic_dec_and_test(&p->inflight_cnt) )
> > +        {
> > +            /* Physical IRQ can't be reinject */
> > +            WARN_ON(p->desc != NULL);
> > +            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> > +            spin_unlock_irq(&gic.lock);
> > +            i++;
> > +            continue;
> > +        }
> > +
> >          GICH[GICH_LR + i] = 0;
> >          clear_bit(i, &this_cpu(lr_mask));
> >  
> >          if ( !list_empty(&v->arch.vgic.lr_pending) ) {
> > -            p = list_entry(v->arch.vgic.lr_pending.next, typeof(*p), lr_queue);
> > -            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> > -            list_del_init(&p->lr_queue);
> > +            n = list_entry(v->arch.vgic.lr_pending.next, typeof(*n), lr_queue);
> > +            gic_set_lr(i, n->irq, GICH_LR_PENDING, n->priority);
> > +            list_del_init(&n->lr_queue);
> >              set_bit(i, &this_cpu(lr_mask));
> >          } else {
> >              gic_inject_irq_stop();
> > @@ -840,14 +859,6 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >          spin_unlock_irq(&gic.lock);
> >  
> >          spin_lock_irq(&v->arch.vgic.lock);
> > -        p = irq_to_pending(v, virq);
> > -        if ( p->desc != NULL ) {
> > -            p->desc->status &= ~IRQ_INPROGRESS;
> > -            /* Assume only one pcpu needs to EOI the irq */
> > -            cpu = p->desc->arch.eoi_cpu;
> > -            eoi = 1;
> > -            pirq = p->desc->irq;
> > -        }
> >          list_del_init(&p->inflight);
> >          spin_unlock_irq(&v->arch.vgic.lock);
> >  

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 16:48         ` Julien Grall
@ 2013-06-25 16:59           ` Stefano Stabellini
  0 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 16:59 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, ian.campbell, patches, Stefano Stabellini

On Tue, 25 Jun 2013, Julien Grall wrote:
> On 06/25/2013 05:36 PM, Stefano Stabellini wrote:
> 
> > On Tue, 25 Jun 2013, Julien Grall wrote:
> >> On 06/25/2013 02:24 PM, Stefano Stabellini wrote:
> >>
> >>> On Tue, 25 Jun 2013, Julien Grall wrote:
> >>>> From: Julien Grall <julien.grall@linaro.org>
> >>>>
> >>>> When an IRQ, marked as IRQS_ONESHOT, is injected Linux will:
> >>>>   - Disable the IRQ
> >>>>   - Call the interrupt handler
> >>>>   - Conditionnally enable the IRQ
> >>>>   - EOI the IRQ
> >>>>
> >>>> When Linux will re-enable the IRQ, Xen will inject again the IRQ because it's
> >>>> still inflight. Therefore, LRs will contains duplicated IRQs and Xen will
> >>>> EOI it twice if it's a physical IRQ.
> >>>>
> >>>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >>>> ---
> >>>>  xen/arch/arm/gic.c        |   27 +++++++++++++++++++++++++++
> >>>>  xen/arch/arm/vgic.c       |    3 ++-
> >>>>  xen/include/asm-arm/gic.h |    3 +++
> >>>>  3 files changed, 32 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >>>> index 21575df..bf05716 100644
> >>>> --- a/xen/arch/arm/gic.c
> >>>> +++ b/xen/arch/arm/gic.c
> >>>> @@ -570,6 +570,33 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
> >>>>      return rc;
> >>>>  }
> >>>>  
> >>>> +/* Check if an IRQ was already injected to the current VCPU */
> >>>> +bool_t gic_irq_injected(unsigned int irq)
> >>>
> >>> Can you rename it to something more specific, like gic_irq_inlr?
> >>>
> >>>> +{
> >>>> +    bool_t found = 0;
> >>>> +    int i = 0;
> >>>> +    unsigned int virq;
> >>>> +
> >>>> +    spin_lock_irq(&gic.lock);
> >>>> +
> >>>> +    while ( (i = find_next_bit((unsigned long *)&this_cpu(lr_mask),
> >>>> +                               nr_lrs, i)) < nr_lrs )
> >>>> +    {
> >>>> +        virq = GICH[GICH_LR + i] & GICH_LR_VIRTUAL_MASK;
> >>>> +
> >>>> +        if ( virq == irq )
> >>>> +        {
> >>>> +            found = 1;
> >>>> +            break;
> >>>> +        }
> >>>> +        i++;
> >>>> +    }
> >>>
> >>> Instead of reading back all the GICH_LR registers, can't just just read
> >>> the ones that have a corresponding bit set in lr_mask?
> >>
> >> It's already the case, I use find_next_bit to find the next used LRs.
> >>
> >>> Also you should be able to avoid having to read the GICH_LR registers by
> >>> simply checking if the irq is in the lr_queue list: if an irq is in
> >>> inflight but not in lr_queue, it means that it is in one of the LRs.
> >>
> >>
> >> No. When a disabled IRQ is injected to the VCPU, Xen puts it in inflight
> >> but not in lr_queue. We don't have a way to know whether the IRQ is
> >> really in LRs or not.
> > 
> > I think it's time we introduce a "status" member in struct irq_desc, so
> 
> Do you mean struct irq_pending?

Yes, sorry I meant struct irq_pending

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 16:46         ` Ian Campbell
@ 2013-06-25 17:05           ` Stefano Stabellini
  2013-06-26 10:53             ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 17:05 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Julien Grall, xen-devel, patches, Stefano Stabellini

On Tue, 25 Jun 2013, Ian Campbell wrote:
> On Tue, 2013-06-25 at 17:36 +0100, Stefano Stabellini wrote:
> > I think it's time we introduce a "status" member in struct irq_desc, so
> > that we are not dependent on the information in the GICH_LR registers or
> > the queue a pending_irq has been added to.
> 
> Yes please, I find this one of the hardest things to keep straight in my
> head (not helped by my inability to remember which of pending and
> inflight is which...)
> 
> > I would implement it as a bitfield:
> > 
> > int status;
> > #define GIC_IRQ_ENABLED  (1<<0)
> > #define GIC_IRQ_INFLIGHT (1<<1)
> > #define GIC_IRQ_INLR     (1<<2)
> > 
> > This way you should just go through the inflight queue and check whether
> > status & GIC_IRQ_INLR.
> 
> Since some of this stuff happens in interrupt context you probably want
> test_bit/set_bit et al rather than regular boolean logic, don't you?
> 
> > At the moment we just want to represent this basic state machine:
> > 
> > irq guest asserted -> inflight -> injected (inlr) -> unasserted (maintenance interrupt)
> 
> Can we model the states after the active/pending states which the gic
> has? It might make a bunch of stuff clearer?

It might be worth storing those too.
So maybe:

#define GIC_IRQ_ENABLED           (1<<0)
#define GIC_IRQ_PENDING           (1<<1)
#define GIC_IRQ_ACTIVE            (1<<2)
#define GIC_IRQ_GUEST_INFLIGHT    (1<<3)
#define GIC_IRQ_GUEST_INLR        (1<<4)

however if we do store the physical gic states (GIC_IRQ_PENDING and
GIC_IRQ_ACTIVE) then maybe the right place for them is actually irq_desc
rather than irq_pending that is used just for guest irqs.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-25 16:55     ` Julien Grall
@ 2013-06-25 17:07       ` Stefano Stabellini
  0 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 17:07 UTC (permalink / raw)
  To: Julien Grall
  Cc: Julien Grall, xen-devel, ian.campbell, patches,
	Stefano Stabellini

On Tue, 25 Jun 2013, Julien Grall wrote:
> On 06/25/2013 05:19 PM, Stefano Stabellini wrote:
> 
> > On Tue, 25 Jun 2013, Julien Grall wrote:
> >> If the guest VCPU receives an interrupts when it's disabled, it will throw
> >                                    ^interrupt
> > 
> >> away the IRQ with EOIed it.
> > 
> > What does this mean? I cannot parse the sentence.
> 
> "it will throw away the IRQ without EOIing".
> 
> > 
> >> This is result to lost IRQ forever.
> >> Directly EOIed the interrupt doesn't help because the IRQ could be fired
> >> again and result to an infinited loop.
> >>
> >> It happens during dom0 boot on the versatile express TC2 with the ethernet
> >> card.
> >>
> >> Let the interrupt disabled when Xen setups the route and enable it when Linux
> >> asks to enable it.
> > 
> > Is the problem that Xen keeps the interrupt enabled even when Linux
> > disables it at the gic level? Is this what this patch is trying to
> > address?
> 
> This patch only delays the physical IRQ activation until Linux will
> enable it. This patch avoids to lose IRQ when a VCPU is disabled.
> 
> I tried to also disable the IRQ when Linux asks to disable it but the
> versatile express platform hang.

do you know why? and the arndale?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-25 16:28   ` Ian Campbell
@ 2013-06-25 17:38     ` Julien Grall
  2013-06-25 18:27       ` Stefano Stabellini
  2013-06-26 10:55       ` Ian Campbell
  0 siblings, 2 replies; 46+ messages in thread
From: Julien Grall @ 2013-06-25 17:38 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Julien Grall, Stefano.Stabellini, patches, xen-devel

On 06/25/2013 05:28 PM, Ian Campbell wrote:

> On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
>> If the guest VCPU receives an interrupts when it's disabled, it will throw
>> away the IRQ with EOIed it.
> 
> Did you mean "without EOIing it" or perhaps "having EOIed it"?
> 
>>  This is result to lost IRQ forever.
> 
> "This results in losing the IRQ forever".
> 
>> Directly EOIed the interrupt doesn't help because the IRQ could be fired
> 
> EOIing in this context.
> 
>> again and result to an infinited loop.
> 
>                         infinite
> 
>> It happens during dom0 boot on the versatile express TC2 with the ethernet
>> card.
>>
>> Let the interrupt disabled when Xen setups the route and enable it when Linux
> 
>   "Lets ... when Xen sets up the route..."
> 
>> asks to enable it.
>>
>> Signed-off-by: Julien Grall <julien.grall@citrix.com>
>> ---
>>  xen/arch/arm/domain_build.c |   14 ++++++++++++++
>>  xen/arch/arm/gic.c          |   25 +++++++++++++++++++++++--
>>  xen/arch/arm/vgic.c         |    7 +++----
>>  xen/include/asm-arm/gic.h   |    4 ++++
>>  xen/include/asm-arm/irq.h   |    6 ++++++
>>  5 files changed, 50 insertions(+), 6 deletions(-)
>>
>> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
>> index f5befbd..0470a2d 100644
>> --- a/xen/arch/arm/domain_build.c
>> +++ b/xen/arch/arm/domain_build.c
>> @@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
>>          }
>>  
>>          DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
>> +
>> +        /*
>> +         * Only map SGI interrupt in the guest as XEN won't handle
>> +         * it correctly.
>> +         * TODO: Fix it
>> +         */
>> +        if ( !irq_is_sgi(irq.irq) )
>> +        {
>> +            printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has "
> 
> s/has/as/ I think.
> 
> Did you really mean SGI here? I'd have thought from the context that you
> would mean SPIs. SGIs aren't anything to do with any real devices almost
> by definition -- if you saw on in the device tree I'd be very surprised!


It was SPIs. I will fix it in the next patch series.

> 
>> +                   "XEN doesn't handle properly non-SGI interrupt\n",
>> +                   i, dt_node_full_name(dev));
>> +            continue;
>> +        }
>> +
>>          /* Don't check return because the IRQ can be use by multiple device */
>>          gic_route_irq_to_guest(d, &irq, dt_node_name(dev));
>>      }
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index b16ba8c..e7d082a 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = {
>>      .set_affinity = gic_irq_set_affinity,
>>  };
>>  
>> +void gic_irq_enable(struct irq_desc *desc)
>> +{
>> +    spin_lock_irq(&desc->lock);
>> +    spin_lock(&gic.lock);
>> +
>> +    desc->handler->enable(desc);
>> +
>> +    spin_unlock(&gic.lock);
>> +    spin_unlock_irq(&desc->lock);
>> +}
>> +
>>  /* needs to be called with gic.lock held */
>>  static void gic_set_irq_properties(unsigned int irq, bool_t level,
>>          unsigned int cpu_mask, unsigned int priority)
>> @@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq,
>>      desc->status &= ~IRQ_DISABLED;
>>      dsb();
>>  
>> -    desc->handler->startup(desc);
>> -
>>      return 0;
>>  }
>>  
>> @@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
>>  
>>      rc = __setup_irq(desc, irq->irq, new);
>>  
>> +    desc->handler->startup(desc);
>> +
>>      spin_unlock_irqrestore(&desc->lock, flags);
>>  
>>      return rc;
>> @@ -711,6 +722,7 @@ void gic_inject(void)
>>          gic_inject_irq_start();
>>  }
>>  
>> +/* TODO: Handle properly non SGI-interrupt */
>>  int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>                             const char * devname)
>>  {
>> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>      unsigned long flags;
>>      int retval;
>>      bool_t level;
>> +    struct pending_irq *p;
>> +    /* XXX: handler other VCPU than 0 */
> 
> That should be something like "XXX: handle VCPUs other than 0".
> 
> This only matters if we can route SGIs or PPIs to the guest though I
> think, since they are the only banked interrupts? For SPIs we actually
> want to actively avoid doing this multiple times, don't we?


Yes. Here the VCPU is only used to retrieved the struct pending_irq.

> 
> For the banked interrupts I think we just need a loop here, or for
> p->desc to not be part of the pending_irq struct but actually part of
> some separate per-domain datastructure, since it would be very weird to
> have a domain where the PPIs differed between CPUs. (I'm not sure if
> that is allowed by the hardware, I bet it is, but it would be a
> pathological case IMHO...).

> I think a perdomain irq_desc * array is probably the right answer,
> unless someone can convincingly argue that PPI routing differing between
> VCPUs in a guest is a useful thing...


Until now, I didn't see PPIs on other devices than the arch timers and
the GIC. I don't know if it's possible, but pending_irq are also banked
for PPIs, so it's not an issue.

The issue is how do we link the physical PPI to the virtual PPI? Is a
1:1 mapping. How does Xen handle PPI when a it is coming on VCPUs which
doesn't handle it (for instance a domU)?

>> +    struct vcpu *v = d->vcpu[0];
>>  
>>      action = xmalloc(struct irqaction);
>>      if (!action)
>>          return -ENOMEM;
>>  
>> +    /* XXX: Here we assume a 1:1 interrupt mapping between the host and dom0 */
>> +    BUG_ON(irq->irq >= (d->arch.vgic.nr_lines + NR_LOCAL_IRQS));
>> +    p = irq_to_pending(v, irq->irq);
>> +
>>      action->dev_id = d;
>>      action->name = devname;
>>      action->free_on_release = 1;
>> @@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>          goto out;
>>      }
>>  
>> +    p->desc = desc;
>> +
>>  out:
>>      spin_unlock(&gic.lock);
>>      spin_unlock_irqrestore(&desc->lock, flags);
>> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
>> index cea9233..4f3d816 100644
>> --- a/xen/arch/arm/vgic.c
>> +++ b/xen/arch/arm/vgic.c
>> @@ -372,6 +372,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>>          if ( !list_empty(&p->inflight) && !gic_irq_injected(irq) )
>>              gic_set_guest_irq(v, irq, GICH_LR_PENDING, p->priority);
>>  
>> +        if ( p->desc != NULL )
>> +            gic_irq_enable(p->desc);
>> +
>>          i++;
>>      }
>>  }
>> @@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
>>  
>>      n->irq = irq;
>>      n->priority = priority;
>> -    if (!virtual)
>> -        n->desc = irq_to_desc(irq);
>> -    else
>> -        n->desc = NULL;
>>  
>>      /* the irq is enabled */
>>      if ( rank->ienable & (1 << (irq % 32)) )
>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>> index f9e9ef1..f7f3c1e 100644
>> --- a/xen/include/asm-arm/gic.h
>> +++ b/xen/include/asm-arm/gic.h
>> @@ -134,6 +134,7 @@
>>  
>>  #ifndef __ASSEMBLY__
>>  #include <xen/device_tree.h>
>> +#include <xen/irq.h>
>>  
>>  extern int domain_vgic_init(struct domain *d);
>>  extern void domain_vgic_free(struct domain *d);
>> @@ -154,6 +155,9 @@ extern void gic_inject(void);
>>  extern void gic_clear_pending_irqs(struct vcpu *v);
>>  extern int gic_events_need_delivery(void);
>>  
>> +/* Helper to enable an IRQ and take all the needed locks */
>> +extern void gic_irq_enable(struct irq_desc *desc);
>> +
>>  extern void __cpuinit init_maintenance_interrupt(void);
>>  extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq,
>>          unsigned int state, unsigned int priority);
>> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
>> index 80ff68d..346dc1d 100644
>> --- a/xen/include/asm-arm/irq.h
>> +++ b/xen/include/asm-arm/irq.h
>> @@ -46,6 +46,12 @@ int __init request_dt_irq(const struct dt_irq *irq,
>>                            void *dev_id);
>>  int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new);
>>  
>> +#define FIRST_SGI_IRQ   32
>> +static inline bool_t irq_is_sgi(unsigned int irq)
>> +{
>> +    return (irq >= FIRST_SGI_IRQ);
>> +}
>> +
>>  #endif /* _ASM_HW_IRQ_H */
>>  /*
>>   * Local variables:
> 
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-25 16:58     ` Stefano Stabellini
@ 2013-06-25 17:46       ` Julien Grall
  2013-06-25 18:38         ` Stefano Stabellini
  2013-06-26 10:58       ` Ian Campbell
  1 sibling, 1 reply; 46+ messages in thread
From: Julien Grall @ 2013-06-25 17:46 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: patches, Stefano Stabellini, Ian Campbell, xen-devel

On 06/25/2013 05:58 PM, Stefano Stabellini wrote:

> On Tue, 25 Jun 2013, Ian Campbell wrote:
>> On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
>>> From: Stefano Stabellini <stefano.stabellini@citrix.com>
>>>
>>> For guest's timers (both virtual and physical), Xen will inject virtual
>>> interrupt. Linux handles timer interrupt as:
>>
>> We should be wary of developing things based on the way which Linux
>> happens to do things. On x86 we have several time modes, which can be
>> selected based upon guest behaviour (described in
>> docs/man/xl.cfg.pod.5). Do we need to do something similar here?
>>
>>>   1) Receive the interrupt and ack it
>>>   2) Handle the current event timer
>>>   3) Set the next event timer
>>>   4) EOI the interrupt
>>>
>>> It's unlikely possible to reinject another interrupt before
>>
>> I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
>> not sure if that is what you meant.
>>
>>> the previous one is EOIed because the next deadline is shorter than the time
>>> to execute code until EOI it.
>>
>> If we get into this situation once is there any danger that we will get
>> into it repeatedly and overflow the count?
>>
>> Overall I'm not convinced this is the right approach to get the
>> behaviour we want. Isn't this interrupt level triggered, with the level
>> being determined by a comparison of two registers? IOW can't we
>> determine whether to retrigger the interrupt or not by examining the
>> state of our emulated versions of those registers? A generic mechanism
>> to callback into the appropriate emulator on EOI plus a little bit of
>> logic in the vtimer code is all it ought to take.
> 
> AFAICT this what could happen:
> 
> - vtimer fires
> - xen mask the vtimer
> - xen adds the vtimer to the LR for the guest
> - xen EOIs the vtimer
> - the guest receive the vtimer interrupt
> - the guest set the next deadline in the past
> - the guest enables the vtimer
> ## an unexpected vtimer interrupt is received by Xen but the current
> ## one is still being serviced 
> - the guest eoi the vtimer
> 
> as a result the guest looses an interrupt.
> Julien, is that correct?

Yes.

> If that is the case, this can only happen once, right?  In that case
> rather than an atomic_t we could just have a bit in the status field I
> proposed before. It should be enough for us to keep track of the case
> when the irq is supposed to stay high even after the guest EOIs it. (Of
> course that means that we need to re-inject it into the guest).


For the timer yes. I wonder, what happen if Xen receive an SGI (for
instance SCHEDULE ipi) twice, does Xen must re-inject it multiple times?

>>> Signed-off-by: Stefano Stabellini <stefano.stabellini@citrix.com>
>>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>>> ---
>>>  xen/arch/arm/gic.c           |   35 +++++++++++++++++++++++------------
>>>  xen/arch/arm/vgic.c          |    1 +
>>>  xen/include/asm-arm/domain.h |    2 ++
>>>  3 files changed, 26 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>>> index 0fee3f2..21575df 100644
>>> --- a/xen/arch/arm/gic.c
>>> +++ b/xen/arch/arm/gic.c
>>> @@ -817,7 +817,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>>>  
>>>      while ((i = find_next_bit((const long unsigned int *) &eisr,
>>>                                64, i)) < 64) {
>>> -        struct pending_irq *p;
>>> +        struct pending_irq *p, *n;
>>>          int cpu, eoi;
>>>  
>>>          cpu = -1;
>>> @@ -826,13 +826,32 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>>>          spin_lock_irq(&gic.lock);
>>>          lr = GICH[GICH_LR + i];
>>>          virq = lr & GICH_LR_VIRTUAL_MASK;
>>> +
>>> +        p = irq_to_pending(v, virq);
>>> +        if ( p->desc != NULL ) {
>>> +            p->desc->status &= ~IRQ_INPROGRESS;
> 
> Now that I am thinking about this, shouldn't this be protected by taking
> the desc->lock?

Right. I don't think desc->lock is enough if we want to protect from
release_irq.
If this function is called, it will wait until IRQ_INPROGRESS is
removed. How about moving ~IRQ_INPROGRESS at then end of the block and
add a dmb() before?

>>> +            /* Assume only one pcpu needs to EOI the irq */
>>> +            cpu = p->desc->arch.eoi_cpu;
>>> +            eoi = 1;
>>> +            pirq = p->desc->irq;
>>> +        }
>>> +        if ( !atomic_dec_and_test(&p->inflight_cnt) )
>>> +        {
>>> +            /* Physical IRQ can't be reinject */
>>> +            WARN_ON(p->desc != NULL);
>>> +            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
>>> +            spin_unlock_irq(&gic.lock);
>>> +            i++;
>>> +            continue;
>>> +        }
>>> +
>>>          GICH[GICH_LR + i] = 0;
>>>          clear_bit(i, &this_cpu(lr_mask));
>>>  
>>>          if ( !list_empty(&v->arch.vgic.lr_pending) ) {
>>> -            p = list_entry(v->arch.vgic.lr_pending.next, typeof(*p), lr_queue);
>>> -            gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
>>> -            list_del_init(&p->lr_queue);
>>> +            n = list_entry(v->arch.vgic.lr_pending.next, typeof(*n), lr_queue);
>>> +            gic_set_lr(i, n->irq, GICH_LR_PENDING, n->priority);
>>> +            list_del_init(&n->lr_queue);
>>>              set_bit(i, &this_cpu(lr_mask));
>>>          } else {
>>>              gic_inject_irq_stop();
>>> @@ -840,14 +859,6 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
>>>          spin_unlock_irq(&gic.lock);
>>>  
>>>          spin_lock_irq(&v->arch.vgic.lock);
>>> -        p = irq_to_pending(v, virq);
>>> -        if ( p->desc != NULL ) {
>>> -            p->desc->status &= ~IRQ_INPROGRESS;
>>> -            /* Assume only one pcpu needs to EOI the irq */
>>> -            cpu = p->desc->arch.eoi_cpu;
>>> -            eoi = 1;
>>> -            pirq = p->desc->irq;
>>> -        }
>>>          list_del_init(&p->inflight);
>>>          spin_unlock_irq(&v->arch.vgic.lock);
>>>  
>  

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-25 17:38     ` Julien Grall
@ 2013-06-25 18:27       ` Stefano Stabellini
  2013-06-26 10:55       ` Ian Campbell
  1 sibling, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 18:27 UTC (permalink / raw)
  To: Julien Grall
  Cc: Julien Grall, Stefano.Stabellini, Ian Campbell, patches,
	xen-devel

On Tue, 25 Jun 2013, Julien Grall wrote:
> On 06/25/2013 05:28 PM, Ian Campbell wrote:
> 
> > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> >> If the guest VCPU receives an interrupts when it's disabled, it will throw
> >> away the IRQ with EOIed it.
> > 
> > Did you mean "without EOIing it" or perhaps "having EOIed it"?
> > 
> >>  This is result to lost IRQ forever.
> > 
> > "This results in losing the IRQ forever".
> > 
> >> Directly EOIed the interrupt doesn't help because the IRQ could be fired
> > 
> > EOIing in this context.
> > 
> >> again and result to an infinited loop.
> > 
> >                         infinite
> > 
> >> It happens during dom0 boot on the versatile express TC2 with the ethernet
> >> card.
> >>
> >> Let the interrupt disabled when Xen setups the route and enable it when Linux
> > 
> >   "Lets ... when Xen sets up the route..."
> > 
> >> asks to enable it.
> >>
> >> Signed-off-by: Julien Grall <julien.grall@citrix.com>
> >> ---
> >>  xen/arch/arm/domain_build.c |   14 ++++++++++++++
> >>  xen/arch/arm/gic.c          |   25 +++++++++++++++++++++++--
> >>  xen/arch/arm/vgic.c         |    7 +++----
> >>  xen/include/asm-arm/gic.h   |    4 ++++
> >>  xen/include/asm-arm/irq.h   |    6 ++++++
> >>  5 files changed, 50 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> >> index f5befbd..0470a2d 100644
> >> --- a/xen/arch/arm/domain_build.c
> >> +++ b/xen/arch/arm/domain_build.c
> >> @@ -408,6 +408,20 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
> >>          }
> >>  
> >>          DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
> >> +
> >> +        /*
> >> +         * Only map SGI interrupt in the guest as XEN won't handle
> >> +         * it correctly.
> >> +         * TODO: Fix it
> >> +         */
> >> +        if ( !irq_is_sgi(irq.irq) )
> >> +        {
> >> +            printk(XENLOG_WARNING "WARNING: Don't map irq %u for %s has "
> > 
> > s/has/as/ I think.
> > 
> > Did you really mean SGI here? I'd have thought from the context that you
> > would mean SPIs. SGIs aren't anything to do with any real devices almost
> > by definition -- if you saw on in the device tree I'd be very surprised!
> 
> 
> It was SPIs. I will fix it in the next patch series.
> 
> > 
> >> +                   "XEN doesn't handle properly non-SGI interrupt\n",
> >> +                   i, dt_node_full_name(dev));
> >> +            continue;
> >> +        }
> >> +
> >>          /* Don't check return because the IRQ can be use by multiple device */
> >>          gic_route_irq_to_guest(d, &irq, dt_node_name(dev));
> >>      }
> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >> index b16ba8c..e7d082a 100644
> >> --- a/xen/arch/arm/gic.c
> >> +++ b/xen/arch/arm/gic.c
> >> @@ -179,6 +179,17 @@ static hw_irq_controller gic_guest_irq_type = {
> >>      .set_affinity = gic_irq_set_affinity,
> >>  };
> >>  
> >> +void gic_irq_enable(struct irq_desc *desc)
> >> +{
> >> +    spin_lock_irq(&desc->lock);
> >> +    spin_lock(&gic.lock);
> >> +
> >> +    desc->handler->enable(desc);
> >> +
> >> +    spin_unlock(&gic.lock);
> >> +    spin_unlock_irq(&desc->lock);
> >> +}
> >> +
> >>  /* needs to be called with gic.lock held */
> >>  static void gic_set_irq_properties(unsigned int irq, bool_t level,
> >>          unsigned int cpu_mask, unsigned int priority)
> >> @@ -543,8 +554,6 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq,
> >>      desc->status &= ~IRQ_DISABLED;
> >>      dsb();
> >>  
> >> -    desc->handler->startup(desc);
> >> -
> >>      return 0;
> >>  }
> >>  
> >> @@ -560,6 +569,8 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
> >>  
> >>      rc = __setup_irq(desc, irq->irq, new);
> >>  
> >> +    desc->handler->startup(desc);
> >> +
> >>      spin_unlock_irqrestore(&desc->lock, flags);
> >>  
> >>      return rc;
> >> @@ -711,6 +722,7 @@ void gic_inject(void)
> >>          gic_inject_irq_start();
> >>  }
> >>  
> >> +/* TODO: Handle properly non SGI-interrupt */
> >>  int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
> >>                             const char * devname)
> >>  {
> >> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
> >>      unsigned long flags;
> >>      int retval;
> >>      bool_t level;
> >> +    struct pending_irq *p;
> >> +    /* XXX: handler other VCPU than 0 */
> > 
> > That should be something like "XXX: handle VCPUs other than 0".
> > 
> > This only matters if we can route SGIs or PPIs to the guest though I
> > think, since they are the only banked interrupts? For SPIs we actually
> > want to actively avoid doing this multiple times, don't we?
> 
> 
> Yes. Here the VCPU is only used to retrieved the struct pending_irq.
> 
> > 
> > For the banked interrupts I think we just need a loop here, or for
> > p->desc to not be part of the pending_irq struct but actually part of
> > some separate per-domain datastructure, since it would be very weird to
> > have a domain where the PPIs differed between CPUs. (I'm not sure if
> > that is allowed by the hardware, I bet it is, but it would be a
> > pathological case IMHO...).
> 
> > I think a perdomain irq_desc * array is probably the right answer,
> > unless someone can convincingly argue that PPI routing differing between
> > VCPUs in a guest is a useful thing...
> 
> 
> Until now, I didn't see PPIs on other devices than the arch timers and
> the GIC. I don't know if it's possible, but pending_irq are also banked
> for PPIs, so it's not an issue.
> 
> The issue is how do we link the physical PPI to the virtual PPI? Is a
> 1:1 mapping. How does Xen handle PPI when a it is coming on VCPUs which
> doesn't handle it (for instance a domU)?

We should be already able to handle this case: vgic_vcpu_inject_irq uses
smp_send_event_check_mask to make sure the other physical processor
receives the notification and injects the virq.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-25 17:46       ` Julien Grall
@ 2013-06-25 18:38         ` Stefano Stabellini
  2013-06-26 10:59           ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-25 18:38 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, Ian Campbell, patches,
	Stefano Stabellini

On Tue, 25 Jun 2013, Julien Grall wrote:
> On 06/25/2013 05:58 PM, Stefano Stabellini wrote:
> 
> > On Tue, 25 Jun 2013, Ian Campbell wrote:
> >> On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> >>> From: Stefano Stabellini <stefano.stabellini@citrix.com>
> >>>
> >>> For guest's timers (both virtual and physical), Xen will inject virtual
> >>> interrupt. Linux handles timer interrupt as:
> >>
> >> We should be wary of developing things based on the way which Linux
> >> happens to do things. On x86 we have several time modes, which can be
> >> selected based upon guest behaviour (described in
> >> docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> >>
> >>>   1) Receive the interrupt and ack it
> >>>   2) Handle the current event timer
> >>>   3) Set the next event timer
> >>>   4) EOI the interrupt
> >>>
> >>> It's unlikely possible to reinject another interrupt before
> >>
> >> I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> >> not sure if that is what you meant.
> >>
> >>> the previous one is EOIed because the next deadline is shorter than the time
> >>> to execute code until EOI it.
> >>
> >> If we get into this situation once is there any danger that we will get
> >> into it repeatedly and overflow the count?
> >>
> >> Overall I'm not convinced this is the right approach to get the
> >> behaviour we want. Isn't this interrupt level triggered, with the level
> >> being determined by a comparison of two registers? IOW can't we
> >> determine whether to retrigger the interrupt or not by examining the
> >> state of our emulated versions of those registers? A generic mechanism
> >> to callback into the appropriate emulator on EOI plus a little bit of
> >> logic in the vtimer code is all it ought to take.
> > 
> > AFAICT this what could happen:
> > 
> > - vtimer fires
> > - xen mask the vtimer
> > - xen adds the vtimer to the LR for the guest
> > - xen EOIs the vtimer
> > - the guest receive the vtimer interrupt
> > - the guest set the next deadline in the past
> > - the guest enables the vtimer
> > ## an unexpected vtimer interrupt is received by Xen but the current
> > ## one is still being serviced 
> > - the guest eoi the vtimer
> > 
> > as a result the guest looses an interrupt.
> > Julien, is that correct?
> 
> Yes.

Could you please add something like that to the commit message?


> > If that is the case, this can only happen once, right?  In that case
> > rather than an atomic_t we could just have a bit in the status field I
> > proposed before. It should be enough for us to keep track of the case
> > when the irq is supposed to stay high even after the guest EOIs it. (Of
> > course that means that we need to re-inject it into the guest).
> 
> 
> For the timer yes. I wonder, what happen if Xen receive an SGI (for
> instance SCHEDULE ipi) twice, does Xen must re-inject it multiple times?

I don't think it can happen with anything but the vtimer: in order for
the scenario above to happen it takes an irq that is EOId in the
hardware before the guest EOIs it.

SGIs are completely "emulated", there is not an hardware irq
corresponding to them. From the Xen point of view the SGI is inflight
exactly and only from the moment the first vcpu sends it, to the point
when the receiving vcpu EOIs it.


> >>> Signed-off-by: Stefano Stabellini <stefano.stabellini@citrix.com>
> >>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >>> ---
> >>>  xen/arch/arm/gic.c           |   35 +++++++++++++++++++++++------------
> >>>  xen/arch/arm/vgic.c          |    1 +
> >>>  xen/include/asm-arm/domain.h |    2 ++
> >>>  3 files changed, 26 insertions(+), 12 deletions(-)
> >>>
> >>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >>> index 0fee3f2..21575df 100644
> >>> --- a/xen/arch/arm/gic.c
> >>> +++ b/xen/arch/arm/gic.c
> >>> @@ -817,7 +817,7 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >>>  
> >>>      while ((i = find_next_bit((const long unsigned int *) &eisr,
> >>>                                64, i)) < 64) {
> >>> -        struct pending_irq *p;
> >>> +        struct pending_irq *p, *n;
> >>>          int cpu, eoi;
> >>>  
> >>>          cpu = -1;
> >>> @@ -826,13 +826,32 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
> >>>          spin_lock_irq(&gic.lock);
> >>>          lr = GICH[GICH_LR + i];
> >>>          virq = lr & GICH_LR_VIRTUAL_MASK;
> >>> +
> >>> +        p = irq_to_pending(v, virq);
> >>> +        if ( p->desc != NULL ) {
> >>> +            p->desc->status &= ~IRQ_INPROGRESS;
> > 
> > Now that I am thinking about this, shouldn't this be protected by taking
> > the desc->lock?
> 
> Right. I don't think desc->lock is enough if we want to protect from
> release_irq.
> If this function is called, it will wait until IRQ_INPROGRESS is
> removed. How about moving ~IRQ_INPROGRESS at then end of the block and
> add a dmb() before?

that should work

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-25 17:05           ` Stefano Stabellini
@ 2013-06-26 10:53             ` Ian Campbell
  2013-06-26 11:19               ` Stefano Stabellini
  0 siblings, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 10:53 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, patches, xen-devel

On Tue, 2013-06-25 at 18:05 +0100, Stefano Stabellini wrote:
> On Tue, 25 Jun 2013, Ian Campbell wrote:
> > On Tue, 2013-06-25 at 17:36 +0100, Stefano Stabellini wrote:
> > > I think it's time we introduce a "status" member in struct irq_desc, so
> > > that we are not dependent on the information in the GICH_LR registers or
> > > the queue a pending_irq has been added to.
> > 
> > Yes please, I find this one of the hardest things to keep straight in my
> > head (not helped by my inability to remember which of pending and
> > inflight is which...)
> > 
> > > I would implement it as a bitfield:
> > > 
> > > int status;
> > > #define GIC_IRQ_ENABLED  (1<<0)
> > > #define GIC_IRQ_INFLIGHT (1<<1)
> > > #define GIC_IRQ_INLR     (1<<2)
> > > 
> > > This way you should just go through the inflight queue and check whether
> > > status & GIC_IRQ_INLR.
> > 
> > Since some of this stuff happens in interrupt context you probably want
> > test_bit/set_bit et al rather than regular boolean logic, don't you?
> > 
> > > At the moment we just want to represent this basic state machine:
> > > 
> > > irq guest asserted -> inflight -> injected (inlr) -> unasserted (maintenance interrupt)
> > 
> > Can we model the states after the active/pending states which the gic
> > has? It might make a bunch of stuff clearer?
> 
> It might be worth storing those too.
> So maybe:
> 
> #define GIC_IRQ_ENABLED           (1<<0)
> #define GIC_IRQ_PENDING           (1<<1)
> #define GIC_IRQ_ACTIVE            (1<<2)
> #define GIC_IRQ_GUEST_INFLIGHT    (1<<3)
> #define GIC_IRQ_GUEST_INLR        (1<<4)
> 
> however if we do store the physical gic states (GIC_IRQ_PENDING and
> GIC_IRQ_ACTIVE) then maybe the right place for them is actually irq_desc
> rather than irq_pending that is used just for guest irqs.

I was thinking of these as states of the emulated interrupts, rather
than any underlying physical interrupts, so I think irq_pending is
correct?

It occurs to me that at least some of these bits are also fields in the
LR. I think it is good to save them separately (reducing the
intertwining of our interrupt handling from GIC internals is a good
thing) but it means you will need to take care of syncing the state
between the LR and our internal state at various points, since the LR
can change based on the guest EOI etc.

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-25 17:38     ` Julien Grall
  2013-06-25 18:27       ` Stefano Stabellini
@ 2013-06-26 10:55       ` Ian Campbell
  2013-06-26 13:03         ` Julien Grall
  1 sibling, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 10:55 UTC (permalink / raw)
  To: Julien Grall; +Cc: Julien Grall, Stefano.Stabellini, patches, xen-devel

On Tue, 2013-06-25 at 18:38 +0100, Julien Grall wrote:
> >> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
> >>      unsigned long flags;
> >>      int retval;
> >>      bool_t level;
> >> +    struct pending_irq *p;
> >> +    /* XXX: handler other VCPU than 0 */
> > 
> > That should be something like "XXX: handle VCPUs other than 0".
> > 
> > This only matters if we can route SGIs or PPIs to the guest though I
> > think, since they are the only banked interrupts? For SPIs we actually
> > want to actively avoid doing this multiple times, don't we?
> 
> 
> Yes. Here the VCPU is only used to retrieved the struct pending_irq.

Which is per-CPU for PPIs and SGIs. Do we not care about PPIs here?

> > 
> > For the banked interrupts I think we just need a loop here, or for
> > p->desc to not be part of the pending_irq struct but actually part of
> > some separate per-domain datastructure, since it would be very weird to
> > have a domain where the PPIs differed between CPUs. (I'm not sure if
> > that is allowed by the hardware, I bet it is, but it would be a
> > pathological case IMHO...).
> 
> > I think a perdomain irq_desc * array is probably the right answer,
> > unless someone can convincingly argue that PPI routing differing between
> > VCPUs in a guest is a useful thing...
> 
> 
> Until now, I didn't see PPIs on other devices than the arch timers and
> the GIC. I don't know if it's possible, but pending_irq are also banked
> for PPIs, so it's not an issue.
> 
> The issue is how do we link the physical PPI to the virtual PPI? Is a
> 1:1 mapping. How does Xen handle PPI when a it is coming on VCPUs which
> doesn't handle it (for instance a domU)?

How do you mean?

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-25 16:58     ` Stefano Stabellini
  2013-06-25 17:46       ` Julien Grall
@ 2013-06-26 10:58       ` Ian Campbell
  2013-06-26 11:08         ` Stefano Stabellini
  1 sibling, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 10:58 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, Stefano Stabellini, patches, xen-devel

On Tue, 2013-06-25 at 17:58 +0100, Stefano Stabellini wrote:
> On Tue, 25 Jun 2013, Ian Campbell wrote:
> > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > > 
> > > For guest's timers (both virtual and physical), Xen will inject virtual
> > > interrupt. Linux handles timer interrupt as:
> > 
> > We should be wary of developing things based on the way which Linux
> > happens to do things. On x86 we have several time modes, which can be
> > selected based upon guest behaviour (described in
> > docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> > 
> > >   1) Receive the interrupt and ack it
> > >   2) Handle the current event timer
> > >   3) Set the next event timer
> > >   4) EOI the interrupt
> > > 
> > > It's unlikely possible to reinject another interrupt before
> > 
> > I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> > not sure if that is what you meant.
> > 
> > > the previous one is EOIed because the next deadline is shorter than the time
> > > to execute code until EOI it.
> > 
> > If we get into this situation once is there any danger that we will get
> > into it repeatedly and overflow the count?
> > 
> > Overall I'm not convinced this is the right approach to get the
> > behaviour we want. Isn't this interrupt level triggered, with the level
> > being determined by a comparison of two registers? IOW can't we
> > determine whether to retrigger the interrupt or not by examining the
> > state of our emulated versions of those registers? A generic mechanism
> > to callback into the appropriate emulator on EOI plus a little bit of
> > logic in the vtimer code is all it ought to take.
> 
> AFAICT this what could happen:
> 
> - vtimer fires
> - xen mask the vtimer
> - xen adds the vtimer to the LR for the guest
> - xen EOIs the vtimer

This step is Xen deprioritises the interrupt (by writing to the GICD_DIR
register)...

> - the guest receive the vtimer interrupt
> - the guest set the next deadline in the past
> - the guest enables the vtimer
> ## an unexpected vtimer interrupt is received by Xen but the current
> ## one is still being serviced 
> - the guest eoi the vtimer

... and the actual Xen EOI only happens here in response to the
maintenance interrupt resulting from the guests EOI.

(or maybe I've misunderstood what you mean by "EOI the vtimer")

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-25 18:38         ` Stefano Stabellini
@ 2013-06-26 10:59           ` Ian Campbell
  2013-06-26 11:10             ` Stefano Stabellini
  0 siblings, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 10:59 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, Stefano Stabellini, patches, xen-devel

On Tue, 2013-06-25 at 19:38 +0100, Stefano Stabellini wrote:
> > > If that is the case, this can only happen once, right?  In that case
> > > rather than an atomic_t we could just have a bit in the status field I
> > > proposed before. It should be enough for us to keep track of the case
> > > when the irq is supposed to stay high even after the guest EOIs it. (Of
> > > course that means that we need to re-inject it into the guest).
> > 
> > 
> > For the timer yes. I wonder, what happen if Xen receive an SGI (for
> > instance SCHEDULE ipi) twice, does Xen must re-inject it multiple times?
> 
> I don't think it can happen with anything but the vtimer: in order for
> the scenario above to happen it takes an irq that is EOId in the
> hardware before the guest EOIs it.
> 
> SGIs are completely "emulated", there is not an hardware irq
> corresponding to them. From the Xen point of view the SGI is inflight
> exactly and only from the moment the first vcpu sends it, to the point
> when the receiving vcpu EOIs it.

Are we talking about real SGIs (passed by Xen between physical
processors) or fake SGIs (emulated between virtual processors)?

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 10:58       ` Ian Campbell
@ 2013-06-26 11:08         ` Stefano Stabellini
  2013-06-26 11:15           ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-26 11:08 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Julien Grall, xen-devel, patches,
	Stefano Stabellini

On Wed, 26 Jun 2013, Ian Campbell wrote:
> On Tue, 2013-06-25 at 17:58 +0100, Stefano Stabellini wrote:
> > On Tue, 25 Jun 2013, Ian Campbell wrote:
> > > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > > > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > > > 
> > > > For guest's timers (both virtual and physical), Xen will inject virtual
> > > > interrupt. Linux handles timer interrupt as:
> > > 
> > > We should be wary of developing things based on the way which Linux
> > > happens to do things. On x86 we have several time modes, which can be
> > > selected based upon guest behaviour (described in
> > > docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> > > 
> > > >   1) Receive the interrupt and ack it
> > > >   2) Handle the current event timer
> > > >   3) Set the next event timer
> > > >   4) EOI the interrupt
> > > > 
> > > > It's unlikely possible to reinject another interrupt before
> > > 
> > > I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> > > not sure if that is what you meant.
> > > 
> > > > the previous one is EOIed because the next deadline is shorter than the time
> > > > to execute code until EOI it.
> > > 
> > > If we get into this situation once is there any danger that we will get
> > > into it repeatedly and overflow the count?
> > > 
> > > Overall I'm not convinced this is the right approach to get the
> > > behaviour we want. Isn't this interrupt level triggered, with the level
> > > being determined by a comparison of two registers? IOW can't we
> > > determine whether to retrigger the interrupt or not by examining the
> > > state of our emulated versions of those registers? A generic mechanism
> > > to callback into the appropriate emulator on EOI plus a little bit of
> > > logic in the vtimer code is all it ought to take.
> > 
> > AFAICT this what could happen:
> > 
> > - vtimer fires
> > - xen mask the vtimer
> > - xen adds the vtimer to the LR for the guest
> > - xen EOIs the vtimer
> 
> This step is Xen deprioritises the interrupt (by writing to the GICD_DIR
> register)...
> 
> > - the guest receive the vtimer interrupt
> > - the guest set the next deadline in the past
> > - the guest enables the vtimer
> > ## an unexpected vtimer interrupt is received by Xen but the current
> > ## one is still being serviced 
> > - the guest eoi the vtimer
> 
> ... and the actual Xen EOI only happens here in response to the
> maintenance interrupt resulting from the guests EOI.
> 
> (or maybe I've misunderstood what you mean by "EOI the vtimer")

The vtimer is a Xen irq that injects an irq into the guest from the Xen
interrupt handler. It's not a guest irq.
See xen/arch/arm/time.c:vtimer_interrupt.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 10:59           ` Ian Campbell
@ 2013-06-26 11:10             ` Stefano Stabellini
  2013-06-26 11:16               ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-26 11:10 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Julien Grall, xen-devel, patches,
	Stefano Stabellini

On Wed, 26 Jun 2013, Ian Campbell wrote:
> On Tue, 2013-06-25 at 19:38 +0100, Stefano Stabellini wrote:
> > > > If that is the case, this can only happen once, right?  In that case
> > > > rather than an atomic_t we could just have a bit in the status field I
> > > > proposed before. It should be enough for us to keep track of the case
> > > > when the irq is supposed to stay high even after the guest EOIs it. (Of
> > > > course that means that we need to re-inject it into the guest).
> > > 
> > > 
> > > For the timer yes. I wonder, what happen if Xen receive an SGI (for
> > > instance SCHEDULE ipi) twice, does Xen must re-inject it multiple times?
> > 
> > I don't think it can happen with anything but the vtimer: in order for
> > the scenario above to happen it takes an irq that is EOId in the
> > hardware before the guest EOIs it.
> > 
> > SGIs are completely "emulated", there is not an hardware irq
> > corresponding to them. From the Xen point of view the SGI is inflight
> > exactly and only from the moment the first vcpu sends it, to the point
> > when the receiving vcpu EOIs it.
> 
> Are we talking about real SGIs (passed by Xen between physical
> processors) or fake SGIs (emulated between virtual processors)?

I was talking about fake SGIs

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:08         ` Stefano Stabellini
@ 2013-06-26 11:15           ` Ian Campbell
  2013-06-26 11:23             ` Stefano Stabellini
  0 siblings, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 11:15 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, Stefano Stabellini, patches, xen-devel

On Wed, 2013-06-26 at 12:08 +0100, Stefano Stabellini wrote:
> On Wed, 26 Jun 2013, Ian Campbell wrote:
> > On Tue, 2013-06-25 at 17:58 +0100, Stefano Stabellini wrote:
> > > On Tue, 25 Jun 2013, Ian Campbell wrote:
> > > > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > > > > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > > > > 
> > > > > For guest's timers (both virtual and physical), Xen will inject virtual
> > > > > interrupt. Linux handles timer interrupt as:
> > > > 
> > > > We should be wary of developing things based on the way which Linux
> > > > happens to do things. On x86 we have several time modes, which can be
> > > > selected based upon guest behaviour (described in
> > > > docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> > > > 
> > > > >   1) Receive the interrupt and ack it
> > > > >   2) Handle the current event timer
> > > > >   3) Set the next event timer
> > > > >   4) EOI the interrupt
> > > > > 
> > > > > It's unlikely possible to reinject another interrupt before
> > > > 
> > > > I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> > > > not sure if that is what you meant.
> > > > 
> > > > > the previous one is EOIed because the next deadline is shorter than the time
> > > > > to execute code until EOI it.
> > > > 
> > > > If we get into this situation once is there any danger that we will get
> > > > into it repeatedly and overflow the count?
> > > > 
> > > > Overall I'm not convinced this is the right approach to get the
> > > > behaviour we want. Isn't this interrupt level triggered, with the level
> > > > being determined by a comparison of two registers? IOW can't we
> > > > determine whether to retrigger the interrupt or not by examining the
> > > > state of our emulated versions of those registers? A generic mechanism
> > > > to callback into the appropriate emulator on EOI plus a little bit of
> > > > logic in the vtimer code is all it ought to take.
> > > 
> > > AFAICT this what could happen:
> > > 
> > > - vtimer fires
> > > - xen mask the vtimer
> > > - xen adds the vtimer to the LR for the guest
> > > - xen EOIs the vtimer
> > 
> > This step is Xen deprioritises the interrupt (by writing to the GICD_DIR
> > register)...
> > 
> > > - the guest receive the vtimer interrupt
> > > - the guest set the next deadline in the past
> > > - the guest enables the vtimer
> > > ## an unexpected vtimer interrupt is received by Xen but the current
> > > ## one is still being serviced 
> > > - the guest eoi the vtimer
> > 
> > ... and the actual Xen EOI only happens here in response to the
> > maintenance interrupt resulting from the guests EOI.
> > 
> > (or maybe I've misunderstood what you mean by "EOI the vtimer")
> 
> The vtimer is a Xen irq that injects an irq into the guest from the Xen
> interrupt handler. It's not a guest irq.
> See xen/arch/arm/time.c:vtimer_interrupt.

OK, so what does it mean to "EOI" that timer?

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:10             ` Stefano Stabellini
@ 2013-06-26 11:16               ` Ian Campbell
  0 siblings, 0 replies; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 11:16 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, Stefano Stabellini, patches, xen-devel

On Wed, 2013-06-26 at 12:10 +0100, Stefano Stabellini wrote:
> On Wed, 26 Jun 2013, Ian Campbell wrote:
> > On Tue, 2013-06-25 at 19:38 +0100, Stefano Stabellini wrote:
> > > > > If that is the case, this can only happen once, right?  In that case
> > > > > rather than an atomic_t we could just have a bit in the status field I
> > > > > proposed before. It should be enough for us to keep track of the case
> > > > > when the irq is supposed to stay high even after the guest EOIs it. (Of
> > > > > course that means that we need to re-inject it into the guest).
> > > > 
> > > > 
> > > > For the timer yes. I wonder, what happen if Xen receive an SGI (for
> > > > instance SCHEDULE ipi) twice, does Xen must re-inject it multiple times?
> > > 
> > > I don't think it can happen with anything but the vtimer: in order for
> > > the scenario above to happen it takes an irq that is EOId in the
> > > hardware before the guest EOIs it.
> > > 
> > > SGIs are completely "emulated", there is not an hardware irq
> > > corresponding to them. From the Xen point of view the SGI is inflight
> > > exactly and only from the moment the first vcpu sends it, to the point
> > > when the receiving vcpu EOIs it.
> > 
> > Are we talking about real SGIs (passed by Xen between physical
> > processors) or fake SGIs (emulated between virtual processors)?
> 
> I was talking about fake SGIs

I think Julien was talking about real ones (the Xen schedule IPI).

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs
  2013-06-26 10:53             ` Ian Campbell
@ 2013-06-26 11:19               ` Stefano Stabellini
  0 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-26 11:19 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Julien Grall, xen-devel, patches, Stefano Stabellini

On Wed, 26 Jun 2013, Ian Campbell wrote:
> On Tue, 2013-06-25 at 18:05 +0100, Stefano Stabellini wrote:
> > On Tue, 25 Jun 2013, Ian Campbell wrote:
> > > On Tue, 2013-06-25 at 17:36 +0100, Stefano Stabellini wrote:
> > > > I think it's time we introduce a "status" member in struct irq_desc, so
> > > > that we are not dependent on the information in the GICH_LR registers or
> > > > the queue a pending_irq has been added to.
> > > 
> > > Yes please, I find this one of the hardest things to keep straight in my
> > > head (not helped by my inability to remember which of pending and
> > > inflight is which...)
> > > 
> > > > I would implement it as a bitfield:
> > > > 
> > > > int status;
> > > > #define GIC_IRQ_ENABLED  (1<<0)
> > > > #define GIC_IRQ_INFLIGHT (1<<1)
> > > > #define GIC_IRQ_INLR     (1<<2)
> > > > 
> > > > This way you should just go through the inflight queue and check whether
> > > > status & GIC_IRQ_INLR.
> > > 
> > > Since some of this stuff happens in interrupt context you probably want
> > > test_bit/set_bit et al rather than regular boolean logic, don't you?
> > > 
> > > > At the moment we just want to represent this basic state machine:
> > > > 
> > > > irq guest asserted -> inflight -> injected (inlr) -> unasserted (maintenance interrupt)
> > > 
> > > Can we model the states after the active/pending states which the gic
> > > has? It might make a bunch of stuff clearer?
> > 
> > It might be worth storing those too.
> > So maybe:
> > 
> > #define GIC_IRQ_ENABLED           (1<<0)
> > #define GIC_IRQ_PENDING           (1<<1)
> > #define GIC_IRQ_ACTIVE            (1<<2)
> > #define GIC_IRQ_GUEST_INFLIGHT    (1<<3)
> > #define GIC_IRQ_GUEST_INLR        (1<<4)
> > 
> > however if we do store the physical gic states (GIC_IRQ_PENDING and
> > GIC_IRQ_ACTIVE) then maybe the right place for them is actually irq_desc
> > rather than irq_pending that is used just for guest irqs.
> 
> I was thinking of these as states of the emulated interrupts, rather
> than any underlying physical interrupts, so I think irq_pending is
> correct?

In that case yes


> It occurs to me that at least some of these bits are also fields in the
> LR. I think it is good to save them separately (reducing the
> intertwining of our interrupt handling from GIC internals is a good
> thing) but it means you will need to take care of syncing the state
> between the LR and our internal state at various points, since the LR
> can change based on the guest EOI etc.

I don't think we can accurately distinguish between pending and active
states for guest irqs, because the transition between the two happens
transparently from Xen's point of view.
The only thing we can do is update the state in irq_pending when we save
and restore the GICH_LR registers.
That might still be useful because it would allow us to know which ones
of the irqs currently in the LRs registers can be temporarily set aside
(for example to implement priorities).

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:15           ` Ian Campbell
@ 2013-06-26 11:23             ` Stefano Stabellini
  2013-06-26 11:41               ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-26 11:23 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Julien Grall, xen-devel, patches,
	Stefano Stabellini

On Wed, 26 Jun 2013, Ian Campbell wrote:
> On Wed, 2013-06-26 at 12:08 +0100, Stefano Stabellini wrote:
> > On Wed, 26 Jun 2013, Ian Campbell wrote:
> > > On Tue, 2013-06-25 at 17:58 +0100, Stefano Stabellini wrote:
> > > > On Tue, 25 Jun 2013, Ian Campbell wrote:
> > > > > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > > > > > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > > > > > 
> > > > > > For guest's timers (both virtual and physical), Xen will inject virtual
> > > > > > interrupt. Linux handles timer interrupt as:
> > > > > 
> > > > > We should be wary of developing things based on the way which Linux
> > > > > happens to do things. On x86 we have several time modes, which can be
> > > > > selected based upon guest behaviour (described in
> > > > > docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> > > > > 
> > > > > >   1) Receive the interrupt and ack it
> > > > > >   2) Handle the current event timer
> > > > > >   3) Set the next event timer
> > > > > >   4) EOI the interrupt
> > > > > > 
> > > > > > It's unlikely possible to reinject another interrupt before
> > > > > 
> > > > > I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> > > > > not sure if that is what you meant.
> > > > > 
> > > > > > the previous one is EOIed because the next deadline is shorter than the time
> > > > > > to execute code until EOI it.
> > > > > 
> > > > > If we get into this situation once is there any danger that we will get
> > > > > into it repeatedly and overflow the count?
> > > > > 
> > > > > Overall I'm not convinced this is the right approach to get the
> > > > > behaviour we want. Isn't this interrupt level triggered, with the level
> > > > > being determined by a comparison of two registers? IOW can't we
> > > > > determine whether to retrigger the interrupt or not by examining the
> > > > > state of our emulated versions of those registers? A generic mechanism
> > > > > to callback into the appropriate emulator on EOI plus a little bit of
> > > > > logic in the vtimer code is all it ought to take.
> > > > 
> > > > AFAICT this what could happen:
> > > > 
> > > > - vtimer fires
> > > > - xen mask the vtimer
> > > > - xen adds the vtimer to the LR for the guest
> > > > - xen EOIs the vtimer
> > > 
> > > This step is Xen deprioritises the interrupt (by writing to the GICD_DIR
> > > register)...
> > > 
> > > > - the guest receive the vtimer interrupt
> > > > - the guest set the next deadline in the past
> > > > - the guest enables the vtimer
> > > > ## an unexpected vtimer interrupt is received by Xen but the current
> > > > ## one is still being serviced 
> > > > - the guest eoi the vtimer
> > > 
> > > ... and the actual Xen EOI only happens here in response to the
> > > maintenance interrupt resulting from the guests EOI.
> > > 
> > > (or maybe I've misunderstood what you mean by "EOI the vtimer")
> > 
> > The vtimer is a Xen irq that injects an irq into the guest from the Xen
> > interrupt handler. It's not a guest irq.
> > See xen/arch/arm/time.c:vtimer_interrupt.
> 
> OK, so what does it mean to "EOI" that timer?
 
By "xen EOIs the vtimer" I meant Xen EOIs the vtimer interrupt in the
real hardware.
By "the guest eoi the vtimer" I meant the guest EOIs the virtual
interrupt that we injected into the guest.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:23             ` Stefano Stabellini
@ 2013-06-26 11:41               ` Ian Campbell
  2013-06-26 11:50                 ` Stefano Stabellini
  0 siblings, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 11:41 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, Stefano Stabellini, patches, xen-devel

On Wed, 2013-06-26 at 12:23 +0100, Stefano Stabellini wrote:
> On Wed, 26 Jun 2013, Ian Campbell wrote:
> > On Wed, 2013-06-26 at 12:08 +0100, Stefano Stabellini wrote:
> > > On Wed, 26 Jun 2013, Ian Campbell wrote:
> > > > On Tue, 2013-06-25 at 17:58 +0100, Stefano Stabellini wrote:
> > > > > On Tue, 25 Jun 2013, Ian Campbell wrote:
> > > > > > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > > > > > > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > > > > > > 
> > > > > > > For guest's timers (both virtual and physical), Xen will inject virtual
> > > > > > > interrupt. Linux handles timer interrupt as:
> > > > > > 
> > > > > > We should be wary of developing things based on the way which Linux
> > > > > > happens to do things. On x86 we have several time modes, which can be
> > > > > > selected based upon guest behaviour (described in
> > > > > > docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> > > > > > 
> > > > > > >   1) Receive the interrupt and ack it
> > > > > > >   2) Handle the current event timer
> > > > > > >   3) Set the next event timer
> > > > > > >   4) EOI the interrupt
> > > > > > > 
> > > > > > > It's unlikely possible to reinject another interrupt before
> > > > > > 
> > > > > > I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> > > > > > not sure if that is what you meant.
> > > > > > 
> > > > > > > the previous one is EOIed because the next deadline is shorter than the time
> > > > > > > to execute code until EOI it.
> > > > > > 
> > > > > > If we get into this situation once is there any danger that we will get
> > > > > > into it repeatedly and overflow the count?
> > > > > > 
> > > > > > Overall I'm not convinced this is the right approach to get the
> > > > > > behaviour we want. Isn't this interrupt level triggered, with the level
> > > > > > being determined by a comparison of two registers? IOW can't we
> > > > > > determine whether to retrigger the interrupt or not by examining the
> > > > > > state of our emulated versions of those registers? A generic mechanism
> > > > > > to callback into the appropriate emulator on EOI plus a little bit of
> > > > > > logic in the vtimer code is all it ought to take.
> > > > > 
> > > > > AFAICT this what could happen:
> > > > > 
> > > > > - vtimer fires
> > > > > - xen mask the vtimer
> > > > > - xen adds the vtimer to the LR for the guest
> > > > > - xen EOIs the vtimer
> > > > 
> > > > This step is Xen deprioritises the interrupt (by writing to the GICD_DIR
> > > > register)...
> > > > 
> > > > > - the guest receive the vtimer interrupt
> > > > > - the guest set the next deadline in the past
> > > > > - the guest enables the vtimer
> > > > > ## an unexpected vtimer interrupt is received by Xen but the current
> > > > > ## one is still being serviced 
> > > > > - the guest eoi the vtimer
> > > > 
> > > > ... and the actual Xen EOI only happens here in response to the
> > > > maintenance interrupt resulting from the guests EOI.
> > > > 
> > > > (or maybe I've misunderstood what you mean by "EOI the vtimer")
> > > 
> > > The vtimer is a Xen irq that injects an irq into the guest from the Xen
> > > interrupt handler. It's not a guest irq.
> > > See xen/arch/arm/time.c:vtimer_interrupt.
> > 
> > OK, so what does it mean to "EOI" that timer?
>  
> By "xen EOIs the vtimer" I meant Xen EOIs the vtimer interrupt in the
> real hardware.

Oh right, for some reason I thought this was driven off Xen timer
infrastructure, rather than being an actual interrupt.

In that case my comments about deprioritisation and actual EOI happening
later are correct, aren't they?

> By "the guest eoi the vtimer" I meant the guest EOIs the virtual
> interrupt that we injected into the guest.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:41               ` Ian Campbell
@ 2013-06-26 11:50                 ` Stefano Stabellini
  2013-06-26 11:57                   ` Ian Campbell
  0 siblings, 1 reply; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-26 11:50 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Julien Grall, xen-devel, patches,
	Stefano Stabellini

On Wed, 26 Jun 2013, Ian Campbell wrote:
> On Wed, 2013-06-26 at 12:23 +0100, Stefano Stabellini wrote:
> > On Wed, 26 Jun 2013, Ian Campbell wrote:
> > > On Wed, 2013-06-26 at 12:08 +0100, Stefano Stabellini wrote:
> > > > On Wed, 26 Jun 2013, Ian Campbell wrote:
> > > > > On Tue, 2013-06-25 at 17:58 +0100, Stefano Stabellini wrote:
> > > > > > On Tue, 25 Jun 2013, Ian Campbell wrote:
> > > > > > > On Tue, 2013-06-25 at 00:04 +0100, Julien Grall wrote:
> > > > > > > > From: Stefano Stabellini <stefano.stabellini@citrix.com>
> > > > > > > > 
> > > > > > > > For guest's timers (both virtual and physical), Xen will inject virtual
> > > > > > > > interrupt. Linux handles timer interrupt as:
> > > > > > > 
> > > > > > > We should be wary of developing things based on the way which Linux
> > > > > > > happens to do things. On x86 we have several time modes, which can be
> > > > > > > selected based upon guest behaviour (described in
> > > > > > > docs/man/xl.cfg.pod.5). Do we need to do something similar here?
> > > > > > > 
> > > > > > > >   1) Receive the interrupt and ack it
> > > > > > > >   2) Handle the current event timer
> > > > > > > >   3) Set the next event timer
> > > > > > > >   4) EOI the interrupt
> > > > > > > > 
> > > > > > > > It's unlikely possible to reinject another interrupt before
> > > > > > > 
> > > > > > > I can't parse this sentence. "unlikely to be possible" perhaps? but I'm
> > > > > > > not sure if that is what you meant.
> > > > > > > 
> > > > > > > > the previous one is EOIed because the next deadline is shorter than the time
> > > > > > > > to execute code until EOI it.
> > > > > > > 
> > > > > > > If we get into this situation once is there any danger that we will get
> > > > > > > into it repeatedly and overflow the count?
> > > > > > > 
> > > > > > > Overall I'm not convinced this is the right approach to get the
> > > > > > > behaviour we want. Isn't this interrupt level triggered, with the level
> > > > > > > being determined by a comparison of two registers? IOW can't we
> > > > > > > determine whether to retrigger the interrupt or not by examining the
> > > > > > > state of our emulated versions of those registers? A generic mechanism
> > > > > > > to callback into the appropriate emulator on EOI plus a little bit of
> > > > > > > logic in the vtimer code is all it ought to take.
> > > > > > 
> > > > > > AFAICT this what could happen:
> > > > > > 
> > > > > > - vtimer fires
> > > > > > - xen mask the vtimer
> > > > > > - xen adds the vtimer to the LR for the guest
> > > > > > - xen EOIs the vtimer
> > > > > 
> > > > > This step is Xen deprioritises the interrupt (by writing to the GICD_DIR
> > > > > register)...
> > > > > 
> > > > > > - the guest receive the vtimer interrupt
> > > > > > - the guest set the next deadline in the past
> > > > > > - the guest enables the vtimer
> > > > > > ## an unexpected vtimer interrupt is received by Xen but the current
> > > > > > ## one is still being serviced 
> > > > > > - the guest eoi the vtimer
> > > > > 
> > > > > ... and the actual Xen EOI only happens here in response to the
> > > > > maintenance interrupt resulting from the guests EOI.
> > > > > 
> > > > > (or maybe I've misunderstood what you mean by "EOI the vtimer")
> > > > 
> > > > The vtimer is a Xen irq that injects an irq into the guest from the Xen
> > > > interrupt handler. It's not a guest irq.
> > > > See xen/arch/arm/time.c:vtimer_interrupt.
> > > 
> > > OK, so what does it mean to "EOI" that timer?
> >  
> > By "xen EOIs the vtimer" I meant Xen EOIs the vtimer interrupt in the
> > real hardware.
> 
> Oh right, for some reason I thought this was driven off Xen timer
> infrastructure, rather than being an actual interrupt.
> 
> In that case my comments about deprioritisation and actual EOI happening
> later are correct, aren't they?

No, they are not. This is the full sequence of events, including
deprioritization and EOI:

- the vtimer interrupt fires
- xen deprioritizes the vtimer interrupt
- xen masks the vtimer interrupt
- xen adds the vtimer interrupt to the LR for the guest
- xen EOIs the vtimer interrupt
- the guest receives the vtimer interrupt
- the guest deprioritizes the vtimer interrupt
- the guest set the next deadline in the past
- the guest enables the vtimer
## an unexpected vtimer interrupt is received by Xen but the current
## one is still being serviced 
- the guest EOIs the vtimer interrupt

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:50                 ` Stefano Stabellini
@ 2013-06-26 11:57                   ` Ian Campbell
  2013-06-26 14:02                     ` Stefano Stabellini
  0 siblings, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-06-26 11:57 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Julien Grall, Stefano Stabellini, patches, xen-devel

On Wed, 2013-06-26 at 12:50 +0100, Stefano Stabellini wrote:
> On Wed, 26 Jun 2013, Ian Campbell wrote:

> > In that case my comments about deprioritisation and actual EOI happening
> > later are correct, aren't they?
> 
> No, they are not. This is the full sequence of events, including
> deprioritization and EOI:
> 
> - the vtimer interrupt fires
> - xen deprioritizes the vtimer interrupt
> - xen masks the vtimer interrupt
> - xen adds the vtimer interrupt to the LR for the guest
> - xen EOIs the vtimer interrupt
> - the guest receives the vtimer interrupt
> - the guest deprioritizes the vtimer interrupt
> - the guest set the next deadline in the past
> - the guest enables the vtimer
> ## an unexpected vtimer interrupt is received by Xen but the current
> ## one is still being serviced 
> - the guest EOIs the vtimer interrupt

Is this particular to the handling of the vtimer interrupt? In the
normal case an interrupt which is injected into the guest isn't EOIed by
Xen until the maintenance interrupt, isn't it? But the vtimer is special
because it isn't routed to the guest even though we do so via an
orthogonal mechanism?

Perhaps the solution here is a third type of interrupt alongside
"for-xen" and "for-a-specific-guest" which is "for-current-guest"?

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-26 10:55       ` Ian Campbell
@ 2013-06-26 13:03         ` Julien Grall
  0 siblings, 0 replies; 46+ messages in thread
From: Julien Grall @ 2013-06-26 13:03 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Julien Grall, Stefano.Stabellini, patches, xen-devel

On 06/26/2013 11:55 AM, Ian Campbell wrote:

> On Tue, 2013-06-25 at 18:38 +0100, Julien Grall wrote:
>>>> @@ -719,11 +731,18 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
>>>>      unsigned long flags;
>>>>      int retval;
>>>>      bool_t level;
>>>> +    struct pending_irq *p;
>>>> +    /* XXX: handler other VCPU than 0 */
>>>
>>> That should be something like "XXX: handle VCPUs other than 0".
>>>
>>> This only matters if we can route SGIs or PPIs to the guest though I
>>> think, since they are the only banked interrupts? For SPIs we actually
>>> want to actively avoid doing this multiple times, don't we?
>>
>>
>> Yes. Here the VCPU is only used to retrieved the struct pending_irq.
> 
> Which is per-CPU for PPIs and SGIs. Do we not care about PPIs here?

I don't see reason to route physical PPIs. Is it possible to have a
device (other than the timer and the GIC) with PPIs?

>>>
>>> For the banked interrupts I think we just need a loop here, or for
>>> p->desc to not be part of the pending_irq struct but actually part of
>>> some separate per-domain datastructure, since it would be very weird to
>>> have a domain where the PPIs differed between CPUs. (I'm not sure if
>>> that is allowed by the hardware, I bet it is, but it would be a
>>> pathological case IMHO...).
>>
>>> I think a perdomain irq_desc * array is probably the right answer,
>>> unless someone can convincingly argue that PPI routing differing between
>>> VCPUs in a guest is a useful thing...
>>
>>
>> Until now, I didn't see PPIs on other devices than the arch timers and
>> the GIC. I don't know if it's possible, but pending_irq are also banked
>> for PPIs, so it's not an issue.
>>
>> The issue is how do we link the physical PPI to the virtual PPI? Is a
>> 1:1 mapping. How does Xen handle PPI when a it is coming on VCPUs which
>> doesn't handle it (for instance a domU)?
> 
> How do you mean?


My sentence wasn't clear.

As for the arch timer, which is using PPIs, routing theses interrupts
require some code to support the device in Xen, mainly to save/restore
the context when the VCPU is moved.

Can we assume that Xen will never route PPIs to a guest?

-- 
Julien

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 2/5] xen/arm: Keep count of inflight interrupts
  2013-06-26 11:57                   ` Ian Campbell
@ 2013-06-26 14:02                     ` Stefano Stabellini
  0 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-06-26 14:02 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Julien Grall, xen-devel, patches,
	Stefano Stabellini

On Wed, 26 Jun 2013, Ian Campbell wrote:
> On Wed, 2013-06-26 at 12:50 +0100, Stefano Stabellini wrote:
> > On Wed, 26 Jun 2013, Ian Campbell wrote:
> 
> > > In that case my comments about deprioritisation and actual EOI happening
> > > later are correct, aren't they?
> > 
> > No, they are not. This is the full sequence of events, including
> > deprioritization and EOI:
> > 
> > - the vtimer interrupt fires
> > - xen deprioritizes the vtimer interrupt
> > - xen masks the vtimer interrupt
> > - xen adds the vtimer interrupt to the LR for the guest
> > - xen EOIs the vtimer interrupt
> > - the guest receives the vtimer interrupt
> > - the guest deprioritizes the vtimer interrupt
> > - the guest set the next deadline in the past
> > - the guest enables the vtimer
> > ## an unexpected vtimer interrupt is received by Xen but the current
> > ## one is still being serviced 
> > - the guest EOIs the vtimer interrupt
> 
> Is this particular to the handling of the vtimer interrupt? 

Yes


> In the
> normal case an interrupt which is injected into the guest isn't EOIed by
> Xen until the maintenance interrupt, isn't it?

Right


> But the vtimer is special
> because it isn't routed to the guest even though we do so via an
> orthogonal mechanism?

Yes


> Perhaps the solution here is a third type of interrupt alongside
> "for-xen" and "for-a-specific-guest" which is "for-current-guest"?

We could try but I did implement this strategy first and I ran into some
serious problems. It could have been because the vtimer emulation in the
FastModel had issues.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/5] Fix multiple issues with the interrupts on ARM
  2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
                   ` (4 preceding siblings ...)
  2013-06-24 23:04 ` [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks Julien Grall
@ 2013-07-31 13:08 ` Andrii Anisov
  2013-07-31 14:00   ` Julien Grall
  5 siblings, 1 reply; 46+ messages in thread
From: Andrii Anisov @ 2013-07-31 13:08 UTC (permalink / raw)
  To: Julien Grall
  Cc: Julien Grall, patches, Ian Campbell, Stefano Stabellini,
	xen-devel@lists.xen.org


[-- Attachment #1.1: Type: text/plain, Size: 1830 bytes --]

Hello,

I wonder if this patchset going to be revised and applied?
It appeared pretty useful for us.
We are experimenting with an Android as an only DomU. For sure it was done
with giving to Android direct access to iomem and delivering some hw irq's
to DomU.

Eventually we had showstopper issue with hw irqs delivery to DomU kernel.
At some moment some IRQs was not delivered to DomU. The issue disappeared
with applying this patchset.

Sincerely,
Andrii Anisov.


On Tue, Jun 25, 2013 at 2:04 AM, Julien Grall <julien.grall@linaro.org>wrote:

> Hello,
>
> This patch series aims to fix different issues on Xen on ARM with the
> arndale and the versatile express:
>   - Handle correctly one shot IRQ (fixed by patch 3)
>   - Make timers work with heavy load (fixed by patch 2)
>   - Make ethernet card works on the TC2 (fixed by patch 5)
>
> Some of these patches (2 and 5) are proof of concept. I would be happy if
> someone find a better solution :).
>
> Cheers,
>
> Julien Grall (4):
>   xen/arm: Physical IRQ is not always equal to virtual IRQ
>   xen/arm: Don't reinject the IRQ if it's already in LRs
>   xen/arm: Rename gic_irq_{startup,shutdown} to gic_irq_{mask,unmask}
>   xen/arm: Only enable physical IRQs when the guest asks
>
> Stefano Stabellini (1):
>   xen/arm: Keep count of inflight interrupts
>
>  xen/arch/arm/domain_build.c  |   14 +++++
>  xen/arch/arm/gic.c           |  119
> ++++++++++++++++++++++++++++++------------
>  xen/arch/arm/vgic.c          |   11 ++--
>  xen/include/asm-arm/domain.h |    2 +
>  xen/include/asm-arm/gic.h    |    7 +++
>  xen/include/asm-arm/irq.h    |    6 +++
>  6 files changed, 122 insertions(+), 37 deletions(-)
>
> --
> 1.7.10.4
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
>

[-- Attachment #1.2: Type: text/html, Size: 2650 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/5] Fix multiple issues with the interrupts on ARM
  2013-07-31 13:08 ` [PATCH 0/5] Fix multiple issues with the interrupts on ARM Andrii Anisov
@ 2013-07-31 14:00   ` Julien Grall
  0 siblings, 0 replies; 46+ messages in thread
From: Julien Grall @ 2013-07-31 14:00 UTC (permalink / raw)
  To: Andrii Anisov
  Cc: patches, Ian Campbell, Stefano Stabellini,
	xen-devel@lists.xen.org

On 07/31/2013 02:08 PM, Andrii Anisov wrote:
> Hello,

Hi,

> I wonder if this patchset going to be revised and applied?

I will try to send as soon as possible a new version.

-- 
Julien

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-06-25 16:19   ` Stefano Stabellini
  2013-06-25 16:55     ` Julien Grall
@ 2013-12-02 17:26     ` Ian Campbell
  2013-12-02 17:37       ` Stefano Stabellini
  1 sibling, 1 reply; 46+ messages in thread
From: Ian Campbell @ 2013-12-02 17:26 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Julien Grall, Julien Grall, Andre Przywara, patches, xen-devel

On Tue, 2013-06-25 at 17:19 +0100, Stefano Stabellini wrote:

We really need to get something along these lines into 4.4, as a bug fix
I think. It seems from the below that the issue which this patch tries
to address was actually observed on vexpress, although it doesn't seem
likely to be specific to any platform.


> > @@ -744,6 +763,8 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
> >          goto out;
> >      }
> >  
> > +    p->desc = desc;
> > +
> >  out:
> >      spin_unlock(&gic.lock);
> >      spin_unlock_irqrestore(&desc->lock, flags);

> > @@ -685,10 +688,6 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
> >  
> >      n->irq = irq;
> >      n->priority = priority;
> > -    if (!virtual)
> > -        n->desc = irq_to_desc(irq);
> > -    else
> > -        n->desc = NULL;
> >  
> >      /* the irq is enabled */
> >      if ( rank->ienable & (1 << (irq % 32)) )
> 
> I don't quite understand why are you changing where the "desc"
> assignement is done.
> If it is a cleanup you shouldn't mix it with a patch like this that is
> supposed to fix a specific issue. Otherwise please explain why you need
> this change.

Was this because gic_router_irq_to_guest has set p->desc as shown above
and therefore the feeling was that it wasn't required here?

I don't think this can be right though, gic_route_irq_to_guest is only
called for SPIs routed via the DTB or the platform specific mapping
hook. In particular it is never called for the various PPIs, such as the
timer PPI and the evtchn PPI.

As it happens the existing PPIs which we pass to the guest are a
virtual, and perhaps we can already rely on n->desc==NULL already in
that case.

TBH, the existing code here is very weird, n->desc should have been set
(possibly on all vcpus) at the time the interrupt was configured/routed,
it certainly shouldn't be updated on every injection. In practice I
think it only happened on the first and was static thereafter so this is
just an odd form of lazy initialisation. If it is in fact changing on
each injection then I've no idea what this code is doing ;-)

Ian.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks
  2013-12-02 17:26     ` Ian Campbell
@ 2013-12-02 17:37       ` Stefano Stabellini
  0 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2013-12-02 17:37 UTC (permalink / raw)
  To: Ian Campbell
  Cc: patches, Julien Grall, Andre Przywara, xen-devel, Julien Grall,
	Stefano Stabellini

On Mon, 2 Dec 2013, Ian Campbell wrote:
> On Tue, 2013-06-25 at 17:19 +0100, Stefano Stabellini wrote:
> 
> We really need to get something along these lines into 4.4, as a bug fix
> I think. It seems from the below that the issue which this patch tries
> to address was actually observed on vexpress, although it doesn't seem
> likely to be specific to any platform.

FYI I am reworking this series using a different approach

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2013-12-02 17:37 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-24 23:04 [PATCH 0/5] Fix multiple issues with the interrupts on ARM Julien Grall
2013-06-24 23:04 ` [PATCH 1/5] xen/arm: Physical IRQ is not always equal to virtual IRQ Julien Grall
2013-06-25 13:16   ` Stefano Stabellini
2013-06-25 15:21     ` Julien Grall
2013-06-25 16:06       ` Ian Campbell
2013-06-24 23:04 ` [PATCH 2/5] xen/arm: Keep count of inflight interrupts Julien Grall
2013-06-25 16:12   ` Ian Campbell
2013-06-25 16:58     ` Stefano Stabellini
2013-06-25 17:46       ` Julien Grall
2013-06-25 18:38         ` Stefano Stabellini
2013-06-26 10:59           ` Ian Campbell
2013-06-26 11:10             ` Stefano Stabellini
2013-06-26 11:16               ` Ian Campbell
2013-06-26 10:58       ` Ian Campbell
2013-06-26 11:08         ` Stefano Stabellini
2013-06-26 11:15           ` Ian Campbell
2013-06-26 11:23             ` Stefano Stabellini
2013-06-26 11:41               ` Ian Campbell
2013-06-26 11:50                 ` Stefano Stabellini
2013-06-26 11:57                   ` Ian Campbell
2013-06-26 14:02                     ` Stefano Stabellini
2013-06-24 23:04 ` [PATCH 3/5] xen/arm: Don't reinject the IRQ if it's already in LRs Julien Grall
2013-06-25 13:24   ` Stefano Stabellini
2013-06-25 13:55     ` Julien Grall
2013-06-25 16:36       ` Stefano Stabellini
2013-06-25 16:46         ` Ian Campbell
2013-06-25 17:05           ` Stefano Stabellini
2013-06-26 10:53             ` Ian Campbell
2013-06-26 11:19               ` Stefano Stabellini
2013-06-25 16:48         ` Julien Grall
2013-06-25 16:59           ` Stefano Stabellini
2013-06-25 16:14     ` Ian Campbell
2013-06-24 23:04 ` [PATCH 4/5] xen/arm: Rename gic_irq_{startup, shutdown} to gic_irq_{mask, unmask} Julien Grall
2013-06-24 23:04 ` [PATCH 5/5] xen/arm: Only enable physical IRQs when the guest asks Julien Grall
2013-06-25 16:19   ` Stefano Stabellini
2013-06-25 16:55     ` Julien Grall
2013-06-25 17:07       ` Stefano Stabellini
2013-12-02 17:26     ` Ian Campbell
2013-12-02 17:37       ` Stefano Stabellini
2013-06-25 16:28   ` Ian Campbell
2013-06-25 17:38     ` Julien Grall
2013-06-25 18:27       ` Stefano Stabellini
2013-06-26 10:55       ` Ian Campbell
2013-06-26 13:03         ` Julien Grall
2013-07-31 13:08 ` [PATCH 0/5] Fix multiple issues with the interrupts on ARM Andrii Anisov
2013-07-31 14:00   ` Julien Grall

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).