From: Vijaya Kumar K <vijaya.ku...@caviumnetworks.com>

Add support for handling ITS(LPI) interrupts.
The LPI interrupts are handled by physical ITS
driver.

nested LPI interrupt handling is not tested and
enabled.

Signed-off-by: Vijaya Kumar K <vijaya.ku...@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c  |   31 +++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c      |    8 ++++++--
 xen/arch/arm/gic.c         |   38 ++++++++++++++++++++++++++++++++++++--
 xen/arch/arm/irq.c         |   10 +++++++---
 xen/arch/arm/vgic-v3-its.c |   10 ++++++++++
 xen/arch/arm/vgic.c        |   14 ++++++++++----
 xen/include/asm-arm/gic.h  |    3 +++
 xen/include/asm-arm/irq.h  |    1 +
 8 files changed, 104 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index b2c3320..7adbee4 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -344,6 +344,37 @@ static const struct gic_its_hw_operations gic_its_ops = {
     .gic_guest_lpi_type  = &gic_guest_its_type,
 };
 
+void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs)
+{
+    struct domain *d;
+    struct irq_desc *desc = irq_to_desc(irqnr);
+
+    irq_enter();
+    spin_lock(&desc->lock);
+
+    if ( !desc->action )
+    {
+        printk("UNKNOWN LPI without handler\n");
+        goto err;
+    }
+
+    if ( desc->status & IRQ_GUEST )
+    {
+        d = irq_get_domain(desc);
+
+        desc->handler->end(desc);
+
+        desc->status |= IRQ_INPROGRESS;
+        desc->arch.eoi_cpu = smp_processor_id();
+
+        /* XXX: inject irq into all guest vcpus */
+        vgic_vcpu_inject_irq(d->vcpu[0], irqnr);
+    }
+err:
+    spin_unlock(&desc->lock);
+    irq_exit();
+}
+
 static u64 its_cmd_ptr_to_offset(struct its_node *its,
                                  struct its_cmd_block *ptr)
 {
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 02e71dd..b654535 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -848,9 +848,13 @@ static void gicv3_update_lr(int lr, const struct 
pending_irq *p,
 
     val =  (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp;
     val |= ((uint64_t)p->priority & 0xff) << GICH_LR_PRIORITY_SHIFT;
-    val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;
 
-   if ( p->desc != NULL )
+    if ( is_lpi(p->irq) )
+        val |= ((uint64_t)p->desc->virq & GICH_LR_VIRTUAL_MASK) << 
GICH_LR_VIRTUAL_SHIFT;
+    else
+        val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << 
GICH_LR_VIRTUAL_SHIFT;
+
+   if ( p->desc != NULL && !(is_lpi(p->irq)) )
        val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK)
                            << GICH_LR_PHYSICAL_SHIFT);
 
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index fb77387..c4d352a 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -34,6 +34,7 @@
 #include <asm/io.h>
 #include <asm/gic.h>
 #include <asm/vgic.h>
+#include <asm/gic-its.h>
 
 static void gic_restore_pending_irqs(struct vcpu *v);
 
@@ -134,6 +135,21 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const 
cpumask_t *cpu_mask,
     gic_set_irq_properties(desc, cpu_mask, priority);
 }
 
+void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
+                            const cpumask_t *cpu_mask, unsigned int priority)
+{
+    struct pending_irq *p;
+    ASSERT(spin_is_locked(&desc->lock));
+
+    desc->handler = gic_its_hw_ops->gic_guest_lpi_type;
+    set_bit(_IRQ_GUEST, &desc->status);
+
+     
+    /* TODO: do not assume delivery to vcpu0 */
+    p = irq_to_pending(d->vcpu[0], desc->irq);
+    p->desc = desc;
+}
+
 /* Program the GIC to route an interrupt to a guest
  *   - desc.lock must be held
  */
@@ -341,20 +357,33 @@ static void gic_update_one_lr(struct vcpu *v, int i)
     struct pending_irq *p;
     int irq;
     struct gic_lr lr_val;
+    uint32_t pirq;
 
     ASSERT(spin_is_locked(&v->arch.vgic.lock));
     ASSERT(!local_irq_is_enabled());
 
     gic_hw_ops->read_lr(i, &lr_val);
     irq = lr_val.virq;
