xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] arm: support fewer LR registers than virtual irqs
@ 2012-02-15 14:03 Stefano Stabellini
  2012-02-15 14:03 ` [PATCH] arm: replace list_del and INIT_LIST_HEAD with list_del_init Stefano Stabellini
  2012-02-17 12:46 ` [PATCH v3] arm: support fewer LR registers than virtual irqs Ian Campbell
  0 siblings, 2 replies; 8+ messages in thread
From: Stefano Stabellini @ 2012-02-15 14:03 UTC (permalink / raw)
  To: xen-devel; +Cc: Stefano Stabellini, Ian.Campbell, david.vrabel

If the vgic needs to inject a virtual irq into the guest, but no free
LR registers are available, add the irq to a list and return.
Whenever an LR register becomes available we add the queued irq to it
and remove it from the list.
We use the gic lock to protect the list and the bitmask.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 xen/arch/arm/gic.c           |   61 ++++++++++++++++++++++++++++++++++++++---
 xen/include/asm-arm/domain.h |    1 +
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index adc10bb..520a400 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -25,6 +25,7 @@
 #include <xen/sched.h>
 #include <xen/errno.h>
 #include <xen/softirq.h>
+#include <xen/list.h>
 #include <asm/p2m.h>
 #include <asm/domain.h>
 
@@ -45,6 +46,8 @@ static struct {
     unsigned int lines;
     unsigned int cpus;
     spinlock_t lock;
+    uint64_t lr_mask;
+    struct list_head lr_pending;
 } gic;
 
 irq_desc_t irq_desc[NR_IRQS];
@@ -247,6 +250,8 @@ static void __cpuinit gic_hyp_init(void)
 
     GICH[GICH_HCR] = GICH_HCR_EN;
     GICH[GICH_MISR] = GICH_MISR_EOI;
+    gic.lr_mask = 0ULL;
+    INIT_LIST_HEAD(&gic.lr_pending);
 }
 
 /* Set up the GIC */
@@ -345,16 +350,51 @@ int __init setup_irq(unsigned int irq, struct irqaction *new)
     return rc;
 }
 
-void gic_set_guest_irq(unsigned int virtual_irq,
+static inline void gic_set_lr(int lr, unsigned int virtual_irq,
         unsigned int state, unsigned int priority)
 {
-    BUG_ON(virtual_irq > nr_lrs);
-    GICH[GICH_LR + virtual_irq] = state |
+    BUG_ON(lr > nr_lrs);
+    GICH[GICH_LR + lr] = state |
         GICH_LR_MAINTENANCE_IRQ |
         ((priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
         ((virtual_irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
 }
 
+void gic_set_guest_irq(unsigned int virtual_irq,
+        unsigned int state, unsigned int priority)
+{
+    int i;
+    struct pending_irq *iter, *n;
+
+    spin_lock(&gic.lock);
+
+    if ( list_empty(&gic.lr_pending) )
+    {
+        for (i = 0; i < nr_lrs; i++) {
+            if (!test_and_set_bit(i, &gic.lr_mask))
+            {
+                gic_set_lr(i, virtual_irq, state, priority);
+                spin_unlock(&gic.lock);
+                return;
+            }
+        }
+    }
+
+    n = irq_to_pending(current, virtual_irq);
+    list_for_each_entry ( iter, &gic.lr_pending, lr_link )
+    {
+        if ( iter->priority < priority )
+        {
+            list_add_tail(&n->lr_link, &iter->lr_link);
+            spin_unlock(&gic.lock);
+            return;
+        }
+    }
+    list_add(&n->lr_link, &gic.lr_pending);
+    spin_unlock(&gic.lock);
+    return;
+}
+
 void gic_inject_irq_start(void)
 {
     uint32_t hcr;
@@ -435,13 +475,25 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
     uint32_t lr;
     uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
 
-    for ( i = 0; i < 64; i++ ) {
+    for ( i = 0; i < nr_lrs; i++ ) {
         if ( eisr & ((uint64_t)1 << i) ) {
             struct pending_irq *p;
 
+            spin_lock(&gic.lock);
             lr = GICH[GICH_LR + i];
             virq = lr & GICH_LR_VIRTUAL_MASK;
             GICH[GICH_LR + i] = 0;
+            clear_bit(i, &gic.lr_mask);
+
+            if ( !list_empty(gic.lr_pending.next) ) {
+                p = list_entry(gic.lr_pending.next, typeof(*p), lr_link);
+                gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
+                list_del_init(&p->lr_link);
+                set_bit(i, &gic.lr_mask);
+            } else {
+                gic_inject_irq_stop();
+            }
+            spin_unlock(&gic.lock);
 
             spin_lock(&current->arch.vgic.lock);
             p = irq_to_pending(current, virq);
@@ -449,7 +501,6 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
                 p->desc->status &= ~IRQ_INPROGRESS;
                 GICC[GICC_DIR] = virq;
             }
-            gic_inject_irq_stop();
             list_del(&p->link);
             INIT_LIST_HEAD(&p->link);
             cpu_raise_softirq(current->processor, VGIC_SOFTIRQ);
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 3372d14..75095ff 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -21,6 +21,7 @@ struct pending_irq
     struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */
     uint8_t priority;
     struct list_head link;
+    struct list_head lr_link;
 };
 
 struct arch_domain
-- 
1.7.2.5

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

end of thread, other threads:[~2012-02-29 17:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-15 14:03 [PATCH v3] arm: support fewer LR registers than virtual irqs Stefano Stabellini
2012-02-15 14:03 ` [PATCH] arm: replace list_del and INIT_LIST_HEAD with list_del_init Stefano Stabellini
2012-02-17 12:50   ` Ian Campbell
2012-02-23 14:55     ` Stefano Stabellini
2012-02-17 12:46 ` [PATCH v3] arm: support fewer LR registers than virtual irqs Ian Campbell
2012-02-23 15:45   ` Stefano Stabellini
2012-02-27 17:22     ` Ian Campbell
2012-02-29 17:18       ` Stefano Stabellini

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).