[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v9 3/7] xen/arm: Add support for GIC v3



From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>

Add support for GIC v3 specification System register access(SRE)
is enabled to access cpu and virtual interface registers based
on kernel GICv3 driver.

This patch adds only basic v3 support.
Does not support Interrupt Translation support (ITS)

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
v9: - ICC_IAR1_EL1 holds only IRQ number. Do not mask the value
    - Remove unused PIDR2 JEP register definitions
    - Change {GICR,GICD}_PIDR2_ARCH_REV_SHIFT to
      {GICR,GICD}_PIDR2_ARCH_REV_OFFSET
    - Remove duplicate MPIDR_LEVEL_BITS define
    - Implemented gicv3_set_irq_affinity similar to gic v2
    - make access to desc->status flags atomic
v8: - Introduced assembler aliases for GIC system registers
    - Removed usage of lib.h for adding size macro, instead used
      sizes.h
    - Renamed PIDR macros
    - Removed check for number of cpus in cluster in gicv3_send_sgi()
      and instead check is added in gicv3_populate_rdist()
    - Added comments and fixed coding style
    - Removed nr_lrs parameter in gicv3_{restore,save}_lrs()
    - Rename GICV3 compat strings.
v7: - Fixed wrong check for irq number in gicv3_set_irq_properties.
    - Introduced panic during cpu_init on wrong priority bits.
v6: - Added read_apr() to read ICH_APRn in GICv3
    - Added asserts
    - PIDR2 check for architecture valu
    - Remove update_cpu_lr_mask call
    - Changed parameter ordering for gicv3_send_sgi()
    - Save and restore ICC_SRE_EL1 registers
---
 xen/arch/arm/Makefile             |    1 +
 xen/arch/arm/gic-v3.c             | 1200 +++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/domain.h      |    8 +
 xen/include/asm-arm/gic.h         |   20 +
 xen/include/asm-arm/gic_v3_defs.h |  154 +++++
 xen/include/asm-arm/processor.h   |   13 +
 xen/include/asm-arm/sysregs.h     |   53 ++
 7 files changed, 1449 insertions(+)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index c13206f..33765f6 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -11,6 +11,7 @@ obj-y += domctl.o
 obj-y += sysctl.o
 obj-y += domain_build.o
 obj-y += gic.o gic-v2.o