-    p = irq_to_pending(v, irq);
+
+    if ( is_lpi(irq) )
+    {
+        // Fetch corresponding plpi for vlpi
+        if ( vgic_its_get_pid(v, irq, &pirq) )
+            BUG();
+        p = irq_to_pending(v, pirq);
+        irq = pirq;
+    }
+    else
+    {
+        p = irq_to_pending(v, irq);
+    }
     if ( lr_val.state & GICH_LR_ACTIVE )
     {
         set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
         if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) &&
              test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status) )
         {
-            if ( p->desc == NULL )
+            if ( p->desc == NULL  || is_lpi(irq) )
             {
                  lr_val.state |= GICH_LR_PENDING;
                  gic_hw_ops->write_lr(i, &lr_val);
@@ -580,6 +609,11 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
     do  {
         /* Reading IRQ will ACK it */
         irq = gic_hw_ops->read_irq();
+        if ( is_lpi(irq) ) {
+            // TODO: Enable irqs?
+            its_handle_lpi(irq, regs);
+            continue;
+        }
 
         if ( likely(irq >= 16 && irq < 1021) )
         {
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 13583b4..52371be 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -276,7 +276,7 @@ void __cpuinit init_secondary_IRQ(void)
     BUG_ON(init_local_irq_data() < 0);
 }
 
-static inline struct domain *irq_get_domain(struct irq_desc *desc)
+struct domain *irq_get_domain(struct irq_desc *desc)
 {
     ASSERT(spin_is_locked(&desc->lock));
 
@@ -603,9 +603,13 @@ int route_irq_to_guest(struct domain *d, unsigned int irq,
     retval = __setup_irq(desc, 0, action);
     if ( retval )
         goto out;
+    if ( irq >= NR_LOCAL_IRQS && irq < NR_IRQS)
+        gic_route_irq_to_guest(d, desc, cpumask_of(smp_processor_id()),
+                               GIC_PRI_IRQ);
+    else
+        gic_route_lpi_to_guest(d, desc, cpumask_of(smp_processor_id()),
+                               GIC_PRI_IRQ);
 
-    gic_route_irq_to_guest(d, desc, cpumask_of(smp_processor_id()),
-                           GIC_PRI_IRQ);
     spin_unlock_irqrestore(&desc->lock, flags);
     return 0;
 
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index e7e587e..51b9614 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -1022,6 +1022,16 @@ int vgic_its_get_pid(struct vcpu *v, uint32_t vid, 
uint32_t *pid)
     return 1;
 }
 
+uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid)
+{
+    uint8_t priority;
+  
+    priority =  readb_relaxed(v->domain->arch.vits->lpi_prop_page + pid);
+    priority &= 0xfc;
+
+    return priority;
+}
+
 static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
 {
     uint32_t offset;
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 3bf9ef3..5571856 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -389,14 +389,20 @@ void vgic_clear_pending_irqs(struct vcpu *v)
 void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
 {
     uint8_t priority;
-    struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);
+    struct vgic_irq_rank *rank;
     struct pending_irq *iter, *n = irq_to_pending(v, irq);
     unsigned long flags;
     bool_t running;
 
-    vgic_lock_rank(v, rank, flags);
-    priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);
-    vgic_unlock_rank(v, rank, flags);
+    if ( irq < NR_GIC_LPI )
+    {
+        rank = vgic_rank_irq(v, irq);
+        vgic_lock_rank(v, rank, flags);
+        priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);
+        vgic_unlock_rank(v, rank, flags);
+    }
+    else
+        priority = vgic_its_get_priority(v, irq);
 
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 6f2237f..075f488 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -220,6 +220,7 @@ enum gic_version {
 
 extern enum gic_version gic_hw_version(void);
 extern void gic_eoi_irq(struct irq_desc *desc);
+extern void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs);
 /* Program the GIC to route an interrupt */
 extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t 
*cpu_mask,
                                  unsigned int priority);
@@ -356,6 +357,8 @@ void register_gic_ops(const struct gic_hw_operations *ops);
 void register_gic_its_ops(const struct gic_its_hw_operations *ops);
 int gic_make_node(const struct domain *d,const struct dt_device_node *node,
                   void *fdt);
+void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
+                            const cpumask_t *cpu_mask, unsigned int priority);
 
 #endif /* __ASSEMBLY__ */
 #endif
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 1159a6d..19246f9 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -51,6 +51,7 @@ int irq_set_spi_type(unsigned int spi, unsigned int type);
 int irq_set_desc_data(unsigned int irq, void *d);
 void *irq_get_desc_data(struct irq_desc *d);
 int platform_get_irq(const struct dt_device_node *device, int index);
+struct domain *irq_get_domain(struct irq_desc *desc);
 
 void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
 
-- 
1.7.9.5


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

Reply via email to