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

Re: [Xen-devel] [PATCH v4 13/16] xen/arm: Add support for GIC v3



On Mon, 26 May 2014, vijay.kilari@xxxxxxxxx wrote:
> 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 regiseters 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>
> ---
>  xen/arch/arm/Makefile             |    1 +
>  xen/arch/arm/gic-v3.c             | 1125 
> +++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/domain.h      |    8 +
>  xen/include/asm-arm/gic.h         |   20 +
>  xen/include/asm-arm/gic_v3_defs.h |  157 ++++++
>  xen/include/asm-arm/processor.h   |   14 +
>  xen/include/xen/lib.h             |    2 +
>  7 files changed, 1327 insertions(+)
> 
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 20f59f4..1684c09 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..7543fb4
> --- /dev/null
> +++ b/xen/arch/arm/gic-v3.c
> @@ -0,0 +1,1125 @@
> +/*
> + * 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/libfdt/libfdt.h>
> +#include <asm/p2m.h>
> +#include <asm/domain.h>
> +#include <asm/platform.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_lr(int nr_lrs, struct vcpu *v)
> +{
> +    /* Fall through for all the cases */
> +    switch ( 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_lr(int nr_lrs, const struct vcpu *v)
> +{
> +    /* Fall through for all the cases */
> +    switch ( 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();
> +    }
> +}

Given that the number of LR registers has grown up quite a bit from
GICv2, we should optimize this code and only save and restore the
registers that are actually in used by checking on lr_mask.

It would also help performances if we restored them in ascending order.

> +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;
> +    }
> +}
> +
> +/*
> + * 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 |
> +           GICC_SRE_EL2_DFB | GICC_SRE_EL2_DIB;
> +
> +    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();
> +    }
> +}
> +
> +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.
> +     */
> +    dsb(sy);
> +    gicv3_save_lr(gicv3_info.nr_lrs, v);
> +    save_aprn_regs(&v->arch.gic);
> +    v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2);
> +}
> +
> +static void gicv3_restore_state(const struct vcpu *v)
> +{
> +    gicv3_restore_lr(gicv3_info.nr_lrs, v);
> +    restore_aprn_regs(&v->arch.gic);
> +    WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2);
> +}

Shouldn't we restore vmcr first? Before writing to the LRs?

Should we save/restore SRE_EL1 too?
Also looking at the Linux code, it seems that SRE_EL1 and VMCR_EL2 might
have strange interactions, in fact Linux disables SRE_EL1 before writing
to VMCR_EL2 (see restore_vgic_v3_state).