+obj-$(CONFIG_ARM_64) += gic-v3.o
 obj-y += io.o
 obj-y += irq.o
 obj-y += kernel.o
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
new file mode 100644
index 0000000..6ccde02
--- /dev/null
+++ b/xen/arch/arm/gic-v3.c
@@ -0,0 +1,1200 @@
+/*
+ * xen/arch/arm/gic-v3.c
+ *
+ * ARM Generic Interrupt Controller support v3 version
+ * based on xen/arch/arm/gic-v2.c and kernel GICv3 driver
+ *
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Marc Zyngier <marc.zyngier@xxxxxxx>
+ *
+ * Vijaya Kumar K <vijaya.kumar@xxxxxxxxxxxxxxxxxx>, Cavium Inc
+ * ported to Xen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/cpu.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/errno.h>
+#include <xen/delay.h>
+#include <xen/device_tree.h>
+#include <xen/sizes.h>
+#include <asm/p2m.h>
+#include <asm/domain.h>
+#include <asm/io.h>
+#include <asm/device.h>
+#include <asm/gic.h>
+#include <asm/gic_v3_defs.h>
+
+struct rdist_region {
+    paddr_t base;
+    paddr_t size;
+    void __iomem *map_base;
+};
+
+/* Global state */
+static struct {
+    paddr_t dbase;            /* Address of distributor registers */
+    paddr_t dbase_size;
+    void __iomem *map_dbase;  /* Mapped address of distributor registers */
+    struct rdist_region *rdist_regions;
+    uint32_t  rdist_stride;
+    unsigned int rdist_count; /* Number of rdist regions count */
+    unsigned int nr_priorities;
+    spinlock_t lock;
+} gicv3;
+
+static struct gic_info gicv3_info;
+
+/* per-cpu re-distributor base */
+static DEFINE_PER_CPU(void __iomem*, rbase);
+
+#define GICD                   (gicv3.map_dbase)
+#define GICD_RDIST_BASE        (this_cpu(rbase))
+#define GICD_RDIST_SGI_BASE    (GICD_RDIST_BASE + SZ_64K)
+
+/*
+ * Saves all 16(Max) LR registers. Though number of LRs implemented
+ * is implementation specific.
+ */
+static inline void gicv3_save_lrs(struct vcpu *v)
+{
+    /* Fall through for all the cases */
+    switch ( gicv3_info.nr_lrs )
+    {
+    case 16:
+        v->arch.gic.v3.lr[15] = READ_SYSREG(ICH_LR15_EL2);
+    case 15:
+        v->arch.gic.v3.lr[14] = READ_SYSREG(ICH_LR14_EL2);
+    case 14:
+        v->arch.gic.v3.lr[13] = READ_SYSREG(ICH_LR13_EL2);
+    case 13:
+        v->arch.gic.v3.lr[12] = READ_SYSREG(ICH_LR12_EL2);
+    case 12:
+        v->arch.gic.v3.lr[11] = READ_SYSREG(ICH_LR11_EL2);
+    case 11:
+        v->arch.gic.v3.lr[10] = READ_SYSREG(ICH_LR10_EL2);
+    case 10:
+        v->arch.gic.v3.lr[9] = READ_SYSREG(ICH_LR9_EL2);
+    case 9:
+        v->arch.gic.v3.lr[8] = READ_SYSREG(ICH_LR8_EL2);
+    case 8:
+        v->arch.gic.v3.lr[7] = READ_SYSREG(ICH_LR7_EL2);
+    case 7:
+        v->arch.gic.v3.lr[6] = READ_SYSREG(ICH_LR6_EL2);
+    case 6:
+        v->arch.gic.v3.lr[5] = READ_SYSREG(ICH_LR5_EL2);
+    case 5:
+        v->arch.gic.v3.lr[4] = READ_SYSREG(ICH_LR4_EL2);
+    case 4:
+        v->arch.gic.v3.lr[3] = READ_SYSREG(ICH_LR3_EL2);
+    case 3:
+        v->arch.gic.v3.lr[2] = READ_SYSREG(ICH_LR2_EL2);
+    case 2:
+        v->arch.gic.v3.lr[1] = READ_SYSREG(ICH_LR1_EL2);
+    case 1:
+         v->arch.gic.v3.lr[0] = READ_SYSREG(ICH_LR0_EL2);
+         break;
+    default:
+         BUG();
+    }
+}
+
+/*
+ * Restores all 16(Max) LR registers. Though number of LRs implemented
+ * is implementation specific.
+ */
+static inline void gicv3_restore_lrs(const struct vcpu *v)
+{
+    /* Fall through for all the cases */
+    switch ( gicv3_info.nr_lrs )
+    {
+    case 16:
+        WRITE_SYSREG(v->arch.gic.v3.lr[15], ICH_LR15_EL2);
+    case 15:
+        WRITE_SYSREG(v->arch.gic.v3.lr[14], ICH_LR14_EL2);
+    case 14:
+        WRITE_SYSREG(v->arch.gic.v3.lr[13], ICH_LR13_EL2);
+    case 13:
+        WRITE_SYSREG(v->arch.gic.v3.lr[12], ICH_LR12_EL2);
+    case 12:
+        WRITE_SYSREG(v->arch.gic.v3.lr[11], ICH_LR11_EL2);
+    case 11:
+        WRITE_SYSREG(v->arch.gic.v3.lr[10], ICH_LR10_EL2);
+    case 10:
+        WRITE_SYSREG(v->arch.gic.v3.lr[9], ICH_LR9_EL2);
+    case 9:
+        WRITE_SYSREG(v->arch.gic.v3.lr[8], ICH_LR8_EL2);
+    case 8:
+        WRITE_SYSREG(v->arch.gic.v3.lr[7], ICH_LR7_EL2);
+    case 7:
+        WRITE_SYSREG(v->arch.gic.v3.lr[6], ICH_LR6_EL2);
+    case 6:
+        WRITE_SYSREG(v->arch.gic.v3.lr[5], ICH_LR5_EL2);
+    case 5:
+        WRITE_SYSREG(v->arch.gic.v3.lr[4], ICH_LR4_EL2);
+    case 4:
+        WRITE_SYSREG(v->arch.gic.v3.lr[3], ICH_LR3_EL2);
+    case 3:
+        WRITE_SYSREG(v->arch.gic.v3.lr[2], ICH_LR2_EL2);
+    case 2:
+        WRITE_SYSREG(v->arch.gic.v3.lr[1], ICH_LR1_EL2);
+    case 1:
+        WRITE_SYSREG(v->arch.gic.v3.lr[0], ICH_LR0_EL2);
+        break;
+    default:
+         BUG();
+    }
+}
+
+static uint64_t gicv3_ich_read_lr(int lr)
+{
+    switch ( lr )
+    {
+    case 0: return READ_SYSREG(ICH_LR0_EL2);
+    case 1: return READ_SYSREG(ICH_LR1_EL2);
+    case 2: return READ_SYSREG(ICH_LR2_EL2);
+    case 3: return READ_SYSREG(ICH_LR3_EL2);
+    case 4: return READ_SYSREG(ICH_LR4_EL2);
+    case 5: return READ_SYSREG(ICH_LR5_EL2);
+    case 6: return READ_SYSREG(ICH_LR6_EL2);
+    case 7: return READ_SYSREG(ICH_LR7_EL2);
+    case 8: return READ_SYSREG(ICH_LR8_EL2);
+    case 9: return READ_SYSREG(ICH_LR9_EL2);
+    case 10: return READ_SYSREG(ICH_LR10_EL2);
+    case 11: return READ_SYSREG(ICH_LR11_EL2);
+    case 12: return READ_SYSREG(ICH_LR12_EL2);
+    case 13: return READ_SYSREG(ICH_LR13_EL2);
+    case 14: return READ_SYSREG(ICH_LR14_EL2);
+    case 15: return READ_SYSREG(ICH_LR15_EL2);
+    default:
+        BUG();
+    }
+}
+
+static void gicv3_ich_write_lr(int lr, uint64_t val)
+{
+    switch ( lr )
+    {
+    case 0:
+        WRITE_SYSREG(val, ICH_LR0_EL2);
+        break;
+    case 1:
+        WRITE_SYSREG(val, ICH_LR1_EL2);
+        break;
+    case 2:
+        WRITE_SYSREG(val, ICH_LR2_EL2);
+        break;
+    case 3:
+        WRITE_SYSREG(val, ICH_LR3_EL2);
+        break;
+    case 4:
+        WRITE_SYSREG(val, ICH_LR4_EL2);
+        break;
+    case 5:
+        WRITE_SYSREG(val, ICH_LR5_EL2);
+        break;
+    case 6:
+        WRITE_SYSREG(val, ICH_LR6_EL2);
+        break;
+    case 7:
+        WRITE_SYSREG(val, ICH_LR7_EL2);
+        break;
+    case 8:
+        WRITE_SYSREG(val, ICH_LR8_EL2);
+        break;
+    case 9:
+        WRITE_SYSREG(val, ICH_LR9_EL2);
+        break;
+    case 10:
+        WRITE_SYSREG(val, ICH_LR10_EL2);
+        break;
+    case 11:
+        WRITE_SYSREG(val, ICH_LR11_EL2);
+        break;
+    case 12:
+        WRITE_SYSREG(val, ICH_LR12_EL2);
+        break;
+    case 13:
+        WRITE_SYSREG(val, ICH_LR13_EL2);
+        break;
+    case 14:
+        WRITE_SYSREG(val, ICH_LR14_EL2);
+        break;
+    case 15:
+        WRITE_SYSREG(val, ICH_LR15_EL2);
+        break;
+    default:
+        return;
+    }
+    isb();
+}
+
+/*
+ * System Register Enable (SRE). Enable to access CPU & Virtual
+ * interface registers as system registers in EL2
+ */
+static void gicv3_enable_sre(void)
+{
+    uint32_t val;
+
+    val = READ_SYSREG32(ICC_SRE_EL2);
+    val |= GICC_SRE_EL2_SRE | GICC_SRE_EL2_ENEL1;
+
+    WRITE_SYSREG32(val, ICC_SRE_EL2);
+    isb();
+}
+
+/* Wait for completion of a distributor change */
+static void gicv3_do_wait_for_rwp(void __iomem *base)
+{
+    uint32_t val;
+    bool_t timeout = 0;
+    s_time_t deadline = NOW() + MILLISECS(1000);
+
+    do {
+        val = readl_relaxed(base + GICD_CTLR);
+        if ( !(val & GICD_CTLR_RWP) )
+            break;
+        if ( NOW() > deadline )
+        {
+            timeout = 1;
+            break;
+        }
+        cpu_relax();
+        udelay(1);
+    } while ( 1 );
+
+    if ( timeout )
+        dprintk(XENLOG_ERR, "RWP timeout\n");
+}
+
+static void gicv3_dist_wait_for_rwp(void)
+{
+    gicv3_do_wait_for_rwp(GICD);
+}
+
+static void gicv3_redist_wait_for_rwp(void)
+{
+    gicv3_do_wait_for_rwp(GICD_RDIST_BASE);
+}
+
+static void gicv3_wait_for_rwp(int irq)
+{
+    if ( irq < NR_LOCAL_IRQS )
+         gicv3_redist_wait_for_rwp();
+    else
+         gicv3_dist_wait_for_rwp();
+}
+
+static unsigned int gicv3_get_cpu_from_mask(const cpumask_t *cpumask)
+{
+    unsigned int cpu;
+    cpumask_t possible_mask;
+
+    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
+    cpu = cpumask_any(&possible_mask);
+
+    return cpu;
+}
+
+static void restore_aprn_regs(const union gic_state_data *d)
+{
+    /* Write APRn register based on number of priorities
+       platform has implemented */
+    switch ( gicv3.nr_priorities )
+    {
+    case 7:
+        WRITE_SYSREG32(d->v3.apr0[2], ICH_AP0R2_EL2);
+        WRITE_SYSREG32(d->v3.apr1[2], ICH_AP1R2_EL2);
+        /* Fall through */
+    case 6:
+        WRITE_SYSREG32(d->v3.apr0[1], ICH_AP0R1_EL2);
+        WRITE_SYSREG32(d->v3.apr1[1], ICH_AP1R1_EL2);
+        /* Fall through */
+    case 5:
+        WRITE_SYSREG32(d->v3.apr0[0], ICH_AP0R0_EL2);
+        WRITE_SYSREG32(d->v3.apr1[0], ICH_AP1R0_EL2);
+        break;
+    default:
+        BUG();
+    }
+}
+
+static void save_aprn_regs(union gic_state_data *d)
+{
+    /* Read APRn register based on number of priorities
+       platform has implemented */
+    switch ( gicv3.nr_priorities )
+    {
+    case 7:
+        d->v3.apr0[2] = READ_SYSREG32(ICH_AP0R2_EL2);
+        d->v3.apr1[2] = READ_SYSREG32(ICH_AP1R2_EL2);
+        /* Fall through */
+    case 6:
+        d->v3.apr0[1] = READ_SYSREG32(ICH_AP0R1_EL2);
+        d->v3.apr1[1] = READ_SYSREG32(ICH_AP1R1_EL2);
+        /* Fall through */
+    case 5:
+        d->v3.apr0[0] = READ_SYSREG32(ICH_AP0R0_EL2);
+        d->v3.apr1[0] = READ_SYSREG32(ICH_AP1R0_EL2);
+        break;
+    default:
+        BUG();
+    }
+}
+
+/*
+ * As per section 4.8.17 of the GICv3 spec following
+ * registers are save and restored on guest swap
+ */
+static void gicv3_save_state(struct vcpu *v)
+{
+
+    /* No need for spinlocks here because interrupts are disabled around
+     * this call and it only accesses struct vcpu fields that cannot be
+     * accessed simultaneously by another pCPU.
+     *
+     * Make sure all stores to the GIC via the memory mapped interface
+     * are now visible to the system register interface
+     */
+    dsb(sy);
+    gicv3_save_lrs(v);
+    save_aprn_regs(&v->arch.gic);
+    v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2);
+    v->arch.gic.v3.sre_el1 = READ_SYSREG32(ICC_SRE_EL1);
+}
+
+static void gicv3_restore_state(const struct vcpu *v)
+{
+    WRITE_SYSREG32(v->arch.gic.v3.sre_el1, ICC_SRE_EL1);
+    WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2);
+    restore_aprn_regs(&v->arch.gic);
+    gicv3_restore_lrs(v);
+
+    /*
+     * Make sure all stores are visible the GIC
+     */
+    dsb(sy);
+}
+
+static void gicv3_dump_state(const struct vcpu *v)
+{
+    int i;
+
+    if ( v == current )
+    {
+        for ( i = 0; i < gicv3_info.nr_lrs; i++ )
+            printk("   HW_LR[%d]=%lx\n", i, gicv3_ich_read_lr(i));
+    }
+    else
+    {
+        for ( i = 0; i < gicv3_info.nr_lrs; i++ )
+            printk("   VCPU_LR[%d]=%lx\n", i, v->arch.gic.v3.lr[i]);
+    }
+}
+
+static void gicv3_poke_irq(struct irq_desc *irqd, u32 offset)
+{
+    u32 mask = 1 << (irqd->irq % 32);
+    void __iomem *base;
+
+    if ( irqd->irq < NR_GIC_LOCAL_IRQS )
+        base = GICD_RDIST_SGI_BASE;
+    else
+        base = GICD;
+
+    writel_relaxed(mask, base + offset + (irqd->irq / 32) * 4);
+    gicv3_wait_for_rwp(irqd->irq);
+}
+
+static void gicv3_unmask_irq(struct irq_desc *irqd)
+{
+    gicv3_poke_irq(irqd, GICD_ISENABLER);
+}
+
+static void gicv3_mask_irq(struct irq_desc *irqd)
+{
+    gicv3_poke_irq(irqd, GICD_ICENABLER);
+}
+
+static void gicv3_eoi_irq(struct irq_desc *irqd)
+{
+    /* Lower the priority */
+    WRITE_SYSREG32(irqd->irq, ICC_EOIR1_EL1);
+    isb();
+}
+
+static void gicv3_dir_irq(struct irq_desc *irqd)
+{
+    /* Deactivate */
+    WRITE_SYSREG32(irqd->irq, ICC_DIR_EL1);
+    isb();
+}
+
+static unsigned int gicv3_read_irq(void)
+{
+    return READ_SYSREG32(ICC_IAR1_EL1);
+}
+
+static inline uint64_t gicv3_mpidr_to_affinity(int cpu)
+{
+     uint64_t mpidr = cpu_logical_map(cpu);
+     return (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
+             MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+             MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
+             MPIDR_AFFINITY_LEVEL(mpidr, 0));
+}
+
+static void gicv3_set_irq_properties(struct irq_desc *desc,
+                                     const cpumask_t *cpu_mask,
+                                     unsigned int priority)
+{
+    uint32_t cfg, edgebit;
+    uint64_t affinity;
+    void __iomem *base;
+    unsigned int cpu = gicv3_get_cpu_from_mask(cpu_mask);
+    unsigned int irq = desc->irq;
+    unsigned int type = desc->arch.type;
+
+    /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */
+    ASSERT(irq >= NR_GIC_SGI);
+
+    spin_lock(&gicv3.lock);
+
+    if ( irq >= NR_GIC_LOCAL_IRQS)
+        base = GICD + GICD_ICFGR + (irq / 16) * 4;
+    else
+        base = GICD_RDIST_SGI_BASE + GICR_ICFGR1;
+
+    cfg = readl_relaxed(base);
+
+    edgebit = 2u << (2 * (irq % 16));
+    if ( type & DT_IRQ_TYPE_LEVEL_MASK )
+        cfg &= ~edgebit;
+    else if ( type & DT_IRQ_TYPE_EDGE_BOTH )
+        cfg |= edgebit;
+
+    writel_relaxed(cfg, base);
+
+    affinity = gicv3_mpidr_to_affinity(cpu);
+    /* Make sure we don't broadcast the interrupt */
+    affinity &= ~GICD_IROUTER_SPI_MODE_ANY;
+
+    if ( irq >= NR_GIC_LOCAL_IRQS )
+        writeq_relaxed(affinity, (GICD + GICD_IROUTER + irq * 8));
+
+    /* Set priority */
+    if ( irq < NR_GIC_LOCAL_IRQS )
+        writeb_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + irq);
+    else
+        writeb_relaxed(priority, GICD + GICD_IPRIORITYR + irq);
+
+    spin_unlock(&gicv3.lock);
+}
+
+static void __init gicv3_dist_init(void)
+{
+    uint32_t type;
+    uint32_t priority;
+    uint64_t affinity;
+    int i;
+
+    /* Disable the distributor */
+    writel_relaxed(0, GICD + GICD_CTLR);
+
+    type = readl_relaxed(GICD + GICD_TYPER);
+    gicv3_info.nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1);
+
+    printk("GICv3: %d lines, (IID %8.8x).\n",
+           gicv3_info.nr_lines, readl_relaxed(GICD + GICD_IIDR));
+
+    /* Default all global IRQs to level, active low */
+    for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 16 )
+        writel_relaxed(0, GICD + GICD_ICFGR + (i / 16) * 4);
+
+    /* Default priority for global interrupts */
+    for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 4 )
+    {
+        priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 |
+                    GIC_PRI_IRQ << 8 | GIC_PRI_IRQ);
+        writel_relaxed(priority, GICD + GICD_IPRIORITYR + (i / 4) * 4);
+    }
+
+    /* Disable all global interrupts */
+    for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 32 )
+        writel_relaxed(0xffffffff, GICD + GICD_ICENABLER + (i / 32) * 4);
+
+    gicv3_dist_wait_for_rwp();
+
+    /* Turn on the distributor */
+    writel_relaxed(GICD_CTL_ENABLE | GICD_CTLR_ARE_NS |
+                GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, GICD + GICD_CTLR);
+
+    /* Route all global IRQs to this CPU */
+    affinity = gicv3_mpidr_to_affinity(smp_processor_id());
+    /* Make sure we don't broadcast the interrupt */
+    affinity &= ~GICD_IROUTER_SPI_MODE_ANY;
+
+    for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i++ )
+        writeq_relaxed(affinity, GICD + GICD_IROUTER + i * 8);
+}
+
+static int gicv3_enable_redist(void)
+{
+    uint32_t val;
+    bool_t timeout = 0;
+    s_time_t deadline = NOW() + MILLISECS(1000);
+
+    /* Wake up this CPU redistributor */
+    val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
+    val &= ~GICR_WAKER_ProcessorSleep;
+    writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER);
+
+    do {
+        val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
+        if ( !(val & GICR_WAKER_ChildrenAsleep) )
+            break;
+        if ( NOW() > deadline )
+        {
+            timeout = 1;
+            break;
+        }
+        cpu_relax();
+        udelay(1);
+    } while ( timeout );
+
+    if ( timeout )
+    {
+        dprintk(XENLOG_ERR, "GICv3: Redist enable RWP timeout\n");
+        return 1;
+    }
+
+    return 0;
+}
+
+static int __init gicv3_populate_rdist(void)
+{
+    int i;
+    uint32_t aff;
+    uint32_t reg;
+    uint64_t typer;
+    uint64_t mpidr = cpu_logical_map(smp_processor_id());
+
+    /*
+     * If we ever get a cluster of more than 16 CPUs, just scream.
+     */
+    if ( (mpidr & 0xff) >= 16 )
+          dprintk(XENLOG_WARNING, "GICv3:Cluster with more than 16's cpus\n");
+
+    /*
+     * Convert affinity to a 32bit value that can be matched to GICR_TYPER
+     * bits [63:32]
+     */
+    aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
+           MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+           MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
+           MPIDR_AFFINITY_LEVEL(mpidr, 0));
+
+    for ( i = 0; i < gicv3.rdist_count; i++ )
+    {
+        void __iomem *ptr = gicv3.rdist_regions[i].map_base;
+
+        reg = readl_relaxed(ptr + GICR_PIDR2) & GICR_PIDR2_ARCH_REV_MASK;
+        if ( (reg >> GICR_PIDR2_ARCH_REV_SHIFT) != GICR_PIDR2_ARCH_GICV3 )
+        {
+            dprintk(XENLOG_ERR,
+                    "GICv3: No redistributor present @%"PRIpaddr"\n",
+                    gicv3.rdist_regions[i].base);
+            break;
+        }
+
+        do {
+            typer = readq_relaxed(ptr + GICR_TYPER);
+
+            if ( (typer >> 32) == aff )
+            {
+                this_cpu(rbase) = ptr;
+                printk("GICv3: CPU%d: Found redistributor in region %d @%p\n",
+                        smp_processor_id(), i, ptr);
+                return 0;
+            }
+            if ( gicv3.rdist_stride )
+                ptr += gicv3.rdist_stride;
+            else
+            {
+                ptr += SZ_64K * 2;
+                if ( typer & GICR_TYPER_VLPIS )
+                    ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
+            }
+
+        } while ( !(typer & GICR_TYPER_LAST) );
+    }
+
+    dprintk(XENLOG_ERR, "GICv3: CPU%d: mpidr 0x%x has no re-distributor!\n",
+            smp_processor_id(), cpu_logical_map(smp_processor_id()));
+
+    return -ENODEV;
+}
+
+static int __cpuinit gicv3_cpu_init(void)
+{
+    int i;
+    uint32_t priority;
+
+    /* Register ourselves with the rest of the world */
+    if ( gicv3_populate_rdist() )
+        return -ENODEV;
+
+    if ( gicv3_enable_redist() )
+        return -ENODEV;
+
+    /* Set priority on PPI and SGI interrupts */
+    priority = (GIC_PRI_IPI << 24 | GIC_PRI_IPI << 16 | GIC_PRI_IPI << 8 |
+                GIC_PRI_IPI);
+    for (i = 0; i < NR_GIC_SGI; i += 4)
+        writel_relaxed(priority,
+                GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4);
+
+    priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 | GIC_PRI_IRQ << 8 |
+                GIC_PRI_IRQ);
+    for (i = NR_GIC_SGI; i < NR_GIC_LOCAL_IRQS; i += 4)
+        writel_relaxed(priority,
+                GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4);
+
+    /*
+     * Disable all PPI interrupts, ensure all SGI interrupts are
+     * enabled.
+     */
+    writel_relaxed(0xffff0000, GICD_RDIST_SGI_BASE + GICR_ICENABLER0);
+    writel_relaxed(0x0000ffff, GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
+
+    gicv3_redist_wait_for_rwp();
+
+    /* Enable system registers */
+    gicv3_enable_sre();
+
+    /* No priority grouping */
+    WRITE_SYSREG32(0, ICC_BPR1_EL1);
+
+    /* Set priority mask register */
+    WRITE_SYSREG32(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
+
+    /* EOI drops priority too (mode 0) */
+    WRITE_SYSREG32(GICC_CTLR_EL1_EOImode_drop, ICC_CTLR_EL1);
+
+    /* Enable Group1 interrupts */
+    WRITE_SYSREG32(1, ICC_IGRPEN1_EL1);
+
+    /* Sync at once at the end of cpu interface configuration */
+    isb();
+
+    return 0;
+}
+
+static void gicv3_cpu_disable(void)
+{
+    WRITE_SYSREG32(0, ICC_CTLR_EL1);
+    isb();
+}
+
+static void __cpuinit gicv3_hyp_init(void)
+{
+    uint32_t vtr;
+
+    vtr = READ_SYSREG32(ICH_VTR_EL2);
+    gicv3_info.nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
+    gicv3.nr_priorities = ((vtr >> GICH_VTR_PRIBITS_SHIFT) &
+                          GICH_VTR_PRIBITS_MASK) + 1;
+
+    if ( !((gicv3.nr_priorities > 4) && (gicv3.nr_priorities < 8)) )
+        panic("GICv3: Invalid number of priority bits\n");
+
+    WRITE_SYSREG32(GICH_VMCR_EOI | GICH_VMCR_VENG1, ICH_VMCR_EL2);
+    WRITE_SYSREG32(GICH_HCR_EN, ICH_HCR_EL2);
+}
+
+/* Set up the per-CPU parts of the GIC for a secondary CPU */
+static int gicv3_secondary_cpu_init(void)
+{
+    int res;
+
+    spin_lock(&gicv3.lock);
+
+    res = gicv3_cpu_init();
+    gicv3_hyp_init();
+
+    spin_unlock(&gicv3.lock);
+
+    return res;
+}
+
+static void __cpuinit gicv3_hyp_disable(void)
+{
+    uint32_t hcr;
+
+    hcr = READ_SYSREG32(ICH_HCR_EL2);
+    hcr &= ~GICH_HCR_EN;
+    WRITE_SYSREG32(hcr, ICH_HCR_EL2);
+    isb();
+}
+
+static u16 gicv3_compute_target_list(int *base_cpu, const struct cpumask *mask,
+                                     uint64_t cluster_id)
+{
+    int cpu = *base_cpu;
+    uint64_t mpidr = cpu_logical_map(cpu);
+    u16 tlist = 0;
+
+    while ( cpu < nr_cpu_ids )
+    {
+        /*
+         * Assume that each cluster does not have more than 16 CPU's.
+         * Check is made during GICv3 initialization (gicv3_populate_rdist())
+         * on mpidr value for this. So skip this check here.
+         */
+        tlist |= 1 << (mpidr & 0xf);
+
+        cpu = cpumask_next(cpu, mask);
+        if ( cpu == nr_cpu_ids )
+        {
+            cpu--;
+            goto out;
+        }
+
+        mpidr = cpu_logical_map(cpu);
+        if ( cluster_id != (mpidr & ~MPIDR_AFF0_MASK) ) {
+            cpu--;
+            goto out;
+        }
+    }
+out:
+    *base_cpu = cpu;
+
+    return tlist;
+}
+
+static void gicv3_send_sgi(enum gic_sgi sgi, enum gic_sgi_mode mode,
+                           const cpumask_t *cpumask)
+{
+    int cpu = 0;
+    uint64_t val;
+
+    for_each_cpu(cpu, cpumask)
+    {
+        /* Mask lower 8 bits. It represent cpu in affinity level 0 */
+        uint64_t cluster_id = cpu_logical_map(cpu) & ~MPIDR_AFF0_MASK;
+        u16 tlist;
+
+        /* Get targetlist for the cluster to send SGI */
+        tlist = gicv3_compute_target_list(&cpu, cpumask, cluster_id);
+
+        /*
+         * Prepare affinity path of the cluster for which SGI is generated
+         * along with SGI number
+         */
+        val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48  |
+               MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32  |
+               sgi << 24                                  |
+               MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16  |
+               tlist);
+
+        WRITE_SYSREG(val, ICC_SGI1R_EL1);
+    }
+    /* Force above writes to ICC_SGI1R_EL1 */
+    isb();
+}
+
+/* Shut down the per-CPU GIC interface */
+static void gicv3_disable_interface(void)
+{
+    spin_lock(&gicv3.lock);
+
+    gicv3_cpu_disable();
+    gicv3_hyp_disable();
+
+    spin_unlock(&gicv3.lock);
+}
+
+static void gicv3_update_lr(int lr, const struct pending_irq *p,
+                            unsigned int state)
+{
+    uint64_t grp = GICH_LR_GRP1;
+    uint64_t val = 0;
+
+    BUG_ON(lr >= gicv3_info.nr_lrs);
+    BUG_ON(lr < 0);
+
+    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 )
+       val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK)
+                           << GICH_LR_PHYSICAL_SHIFT);
+
+    gicv3_ich_write_lr(lr, val);
+}
+
+static void gicv3_clear_lr(int lr)
+{
+    gicv3_ich_write_lr(lr, 0);
+}
+
+static void gicv3_read_lr(int lr, struct gic_lr *lr_reg)
+{
+    uint64_t lrv;
+
+    lrv = gicv3_ich_read_lr(lr);
+
+    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
+    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK;
+
+    lr_reg->priority  = (lrv >> GICH_LR_PRIORITY_SHIFT) & 
GICH_LR_PRIORITY_MASK;
+    lr_reg->state     = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
+    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
+    lr_reg->grp       = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
+}
+
+static void gicv3_write_lr(int lr_reg, const struct gic_lr *lr)
+{
+    uint64_t lrv = 0;
+
+    lrv = ( ((u64)(lr->pirq & GICH_LR_PHYSICAL_MASK) << 
GICH_LR_PHYSICAL_SHIFT)|
+        ((u64)(lr->virq & GICH_LR_VIRTUAL_MASK)  << GICH_LR_VIRTUAL_SHIFT) |
+        ((u64)(lr->priority & GICH_LR_PRIORITY_MASK) << 
GICH_LR_PRIORITY_SHIFT)|
+        ((u64)(lr->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) |
+        ((u64)(lr->hw_status & GICH_LR_HW_MASK) << GICH_LR_HW_SHIFT)  |
+        ((u64)(lr->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) );
+
+    gicv3_ich_write_lr(lr_reg, lrv);
+}
+
+static int gicv_v3_init(struct domain *d)
+{
+    int i;
+
+    /*
+     * Domain 0 gets the hardware address.
+     * Guests get the virtual platform layout.
+     */
+    if ( is_hardware_domain(d) )
+    {
+        d->arch.vgic.dbase = gicv3.dbase;
+        d->arch.vgic.dbase_size = gicv3.dbase_size;
+        for ( i = 0; i < gicv3.rdist_count; i++ )
+        {
+            d->arch.vgic.rbase[i] = gicv3.rdist_regions[i].base;
+            d->arch.vgic.rbase_size[i] = gicv3.rdist_regions[i].size;
+        }
+        d->arch.vgic.rdist_stride = gicv3.rdist_stride;
+        d->arch.vgic.rdist_count = gicv3.rdist_count;
+    }
+    else
+        d->arch.vgic.dbase = GUEST_GICD_BASE;
+
+    d->arch.vgic.nr_lines = 0;
+
+    return 0;
+}
+
+static void gicv3_hcr_status(uint32_t flag, bool_t status)
+{
+    uint32_t hcr;
+
+    hcr = READ_SYSREG32(ICH_HCR_EL2);
+    if ( status )
+        WRITE_SYSREG32(hcr | flag, ICH_HCR_EL2);
+    else
+        WRITE_SYSREG32(hcr & (~flag), ICH_HCR_EL2);
+    isb();
+}
+
+static unsigned int gicv3_read_vmcr_priority(void)
+{
+   return ((READ_SYSREG32(ICH_VMCR_EL2) >> GICH_VMCR_PRIORITY_SHIFT) &
+            GICH_VMCR_PRIORITY_MASK);
+}
+
+/* Only support reading GRP1 APRn registers */
+static unsigned int gicv3_read_apr(int apr_reg)
+{
+    switch ( apr_reg )
+    {
+    case 0:
+        ASSERT(gicv3.nr_priorities > 4 && gicv3.nr_priorities < 8);
+        return READ_SYSREG32(ICH_AP1R0_EL2);
+    case 1:
+        ASSERT(gicv3.nr_priorities > 5 && gicv3.nr_priorities < 8);
+        return READ_SYSREG32(ICH_AP1R1_EL2);
+    case 2:
+        ASSERT(gicv3.nr_priorities > 6 && gicv3.nr_priorities < 8);
+        return READ_SYSREG32(ICH_AP1R2_EL2);
+    default:
+        BUG();
+    }
+}
+
+static void gicv3_irq_enable(struct irq_desc *desc)
+{
+    unsigned long flags;
+
+    ASSERT(spin_is_locked(&desc->lock));
+
+    spin_lock_irqsave(&gicv3.lock, flags);
+    clear_bit(_IRQ_DISABLED, &desc->status);
+    dsb(sy);
+    /* Enable routing */
+    gicv3_unmask_irq(desc);
+    spin_unlock_irqrestore(&gicv3.lock, flags);
+}
+
+static void gicv3_irq_disable(struct irq_desc *desc)
+{
+    unsigned long flags;
+
+    ASSERT(spin_is_locked(&desc->lock));
+
+    spin_lock_irqsave(&gicv3.lock, flags);
+    /* Disable routing */
+    gicv3_mask_irq(desc);
+    set_bit(_IRQ_DISABLED, &desc->status);
+    spin_unlock_irqrestore(&gicv3.lock, flags);
+}
+
+static unsigned int gicv3_irq_startup(struct irq_desc *desc)
+{
+    gicv3_irq_enable(desc);
+
+    return 0;
+}
+
+static void gicv3_irq_shutdown(struct irq_desc *desc)
+{
+    gicv3_irq_disable(desc);
+}
+
+static void gicv3_irq_ack(struct irq_desc *desc)
+{
+    /* No ACK -- reading IAR has done this for us */
+}
+
+static void gicv3_host_irq_end(struct irq_desc *desc)
+{
+    /* Lower the priority */
+    gicv3_eoi_irq(desc);
+    /* Deactivate */
+    gicv3_dir_irq(desc);
+}
+
+static void gicv3_guest_irq_end(struct irq_desc *desc)
+{
+    /* Lower the priority of the IRQ */
+    gicv3_eoi_irq(desc);
+    /* Deactivation happens in maintenance interrupt / via GICV */
+}
+
+static void gicv3_irq_set_affinity(struct irq_desc *desc, const cpumask_t 
*mask)
+{
+    unsigned int cpu;
+    uint64_t affinity;
+
+    ASSERT(!cpumask_empty(mask));
+
+    spin_lock(&gicv3.lock);
+
+    cpu = gicv3_get_cpu_from_mask(mask);
+    affinity = gicv3_mpidr_to_affinity(cpu);
+    /* Make sure we don't broadcast the interrupt */
+    affinity &= ~GICD_IROUTER_SPI_MODE_ANY;
+
+    if ( desc->irq >= NR_GIC_LOCAL_IRQS )
+        writeq_relaxed(affinity, (GICD + GICD_IROUTER + desc->irq * 8));
+
+    spin_unlock(&gicv3.lock);
+}
+
+static const hw_irq_controller gicv3_host_irq_type = {
+    .typename     = "gic-v3",
+    .startup      = gicv3_irq_startup,
+    .shutdown     = gicv3_irq_shutdown,
+    .enable       = gicv3_irq_enable,
+    .disable      = gicv3_irq_disable,
+    .ack          = gicv3_irq_ack,
+    .end          = gicv3_host_irq_end,
+    .set_affinity = gicv3_irq_set_affinity,
+};
+
+static const hw_irq_controller gicv3_guest_irq_type = {
+    .typename     = "gic-v3",
+    .startup      = gicv3_irq_startup,
+    .shutdown     = gicv3_irq_shutdown,
+    .enable       = gicv3_irq_enable,
+    .disable      = gicv3_irq_disable,
+    .ack          = gicv3_irq_ack,
+    .end          = gicv3_guest_irq_end,
+    .set_affinity = gicv3_irq_set_affinity,
+};
+
+static const struct gic_hw_operations gicv3_ops = {
+    .info                = &gicv3_info,
+    .save_state          = gicv3_save_state,
+    .restore_state       = gicv3_restore_state,
+    .dump_state          = gicv3_dump_state,
+    .gicv_setup          = gicv_v3_init,
+    .gic_host_irq_type   = &gicv3_host_irq_type,
+    .gic_guest_irq_type  = &gicv3_guest_irq_type,
+    .eoi_irq             = gicv3_eoi_irq,
+    .deactivate_irq      = gicv3_dir_irq,
+    .read_irq            = gicv3_read_irq,
+    .set_irq_properties  = gicv3_set_irq_properties,
+    .send_SGI            = gicv3_send_sgi,
+    .disable_interface   = gicv3_disable_interface,
+    .update_lr           = gicv3_update_lr,
+    .update_hcr_status   = gicv3_hcr_status,
+    .clear_lr            = gicv3_clear_lr,
+    .read_lr             = gicv3_read_lr,
+    .write_lr            = gicv3_write_lr,
+    .read_vmcr_priority  = gicv3_read_vmcr_priority,
+    .read_apr            = gicv3_read_apr,
+    .secondary_init      = gicv3_secondary_cpu_init,
+};
+
+/* Set up the GIC */
+static int __init gicv3_init(struct dt_device_node *node, const void *data)
+{
+    struct rdist_region *rdist_regs;
+    int res, i;
+    uint32_t reg;
+
+    dt_device_set_used_by(node, DOMID_XEN);
+
+    res = dt_device_get_address(node, 0, &gicv3.dbase, &gicv3.dbase_size);
+    if ( res || !gicv3.dbase )
+        panic("GICv3: Cannot find a valid distributor address");
+
+    if ( (gicv3.dbase & ~PAGE_MASK) || (gicv3.dbase_size & ~PAGE_MASK) )
+        panic("GICv3:  Found unaligned distributor address %"PRIpaddr"",
+              gicv3.dbase);
+
+    gicv3.map_dbase = ioremap_nocache(gicv3.dbase, gicv3.dbase_size);
+    if ( !gicv3.map_dbase )
+        panic("GICv3: Failed to ioremap for GIC distributor\n");
+
+    reg = readl_relaxed(GICD + GICD_PIDR2) & GICD_PIDR2_ARCH_REV_MASK;
+    if ( ((reg >> GICD_PIDR2_ARCH_REV_SHIFT) != GICD_PIDR2_ARCH_GICV3) )
+         panic("GICv3: no distributor detected\n");
+
+    if ( !dt_property_read_u32(node, "#redistributor-regions",
+                &gicv3.rdist_count) )
+        gicv3.rdist_count = 1;
+
+    if ( gicv3.rdist_count > MAX_RDIST_COUNT )
+        panic("GICv3: Number of redistributor regions is more than"
+              "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT);
+
+    rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count);
+    if ( !rdist_regs )
+        panic("GICv3: Failed to allocate memory for rdist regions\n");
+
+    for ( i = 0; i < gicv3.rdist_count; i++ )
+    {
+        uint64_t rdist_base, rdist_size;
+
+        res = dt_device_get_address(node, 1 + i, &rdist_base, &rdist_size);
+        if ( res || !rdist_base )
+            panic("GICv3: No rdist base found for region %d\n", i);
+
+        rdist_regs[i].base = rdist_base;
+        rdist_regs[i].size = rdist_size;
+    }
+
+    /* If stride is not set in dt. Set default to 2 * SZ_64K */
+    if ( !dt_property_read_u32(node, "redistributor-stride", 
&gicv3.rdist_stride) )
+        gicv3.rdist_stride = 0;
+
+    gicv3.rdist_regions= rdist_regs;
+
+    res = platform_get_irq(node, 0);
+    if ( res < 0 )
+        panic("GICv3: Cannot find the maintenance IRQ");
+    gicv3_info.maintenance_irq = res;
+
+    /* Set the GIC as the primary interrupt controller */
+    dt_interrupt_controller = node;
+
+    for ( i = 0; i < gicv3.rdist_count; i++ )
+    {
+        /* map dbase & rdist regions */
+        gicv3.rdist_regions[i].map_base =
+                ioremap_nocache(gicv3.rdist_regions[i].base,
+                                gicv3.rdist_regions[i].size);
+
+        if ( !gicv3.rdist_regions[i].map_base )
+            panic("GICv3: Failed to ioremap rdist region for region %d\n", i);
+    }
+
+    printk("GICv3 initialization:\n"
+           "      gic_dist_addr=%"PRIpaddr"\n"
+           "      gic_dist_size=%"PRIpaddr"\n"
+           "      gic_dist_mapaddr=%p\n"
+           "      gic_rdist_regions=%d\n"
+           "      gic_rdist_stride=%x\n"
+           "      gic_rdist_base=%"PRIpaddr"\n"
+           "      gic_rdist_base_size=%"PRIpaddr"\n"
+           "      gic_rdist_base_mapaddr=%p\n"
+           "      gic_maintenance_irq=%u\n",
+           gicv3.dbase, gicv3.dbase_size, gicv3.map_dbase, gicv3.rdist_count,
+           gicv3.rdist_stride, gicv3.rdist_regions[0].base,
+           gicv3.rdist_regions[0].size, gicv3.rdist_regions[0].map_base,
+           gicv3_info.maintenance_irq);
+
+    spin_lock_init(&gicv3.lock);
+
+    spin_lock(&gicv3.lock);
+
+    gicv3_dist_init();
+    res = gicv3_cpu_init();
+    gicv3_hyp_init();
+
+    gicv3_info.hw_version = GIC_V3;
+    /* Register hw ops*/
+    register_gic_ops(&gicv3_ops);
+
+    spin_unlock(&gicv3.lock);
+
+    return res;
+}
+
+static const char * const gicv3_dt_compat[] __initconst =
+{
+    DT_COMPAT_GIC_V3,
+    NULL
+};
+
+DT_DEVICE_START(gicv3, "GICv3", DEVICE_GIC)
+        .compatible = gicv3_dt_compat,
+        .init = gicv3_init,
+DT_DEVICE_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 32d0554..787e93c 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -99,6 +99,14 @@ struct arch_domain
         /* Base address for guest GIC */
         paddr_t dbase; /* Distributor base address */
         paddr_t cbase; /* CPU base address */
+#ifdef CONFIG_ARM_64
+        /* GIC V3 addressing */
+        paddr_t dbase_size; /* Distributor base size */
+        paddr_t rbase[MAX_RDIST_COUNT];      /* Re-Distributor base address */
+        paddr_t rbase_size[MAX_RDIST_COUNT]; /* Re-Distributor size */
+        uint32_t rdist_stride;               /* Re-Distributor stride */
+        int rdist_count;                     /* No. of Re-Distributors */
+#endif
     } vgic;
 
     struct vuart {
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index a0c07bf..c4daf5b 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -18,6 +18,10 @@
 #ifndef __ASM_ARM_GIC_H__
 #define __ASM_ARM_GIC_H__
 
+#define NR_GIC_LOCAL_IRQS  NR_LOCAL_IRQS
+#define NR_GIC_SGI         16
+#define MAX_RDIST_COUNT    4
+
 #define GICD_CTLR       (0x000)
 #define GICD_TYPER      (0x004)
 #define GICD_IIDR       (0x008)
@@ -154,6 +158,20 @@
 #define DT_MATCH_GIC_V2 DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_CORTEX_A15), \
                         DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_CORTEX_A7)
 
+#define DT_COMPAT_GIC_V3             "arm,gic-v3"
+
+#define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_V3)
+
+/*
+ * GICv3 registers that needs to be saved/restored
+ */
+struct gic_v3 {
+    uint32_t hcr, vmcr, sre_el1;
+    uint32_t apr0[4];
+    uint32_t apr1[4];
+    uint64_t lr[16];
+};
+
 /*
  * GICv2 register that needs to be saved/restored
  * on VCPU context switch
@@ -170,6 +188,7 @@ struct gic_v2 {
  */
 union gic_state_data {
     struct gic_v2 v2;
+    struct gic_v3 v3;
 };
 
 /*
@@ -189,6 +208,7 @@ struct gic_lr {
 
 enum gic_version {
     GIC_V2,
+    GIC_V3,
 };
 
 extern enum gic_version gic_hw_version(void);
diff --git a/xen/include/asm-arm/gic_v3_defs.h 
b/xen/include/asm-arm/gic_v3_defs.h
new file mode 100644
index 0000000..6c8ff26
--- /dev/null
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -0,0 +1,154 @@
+/*
+ * ARM Generic Interrupt Controller v3 definitions
+ *
+ * Vijaya Kumar K <vijaya.kumar@xxxxxxxxxxxxxxxxxx>
+ * Copyright (c) 2014 Cavium Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARM_GIC_V3_DEFS_H__
+#define __ASM_ARM_GIC_V3_DEFS_H__
+
+/*
+ * Additional registers defined in GIC v3.
+ * Common GICD registers are defined in gic.h
+ */
+
+#define GICD_STATUSR                 (0x010)
+#define GICD_SETSPI_NSR              (0x040)
+#define GICD_CLRSPI_NSR              (0x048)
+#define GICD_SETSPI_SR               (0x050)
+#define GICD_CLRSPI_SR               (0x058)
+#define GICD_IROUTER                 (0x6000)
+#define GICD_IROUTER31               (0x60F8)
+#define GICD_IROUTER32               (0x6100)
+#define GICD_IROUTERN                (0x7FF8)
+#define GICD_PIDR0                   (0xFFE0)
+#define GICD_PIDR1                   (0xFFE4)
+#define GICD_PIDR2                   (0xFFE8)
+#define GICD_PIDR3                   (0xFFEC)
+#define GICD_PIDR4                   (0xFFD0)
+#define GICD_PIDR5                   (0xFFD4)
+#define GICD_PIDR7                   (0xFFDC)
+
+#define GICC_SRE_EL2_SRE             (1UL << 0)
+#define GICC_SRE_EL2_DFB             (1UL << 1)
+#define GICC_SRE_EL2_DIB             (1UL << 2)
+#define GICC_SRE_EL2_ENEL1           (1UL << 3)
+
+#define GICD_CTLR_RWP                (1UL << 31)
+#define GICD_CTLR_ARE_NS             (1U << 4)
+#define GICD_CTLR_ENABLE_G1A         (1U << 1)
+#define GICD_CTLR_ENABLE_G1          (1U << 0)
+#define GICD_IROUTER_SPI_MODE_ANY    (1UL << 31)
+
+#define GICC_CTLR_EL1_EOImode_drop   (1U << 1)
+
+#define GICR_WAKER_ProcessorSleep    (1U << 1)
+#define GICR_WAKER_ChildrenAsleep    (1U << 2)
+
+#define GICD_PIDR2_ARCH_REV_MASK     (0xf0)
+#define GICD_PIDR2_ARCH_REV_SHIFT    (0x4)
+#define GICD_PIDR2_ARCH_GICV3        (0x3)
+
+#define GICR_PIDR2_ARCH_REV_MASK     GICD_PIDR2_ARCH_REV_MASK
+#define GICR_PIDR2_ARCH_REV_SHIFT    GICD_PIDR2_ARCH_REV_SHIFT
+#define GICR_PIDR2_ARCH_GICV3        GICD_PIDR2_ARCH_GICV3
+
+#define GICR_SYNCR_NOT_BUSY          1
+/*
+ * Implementation defined value JEP106?
+ * use physical hw value for now
+ */
+#define GICV3_GICD_IIDR_VAL          0x34c
+#define GICV3_GICR_IIDR_VAL          GICV3_GICD_IIDR_VAL
+
+#define GICR_CTLR                    (0x0000)
+#define GICR_IIDR                    (0x0004)
+#define GICR_TYPER                   (0x0008)
+#define GICR_STATUSR                 (0x0010)
+#define GICR_WAKER                   (0x0014)
+#define GICR_SETLPIR                 (0x0040)
+#define GICR_CLRLPIR                 (0x0048)
+#define GICR_PROPBASER               (0x0070)
+#define GICR_PENDBASER               (0x0078)
+#define GICR_INVLPIR                 (0x00A0)
+#define GICR_INVALLR                 (0x00B0)
+#define GICR_SYNCR                   (0x00C0)
+#define GICR_MOVLPIR                 (0x100)
+#define GICR_MOVALLR                 (0x0110)
+#define GICR_PIDR0                   GICD_PIDR0
+#define GICR_PIDR1                   GICD_PIDR1
+#define GICR_PIDR2                   GICD_PIDR2
+#define GICR_PIDR3                   GICD_PIDR3
+#define GICR_PIDR4                   GICD_PIDR4
+#define GICR_PIDR5                   GICD_PIDR5
+#define GICR_PIDR7                   GICD_PIDR7
+
+/* GICR for SGI's & PPI's */
+
+#define GICR_IGROUPR0                (0x0080)
+#define GICR_IGRPMODR0               (0x0F80)
+#define GICR_ISENABLER0              (0x0100)
+#define GICR_ICENABLER0              (0x0180)
+#define GICR_ISPENDR0                (0x0200)
+#define GICR_ICPENDR0                (0x0280)
+#define GICR_ISACTIVER0              (0x0300)
+#define GICR_ICACTIVER0              (0x0380)
+#define GICR_IPRIORITYR0             (0x0400)
+#define GICR_IPRIORITYR7             (0x041C)
+#define GICR_ICFGR0                  (0x0C00)
+#define GICR_ICFGR1                  (0x0C04)
+#define GICR_NSACR                   (0x0E00)
+
+#define GICR_TYPER_PLPIS             (1U << 0)
+#define GICR_TYPER_VLPIS             (1U << 1)
+#define GICR_TYPER_LAST              (1U << 4)
+
+#define DEFAULT_PMR_VALUE            0xff
+
+#define GICH_VMCR_EOI                (1 << 9)
+#define GICH_VMCR_VENG1              (1 << 1)
+
+#define GICH_LR_VIRTUAL_MASK         0xffff
+#define GICH_LR_VIRTUAL_SHIFT        0
+#define GICH_LR_PHYSICAL_MASK        0x3ff
+#define GICH_LR_PHYSICAL_SHIFT       32
+#define GICH_LR_STATE_MASK           0x3
+#define GICH_LR_STATE_SHIFT          62
+#define GICH_LR_PRIORITY_MASK        0xff
+#define GICH_LR_PRIORITY_SHIFT       48
+#define GICH_LR_HW_MASK              0x1
+#define GICH_LR_HW_SHIFT             61
+#define GICH_LR_GRP_MASK             0x1
+#define GICH_LR_GRP_SHIFT            60
+#define GICH_LR_MAINTENANCE_IRQ      (1UL<<41)
+#define GICH_LR_GRP1                 (1UL<<60)
+#define GICH_LR_HW                   (1UL<<61)
+
+#define GICH_VTR_NRLRGS              0x3f
+#define GICH_VTR_PRIBITS_MASK        0x7
+#define GICH_VTR_PRIBITS_SHIFT       29
+
+#define GICH_VMCR_PRIORITY_MASK      0xff
+#define GICH_VMCR_PRIORITY_SHIFT     24
+
+#endif /* __ASM_ARM_GIC_V3_DEFS_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 33ef385..d83f593 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -20,6 +20,19 @@
 #define AFFINITY_MASK(level)    ~((_AC(0x1,U) << ((level) * MPIDR_LEVEL_BITS)) 
- 1)
 
 
+/*
+ * Macros to extract affinity level. picked from kernel
+ */
+
+#define MPIDR_LEVEL_BITS_SHIFT  3
+#define MPIDR_LEVEL_MASK        ((1 << MPIDR_LEVEL_BITS) - 1)
+
+#define MPIDR_LEVEL_SHIFT(level) \
+         (((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT)
+
+#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
+         ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)
+
 /* TTBCR Translation Table Base Control Register */
 #define TTBCR_EAE    _AC(0x80000000,U)
 #define TTBCR_N_MASK _AC(0x07,U)
diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
index b00871c..b4616ac 100644
--- a/xen/include/asm-arm/sysregs.h
+++ b/xen/include/asm-arm/sysregs.h
@@ -100,6 +100,59 @@
 #define HSR_SYSREG_CNTP_CTL_EL0   HSR_SYSREG(3,3,c14,c2,1)
 #define HSR_SYSREG_CNTP_TVAL_EL0  HSR_SYSREG(3,3,c14,c2,0)
 
+/*
+ * GIC System register assembly aliases picked from kernel
+ */
+#define ICC_PMR_EL1               S3_0_C4_C6_0
+#define ICC_DIR_EL1               S3_0_C12_C11_1
+#define ICC_SGI1R_EL1             S3_0_C12_C11_5
+#define ICC_EOIR1_EL1             S3_0_C12_C12_1
+#define ICC_IAR1_EL1              S3_0_C12_C12_0
+#define ICC_BPR1_EL1              S3_0_C12_C12_3
+#define ICC_CTLR_EL1              S3_0_C12_C12_4
+#define ICC_SRE_EL1               S3_0_C12_C12_5
+#define ICC_IGRPEN1_EL1           S3_0_C12_C12_7
+
+#define ICH_VSEIR_EL2             S3_4_C12_C9_4
+#define ICC_SRE_EL2               S3_4_C12_C9_5
+#define ICH_HCR_EL2               S3_4_C12_C11_0
+#define ICH_VTR_EL2               S3_4_C12_C11_1
+#define ICH_MISR_EL2              S3_4_C12_C11_2
+#define ICH_EISR_EL2              S3_4_C12_C11_3
+#define ICH_ELSR_EL2              S3_4_C12_C11_5
+#define ICH_VMCR_EL2              S3_4_C12_C11_7
+
+#define __LR0_EL2(x)              S3_4_C12_C12_ ## x
+#define __LR8_EL2(x)              S3_4_C12_C13_ ## x
+
+#define ICH_LR0_EL2               __LR0_EL2(0)
+#define ICH_LR1_EL2               __LR0_EL2(1)
+#define ICH_LR2_EL2               __LR0_EL2(2)
+#define ICH_LR3_EL2               __LR0_EL2(3)
+#define ICH_LR4_EL2               __LR0_EL2(4)
+#define ICH_LR5_EL2               __LR0_EL2(5)
+#define ICH_LR6_EL2               __LR0_EL2(6)
+#define ICH_LR7_EL2               __LR0_EL2(7)
+#define ICH_LR8_EL2               __LR8_EL2(0)
+#define ICH_LR9_EL2               __LR8_EL2(1)
+#define ICH_LR10_EL2              __LR8_EL2(2)
+#define ICH_LR11_EL2              __LR8_EL2(3)
+#define ICH_LR12_EL2              __LR8_EL2(4)
+#define ICH_LR13_EL2              __LR8_EL2(5)
+#define ICH_LR14_EL2              __LR8_EL2(6)
+#define ICH_LR15_EL2              __LR8_EL2(7)
+
+#define __AP0Rx_EL2(x)            S3_4_C12_C8_ ## x
+#define ICH_AP0R0_EL2             __AP0Rx_EL2(0)
+#define ICH_AP0R1_EL2             __AP0Rx_EL2(1)
+#define ICH_AP0R2_EL2             __AP0Rx_EL2(2)
+#define ICH_AP0R3_EL2             __AP0Rx_EL2(3)
+
+#define __AP1Rx_EL2(x)            S3_4_C12_C9_ ## x
+#define ICH_AP1R0_EL2             __AP1Rx_EL2(0)
+#define ICH_AP1R1_EL2             __AP1Rx_EL2(1)
+#define ICH_AP1R2_EL2             __AP1Rx_EL2(2)
+#define ICH_AP1R3_EL2             __AP1Rx_EL2(3)
 
 #endif
 
-- 
1.7.9.5


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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.