> +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_enable_irq(struct irq_desc *irqd)
> +{
> +    int irq = irqd->irq;
> +
> +    /* Enable routing */
> +    if ( irq < NR_GIC_LOCAL_IRQS )
> +        writel_relaxed((1u << irq), GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
> +    else
> +        writel_relaxed((1u << (irq % 32)),
> +                        GICD + GICD_ISENABLER + (irq / 32) * 4);
> +
> +    gicv3_wait_for_rwp(irq);
> +}
> +
> +static void gicv3_disable_irq(struct irq_desc *irqd)
> +{
> +    /* Disable routing */
> +    if ( irqd->irq < NR_GIC_LOCAL_IRQS )
> +        writel_relaxed((1u << irqd->irq),
> +                       GICD_RDIST_SGI_BASE + GICR_ICENABLER0);
> +    else
> +        writel_relaxed(1u << (irqd->irq % 32),
> +                       GICD + GICD_ICENABLER + ((irqd->irq / 32) * 4));
> +}

Strangely we have a wait in gicv3_enable_irq but not a wait in
gicv3_disable_irq.
Is that deliberate?


> +static void gicv3_eoi_irq(struct irq_desc *irqd)
> +{
> +    /* Lower the priority */
> +    WRITE_SYSREG32(irqd->irq, ICC_EOIR1_EL1);

We need an isb here.


> +}
> +
> +static void gicv3_dir_irq(int irq)
> +{
> +    /* Deactivate */
> +    WRITE_SYSREG32(irq, ICC_DIR_EL1);
> +}

I am not sure if this needs an isb or not.


> +static unsigned int gicv3_read_irq(void)
> +{
> +    return (READ_SYSREG32(ICC_IAR1_EL1) & GICC_IA_IRQ);
> +}
> +
> +static inline uint64_t gicv3_mpidr_to_affinity(uint64_t mpidr)
> +{
> +     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)
> +{
> +    unsigned long flags;
> +    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;
> +
> +    spin_lock_irqsave(&gicv3.lock, flags);
> +
> +    /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */
> +    if ( irq >= NR_GIC_SGI )
> +    {
> +        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_logical_map(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_irqrestore(&gicv3.lock, flags);
> +}
> +
> +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(cpu_logical_map(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 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());
> +
> +    aff = gicv3_mpidr_to_affinity(mpidr);
> +
> +    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_MASK;
> +        if ( reg  != (GICV3_GICR_PIDR2 & GICR_PIDR2_ARCH_MASK) )
> +        {
> +            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;
> +            }
> +
> +            ptr += gicv3.rdist_stride;
> +            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 %lx has no re-distributor!\n",
> +                  smp_processor_id(), mpidr);
> +    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);
> +
> +    return 0;
> +}
> +
> +static void gicv3_cpu_disable(void)
> +{
> +    WRITE_SYSREG32(0, ICC_CTLR_EL1);
> +}
> +
> +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;
> +
> +    ASSERT((gicv3.nr_priorities > 4 && gicv3.nr_priorities < 8));
> +
> +    WRITE_SYSREG32(GICH_VMCR_EOI | GICH_VMCR_VENG1, ICH_VMCR_EL2);
> +    WRITE_SYSREG32(GICH_HCR_EN, ICH_HCR_EL2);
> +
> +    update_cpu_lr_mask();
> +}
> +
> +/* 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 vtr;
> +
> +    vtr = READ_SYSREG32(ICH_HCR_EL2);
> +    vtr &= ~0x1;
> +    WRITE_SYSREG32( vtr, ICH_HCR_EL2);
> +}
> +
> +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 )
> +    {
> +        /*
> +         * If we ever get a cluster of more than 16 CPUs, just
> +         * scream and skip that CPU.
> +         */
> +        if ( (mpidr & 0xff) >= 16 )
> +        {
> +            dprintk(XENLOG_WARNING, "GICv3:Cluster with more than 16's 
> cpus\n");
> +            goto out;
> +        }
> +        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 & ~0xffUL) ) {
> +            cpu--;
> +            goto out;
> +        }
> +    }
> +out:
> +    *base_cpu = cpu;
> +
> +    return tlist;
> +}
> +
> +static void gicv3_send_sgi(const cpumask_t *cpumask, enum gic_sgi sgi,
> +                           uint8_t mode)
> +{
> +    int cpu = 0;
> +    uint64_t val;
> +
> +    dsb(sy);
> +
> +    for_each_cpu(cpu, cpumask)
> +    {
> +        uint64_t cluster_id = cpu_logical_map(cpu) & ~0xffUL;
> +        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);
> +    }
> +}
> +
> +/* 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;

Could you please add a TODO comment here to remind us that one day we
might need to handle GRP0 as well?


> +    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 ( d->domain_id == 0 )
> +    {
> +        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);
> +}
> +
> +static unsigned int gicv3_read_vmcr_priority(void)
> +{
> +   return ((READ_SYSREG32(ICH_VMCR_EL2) >> GICH_VMCR_PRIORITY_SHIFT) &
> +            GICH_VMCR_PRIORITY_MASK);
> +}
> +
> +static void gicv3_irq_enable(struct irq_desc *desc)
> +{
> +    unsigned long flags;
> +
> +    spin_lock_irqsave(&gicv3.lock, flags);
> +    desc->status &= ~IRQ_DISABLED;
> +    dsb(sy);
> +    /* Enable routing */
> +    gicv3_enable_irq(desc);
> +    spin_unlock_irqrestore(&gicv3.lock, flags);
> +}
> +
> +static void gicv3_irq_disable(struct irq_desc *desc)
> +{
> +    unsigned long flags;
> +
> +    spin_lock_irqsave(&gicv3.lock, flags);
> +    /* Disable routing */
> +    gicv3_disable_irq(desc);
> +    desc->status |= IRQ_DISABLED;
> +    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->irq);
> +}
> +
> +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)
> +{
> +    BUG();
> +}
> +
> +const static 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,
> +};
> +
> +const static 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,
> +};
> +
> +const static 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,
> +    .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_MASK;
> +    if ( reg  != (GICV3_GICD_PIDR2 & GICD_PIDR2_ARCH_MASK) )
> +         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 = 2 * SZ_64K;
> +
> +    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_MATCH_GIC_V3_STRING1,
> +    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 8a00aa1..66e246e 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -154,6 +154,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 2aadcb6..b40beb5 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)
> @@ -150,6 +154,20 @@
>  #define DT_MATCH_GIC_V2 DT_MATCH_COMPATIBLE(DT_MATCH_GIC_V2_STRING_1), \
>                          DT_MATCH_COMPATIBLE(DT_MATCH_GIC_V2_STRING_2)
>  
> +#define DT_MATCH_GIC_V3_STRING1      "arm,gic-v3"
> +
> +#define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE(DT_MATCH_GIC_V3_STRING1);
> +
> +/*
> + * GICv3 registers that needs to be saved/restored
> + */
> +struct gic_v3 {
> +    uint32_t hcr, vmcr;
> +    uint32_t apr0[4];
> +    uint32_t apr1[4];
> +    uint64_t lr[16];
> +};
> +
>  /*
>   * GICv2 register that needs to be saved/restored
>   * on VCPU context switch
> @@ -166,6 +184,7 @@ struct gic_v2 {
>   */ 
>  union gic_state_data {
>      struct gic_v2 v2;
> +    struct gic_v3 v3;
>  };
>  
>  /*
> @@ -251,6 +270,7 @@ void gic_clear_lrs(struct vcpu *v);
>  
>  enum gic_version {
>      GIC_V2 = 2,
> +    GIC_V3 = 3,
>  };
>  
>  struct gic_info {
> 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..6f393aa
> --- /dev/null
> +++ b/xen/include/asm-arm/gic_v3_defs.h
> @@ -0,0 +1,157 @@
> +/*
> + * 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 GICV3_GICD_PIDR0             (0x92)
> +#define GICV3_GICD_PIDR1             (0xb4)
> +#define GICV3_GICD_PIDR2             (0x3b)
> +#define GICV3_GICD_PIDR4             (0x04)
> +#define GICD_PIDR2_ARCH_MASK         (0xf0)
> +
> +#define GICV3_GICR_PIDR0             (0x93)
> +#define GICV3_GICR_PIDR1             GICV3_GICD_PIDR1
> +#define GICV3_GICR_PIDR2             GICV3_GICD_PIDR2
> +#define GICV3_GICR_PIDR4             GICV3_GICD_PIDR4
> +#define GICR_PIDR2_ARCH_MASK         GICD_PIDR2_ARCH_MASK
> +#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 3662749..5978b8a 100644
> --- a/xen/include/asm-arm/processor.h
> +++ b/xen/include/asm-arm/processor.h
> @@ -17,6 +17,20 @@
>  #define MPIDR_HWID_MASK     _AC(0xffffff,U)
>  #define MPIDR_INVALID       (~MPIDR_HWID_MASK)
>  
> +/*
> + * Macros to extract affinity level. picked from kernel
> + */
> +
> +#define MPIDR_LEVEL_BITS_SHIFT  3
> +#define MPIDR_LEVEL_BITS        (1 << MPIDR_LEVEL_BITS_SHIFT)
> +#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/xen/lib.h b/xen/include/xen/lib.h
> index 1369b2b..499a798 100644
> --- a/xen/include/xen/lib.h
> +++ b/xen/include/xen/lib.h
> @@ -67,6 +67,8 @@ do {                                                        
>     \
>  
>  #define reserve_bootmem(_p,_l) ((void)0)
>  
> +#define SZ_64K  0x00010000
> +
>  struct domain;
>  
>  void cmdline_parse(const char *cmdline);
> -- 
> 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®.