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

Re: [Xen-devel] [RFC PATCH v1 06/10] xen/arm: split gic driver into generic and gicv2 driver



On Thu, Mar 20, 2014 at 5:25 PM, Stefano Stabellini
<stefano.stabellini@xxxxxxxxxxxxx> wrote:
> On Wed, 19 Mar 2014, vijay.kilari@xxxxxxxxx wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
>>
>> Existing GIC driver has both generic code and hw specific
>> code. Segregate GIC low level driver into gic-v2.c and
>> keep generic code in existing gic.c file
>>
>> GIC v2 driver registers required functions
>> to generic GIC driver. This helps to plug in next version
>> of GIC drivers like GIC v3.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
>
> Am I correct in assuming that this patch is just code movement plus the
> introduction of struct gic_hw_operations?
>
Yes, as a part of code movement, I introduced this structure and
used this callbacks in generic code

>
>>  xen/arch/arm/Makefile             |    2 +-
>>  xen/arch/arm/gic-v2.c             |  562 
>> +++++++++++++++++++++++++++++++++++++
>>  xen/arch/arm/gic.c                |  530 +++++++---------------------------
>>  xen/include/asm-arm/gic.h         |   40 ++-
>>  xen/include/asm-arm/gic_v2_defs.h |    2 -
>>  5 files changed, 708 insertions(+), 428 deletions(-)
>>
>> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
>> index 63e0460..969ee52 100644
>> --- a/xen/arch/arm/Makefile
>> +++ b/xen/arch/arm/Makefile
>> @@ -10,7 +10,7 @@ obj-y += vpsci.o
>>  obj-y += domctl.o
>>  obj-y += sysctl.o
>>  obj-y += domain_build.o
>> -obj-y += gic.o
>> +obj-y += gic.o gic-v2.o
>>  obj-y += io.o
>>  obj-y += irq.o
>>  obj-y += kernel.o
>> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
>> new file mode 100644
>> index 0000000..9378427
>> --- /dev/null
>> +++ b/xen/arch/arm/gic-v2.c
>> @@ -0,0 +1,562 @@
>> +/*
>> + * xen/arch/arm/gic-v2.c
>> + *
>> + * ARM Generic Interrupt Controller support v2
>> + *
>> + * Tim Deegan <tim@xxxxxxx>
>> + * Copyright (c) 2011 Citrix Systems.
>> + *
>> + * 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/serial.h>
>> +#include <xen/softirq.h>
>> +#include <xen/list.h>
>> +#include <xen/device_tree.h>
>> +#include <asm/p2m.h>
>> +#include <asm/domain.h>
>> +#include <asm/platform.h>
>> +
>> +#include <asm/gic_v2_defs.h>
>> +#include <asm/gic.h>
>> +
>> +/* Access to the GIC Distributor registers through the fixmap */
>> +#define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
>> +#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
>> +#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH))
>> +
>> +struct gic_state_data {
>> +    uint32_t gic_hcr;
>> +    uint32_t gic_vmcr;
>> +    uint32_t gic_apr;
>> +    uint32_t gic_lr[64];
>> +};
>> +
>> +/* Global state */
>> +static struct {
>> +    int hw_version;
>> +    paddr_t dbase;       /* Address of distributor registers */
>> +    paddr_t cbase;       /* Address of CPU interface registers */
>> +    paddr_t hbase;       /* Address of virtual interface registers */
>> +    paddr_t vbase;       /* Address of virtual cpu interface registers */
>> +    unsigned int lines;  /* Number of interrupts (SPIs + PPIs + SGIs) */
>> +    struct dt_irq maintenance; /* IRQ maintenance */
>> +    unsigned int cpus;
>> +    spinlock_t lock;
>> +} gic;
>> +
>> +static unsigned nr_lrs;
>> +
>> +/* The GIC mapping of CPU interfaces does not necessarily match the
>> + * logical CPU numbering. Let's use mapping as returned by the GIC
>> + * itself
>> + */
>> +static DEFINE_PER_CPU(u8, gic_cpu_id);
>> +
>> +/* Maximum cpu interface per GIC */
>> +#define NR_GIC_CPU_IF 8
>> +
>> +static unsigned int gic_cpu_mask(const cpumask_t *cpumask)
>> +{
>> +    unsigned int cpu;
>> +    unsigned int mask = 0;
>> +    cpumask_t possible_mask;
>> +
>> +    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
>> +    for_each_cpu(cpu, &possible_mask)
>> +    {
>> +        ASSERT(cpu < NR_GIC_CPU_IF);
>> +        mask |= per_cpu(gic_cpu_id, cpu);
>> +    }
>> +
>> +    return mask;
>> +}
>> +
>> +static unsigned int gic_nr_lines(void)
>> +{
>> +    return gic.lines;
>> +}
>> +
>> +static unsigned int gic_nr_lrs(void)
>> +{
>> +    return nr_lrs;
>> +}
>> +
>> +static int gic_state_init(struct vcpu *v)
>> +{
>> +     v->arch.gic_state = (struct gic_state_data *)xzalloc(struct 
>> gic_state_data);
>> +     if(!v->arch.gic_state)
>> +        return -ENOMEM;
>> +     return 0;
>> +}
>> +
>> +static void save_state(struct vcpu *v)
>> +{
>> +    int i;
>> +    struct gic_state_data *d;
>> +    d = (struct gic_state_data *)v->arch.gic_state;
>> +
>> +    ASSERT(!local_irq_is_enabled());
>> +
>> +    /* 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.
>> +     */
>> +    for ( i = 0; i < nr_lrs; i++)
>> +        d->gic_lr[i] = GICH[GICH_LR + i];
>> +    d->gic_apr = GICH[GICH_APR];
>> +    d->gic_vmcr = GICH[GICH_VMCR];
>> +    /* Disable until next VCPU scheduled */
>> +    GICH[GICH_HCR] = 0;
>> +}
>> +
>> +static void restore_state(struct vcpu *v)
>> +{
>> +    int i;
>> +    struct gic_state_data *d;
>> +    d = (struct gic_state_data *)v->arch.gic_state;
>> +
>> +    for ( i = 0; i < nr_lrs; i++)
>> +        GICH[GICH_LR + i] = d->gic_lr[i];
>> +    GICH[GICH_APR] = d->gic_apr;
>> +    GICH[GICH_VMCR] = d->gic_vmcr;
>> +    GICH[GICH_HCR] = GICH_HCR_EN;
>> +}
>> +
>> +static void gic_dump_state(struct vcpu *v)
>> +{
>> +    int i;
>> +    struct gic_state_data *d;
>> +    d = (struct gic_state_data *)v->arch.gic_state;
>> +
>> +    if ( v == current )
>> +    {
>> +        for ( i = 0; i < nr_lrs; i++ )
>> +            printk("   HW_LR[%d]=%x\n", i, GICH[GICH_LR + i]);
>> +    } else {
>> +        for ( i = 0; i < nr_lrs; i++ )
>> +            printk("   VCPU_LR[%d]=%x\n", i, d->gic_lr[i]);
>> +    }
>> +}
>> +
>> +static void gic_enable_irq(int irq)
>> +{
>> +    /* Enable routing */
>> +    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
>> +}
>> +
>> +static void gic_disable_irq(int irq)
>> +{
>> +    /* Disable routing */
>> +    GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
>> +}
>> +
>> +static void gic_eoi_irq(int irq)
>> +{
>> +    /* Lower the priority */
>> +    GICC[GICC_EOIR] = irq;
>> +}
>> +
>> +static void gic_dir_irq(int irq)
>> +{
>> +    /* Deactivate */
>> +    GICC[GICC_DIR] = irq;
>> +}
>> +
>> +static unsigned int gic_ack_irq(void)
>> +{
>> +    return (GICC[GICC_IAR] & GICC_IA_IRQ);
>> +}
>> +
>> +/*
>> + * - needs to be called with gic.lock held
>> + * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
>> + * already called gic_cpu_init
>> + */
>> +static void gic_set_irq_properties(unsigned int irq, bool_t level,
>> +                                   const cpumask_t *cpu_mask,
>> +                                   unsigned int priority)
>> +{
>> +    volatile unsigned char *bytereg;
>> +    uint32_t cfg, edgebit;
>> +    unsigned int mask = gic_cpu_mask(cpu_mask);
>> +
>> +    /* Set edge / level */
>> +    cfg = GICD[GICD_ICFGR + irq / 16];
>> +    edgebit = 2u << (2 * (irq % 16));
>> +    if ( level )
>> +        cfg &= ~edgebit;
>> +    else
>> +        cfg |= edgebit;
>> +    GICD[GICD_ICFGR + irq / 16] = cfg;
>> +
>> +    /* Set target CPU mask (RAZ/WI on uniprocessor) */
>> +    bytereg = (unsigned char *) (GICD + GICD_ITARGETSR);
>> +    bytereg[irq] = mask;
>> +
>> +    /* Set priority */
>> +    bytereg = (unsigned char *) (GICD + GICD_IPRIORITYR);
>> +    bytereg[irq] = priority;
>> +
>> +}
>> +
>> +static void __init gic_dist_init(void)
>> +{
>> +    uint32_t type;
>> +    uint32_t cpumask;
>> +    int i;
>> +
>> +    cpumask = GICD[GICD_ITARGETSR] & 0xff;
>> +    cpumask |= cpumask << 8;
>> +    cpumask |= cpumask << 16;
>> +
>> +    /* Disable the distributor */
>> +    GICD[GICD_CTLR] = 0;
>> +
>> +    type = GICD[GICD_TYPER];
>> +    gic.lines = 32 * ((type & GICD_TYPE_LINES) + 1);
>> +    gic.cpus = 1 + ((type & GICD_TYPE_CPUS) >> 5);
>> +    printk("GIC: %d lines, %d cpu%s%s (IID %8.8x).\n",
>> +           gic.lines, gic.cpus, (gic.cpus == 1) ? "" : "s",
>> +           (type & GICD_TYPE_SEC) ? ", secure" : "",
>> +           GICD[GICD_IIDR]);
>> +
>> +    /* Default all global IRQs to level, active low */
>> +    for ( i = 32; i < gic.lines; i += 16 )
>> +        GICD[GICD_ICFGR + i / 16] = 0x0;
>> +
>> +    /* Route all global IRQs to this CPU */
>> +    for ( i = 32; i < gic.lines; i += 4 )
>> +        GICD[GICD_ITARGETSR + i / 4] = cpumask;
>> +
>> +    /* Default priority for global interrupts */
>> +    for ( i = 32; i < gic.lines; i += 4 )
>> +        GICD[GICD_IPRIORITYR + i / 4] =
>> +            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | 
>> GIC_PRI_IRQ;
>> +
>> +    /* Disable all global interrupts */
>> +    for ( i = 32; i < gic.lines; i += 32 )
>> +        GICD[GICD_ICENABLER + i / 32] = (uint32_t)~0ul;
>> +
>> +    /* Turn on the distributor */
>> +    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
>> +}
>> +
>> +static void __cpuinit gic_cpu_init(void)
>> +{
>> +    int i;
>> +
>> +    this_cpu(gic_cpu_id) = GICD[GICD_ITARGETSR] & 0xff;
>> +
>> +    /* The first 32 interrupts (PPI and SGI) are banked per-cpu, so
>> +     * even though they are controlled with GICD registers, they must
>> +     * be set up here with the other per-cpu state. */
>> +    GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
>> +    GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */
>> +    /* Set SGI priorities */
>> +    for (i = 0; i < 16; i += 4)
>> +        GICD[GICD_IPRIORITYR + i / 4] =
>> +            GIC_PRI_IPI<<24 | GIC_PRI_IPI<<16 | GIC_PRI_IPI<<8 | 
>> GIC_PRI_IPI;
>> +    /* Set PPI priorities */
>> +    for (i = 16; i < 32; i += 4)
>> +        GICD[GICD_IPRIORITYR + i / 4] =
>> +            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | 
>> GIC_PRI_IRQ;
>> +
>> +    /* Local settings: interface controller */
>> +    GICC[GICC_PMR] = 0xff;                /* Don't mask by priority */
>> +    GICC[GICC_BPR] = 0;                   /* Finest granularity of priority 
>> */
>> +    GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI;    /* Turn on delivery 
>> */
>> +}
>> +
>> +static void gic_cpu_disable(void)
>> +{
>> +    GICC[GICC_CTLR] = 0;
>> +}
>> +
>> +static void __cpuinit gic_hyp_init(void)
>> +{
>> +    uint32_t vtr;
>> +
>> +    vtr = GICH[GICH_VTR];
>> +    nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
>> +
>> +    GICH[GICH_MISR] = GICH_MISR_EOI;
>> +    update_cpu_lr_mask();
>> +}
>> +
>> +static void __cpuinit gic_hyp_disable(void)
>> +{
>> +    GICH[GICH_HCR] = 0;
>> +}
>> +
>> +/* Set up the per-CPU parts of the GIC for a secondary CPU */
>> +static int __cpuinit gic_init_secondary_cpu(struct notifier_block *nfb,
>> +                                       unsigned long action, void *hcpu)
>> +{
>> +    if (action == CPU_STARTING)
>> +    {
>> +        spin_lock(&gic.lock);
>> +        gic_cpu_init();
>> +        gic_hyp_init();
>> +        spin_unlock(&gic.lock);
>> +    }
>> +    return NOTIFY_DONE;
>> +}
>> +
>> +static struct notifier_block gic_cpu_nb = {
>> +    .notifier_call = gic_init_secondary_cpu,
>> +    .priority = 100
>> +};
>> +
>> +static void gic_smp_init(void)
>> +{
>> +   register_cpu_notifier(&gic_cpu_nb);
>> +}
>> +
>> +static int gic_hw_type(void)
>> +{
>> +    return gic.hw_version;
>> +}
>> +
>> +static struct dt_irq * gic_maintenance_irq(void)
>> +{
>> +    return &gic.maintenance;
>> +}
>> +
>> +/* Set up the GIC */
>> +
>> +static void gic_send_sgi(const cpumask_t *cpumask, enum gic_sgi sgi)
>> +{
>> +    unsigned int mask = 0;
>> +    cpumask_t online_mask;
>> +
>> +    ASSERT(sgi < 16); /* There are only 16 SGIs */
>> +
>> +    cpumask_and(&online_mask, cpumask, &cpu_online_map);
>> +    mask = gic_cpu_mask(&online_mask);
>> +
>> +    dsb();
>> +
>> +    GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST
>> +        | (mask<<GICD_SGI_TARGET_SHIFT)
>> +        | sgi;
>> +}
>> +
>> +/* Shut down the per-CPU GIC interface */
>> +static void gic_disable_interface(void)
>> +{
>> +    ASSERT(!local_irq_is_enabled());
>> +
>> +    spin_lock(&gic.lock);
>> +    gic_cpu_disable();
>> +    gic_hyp_disable();
>> +    spin_unlock(&gic.lock);
>> +}
>> +
>> +static void gic_update_lr(int lr, unsigned int virtual_irq,
>> +        unsigned int state, unsigned int priority)
>> +{
>> +    int maintenance_int = GICH_LR_MAINTENANCE_IRQ;
>> +
>> +    BUG_ON(lr >= nr_lrs);
>> +    BUG_ON(lr < 0);
>> +    BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT));
>> +
>> +    GICH[GICH_LR + lr] = ((state & 0x3) << GICH_LR_STATE_SHIFT) |
>> +        maintenance_int |
>> +        ((priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
>> +        ((virtual_irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
>> +
>> +}
>> +
>> +static int gicv_init(struct domain *d)
>> +{
>> +    int ret;
>> +
>> +    /*
>> +     * Domain 0 gets the hardware address.
>> +     * Guests get the virtual platform layout.
>> +     */
>> +    if ( d->domain_id == 0 )
>> +    {
>> +        d->arch.vgic.dbase = gic.dbase;
>> +        d->arch.vgic.cbase = gic.cbase;
>> +    }
>> +    else
>> +    {
>> +        d->arch.vgic.dbase = GUEST_GICD_BASE;
>> +        d->arch.vgic.cbase = GUEST_GICC_BASE;
>> +    }
>> +
>> +    d->arch.vgic.nr_lines = 0;
>> +
>> +    /*
>> +     * Map the gic virtual cpu interface in the gic cpu interface
>> +     * region of the guest.
>> +     *
>> +     * The second page is always mapped at +4K irrespective of the
>> +     * GIC_64K_STRIDE quirk. The DTB passed to the guest reflects this.
>> +     */
>> +    ret = map_mmio_regions(d, d->arch.vgic.cbase,
>> +                           d->arch.vgic.cbase + PAGE_SIZE - 1,
>> +                           gic.vbase);
>> +    if (ret)
>> +        return ret;
>> +
>> +    if ( !platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
>> +        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
>> +                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
>> +                               gic.vbase + PAGE_SIZE);
>> +    else
>> +        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
>> +                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
>> +                               gic.vbase + 16*PAGE_SIZE);
>> +
>> +    return ret;
>> +
>> +}
>> +
>> +static unsigned long gic_read_eisr(void)
>> +{
>> +    return ((unsigned long)(GICH[GICH_EISR0] | (((uint64_t) 
>> GICH[GICH_EISR1]) << 32)));
>> +}
>> +
>> +static unsigned int gic_update_lr_for_mi(int lr)
>> +{
>> +    u64 val;
>> +    uint32_t virq;
>> +
>> +    spin_lock_irq(&gic.lock);
>> +    val = GICH[GICH_LR + lr];
>> +    virq = val & GICH_LR_VIRTUAL_MASK;
>> +    GICH[GICH_LR + lr] = 0;
>> +    spin_unlock_irq(&gic.lock);
>> +    return virq;
>> +}
>> +
>> +static struct gic_hw_operations gic_ops = {
>> +    .gic_type            = gic_hw_type,
>> +    .nr_lines            = gic_nr_lines,
>> +    .nr_lrs              = gic_nr_lrs,
>> +    .get_maintenance_irq = gic_maintenance_irq,
>> +    .state_init        = gic_state_init,
>> +    .save_state          = save_state,
>> +    .restore_state       = restore_state,
>> +    .dump_state          = gic_dump_state,
>> +    .gicv_setup          = gicv_init,
>> +    .enable_irq          = gic_enable_irq,
>> +    .disable_irq         = gic_disable_irq,
>> +    .eoi_irq             = gic_eoi_irq,
>> +    .deactivate_irq      = gic_dir_irq,
>> +    .ack_irq             = gic_ack_irq,
>> +    .set_irq_property    = gic_set_irq_properties,
>> +    .send_sgi            = gic_send_sgi,
>> +    .disable_interface   = gic_disable_interface,
>> +    .update_lr           = gic_update_lr,
>> +    .update_lr_for_mi    = gic_update_lr_for_mi,
>> +    .read_eisr           = gic_read_eisr,
>> +};
>> +
>> +void __init gicv2_init(void)
>> +{
>> +    static const struct dt_device_match gic_ids[] __initconst =
>> +    {
>> +        DT_MATCH_GIC,
>> +        { /* sentinel */ },
>> +    };
>> +    struct dt_device_node *node;
>> +    int res;
>> +
>> +    node = dt_find_interrupt_controller(gic_ids);
>> +    if ( !node )
>> +        panic("Unable to find compatible GIC in the device tree");
>> +
>> +    dt_device_set_used_by(node, DOMID_XEN);
>> +
>> +    gic.hw_version = GIC_VERSION_V2;
>> +
>> +    res = dt_device_get_address(node, 0, &gic.dbase, NULL);
>> +    if ( res || !gic.dbase || (gic.dbase & ~PAGE_MASK) )
>> +        panic("GIC: Cannot find a valid address for the distributor");
>> +
>> +    res = dt_device_get_address(node, 1, &gic.cbase, NULL);
>> +    if ( res || !gic.cbase || (gic.cbase & ~PAGE_MASK) )
>> +        panic("GIC: Cannot find a valid address for the CPU");
>> +
>> +    res = dt_device_get_address(node, 2, &gic.hbase, NULL);
>> +    if ( res || !gic.hbase || (gic.hbase & ~PAGE_MASK) )
>> +        panic("GIC: Cannot find a valid address for the hypervisor");
>> +
>> +    res = dt_device_get_address(node, 3, &gic.vbase, NULL);
>> +    if ( res || !gic.vbase || (gic.vbase & ~PAGE_MASK) )
>> +        panic("GIC: Cannot find a valid address for the virtual CPU");
>> +
>> +    res = dt_device_get_irq(node, 0, &gic.maintenance);
>> +    if ( res )
>> +        panic("GIC: Cannot find the maintenance IRQ");
>> +
>> +    /* Set the GIC as the primary interrupt controller */
>> +    dt_interrupt_controller = node;
>> +
>> +    /* TODO: Add check on distributor, cpu size */
>> +
>> +    printk("GIC initialization:\n"
>> +              "        gic_dist_addr=%"PRIpaddr"\n"
>> +              "        gic_cpu_addr=%"PRIpaddr"\n"
>> +              "        gic_hyp_addr=%"PRIpaddr"\n"
>> +              "        gic_vcpu_addr=%"PRIpaddr"\n"
>> +              "        gic_maintenance_irq=%u\n",
>> +              gic.dbase, gic.cbase, gic.hbase, gic.vbase,
>> +              gic.maintenance.irq);
>> +
>> +    if ( (gic.dbase & ~PAGE_MASK) || (gic.cbase & ~PAGE_MASK) ||
>> +         (gic.hbase & ~PAGE_MASK) || (gic.vbase & ~PAGE_MASK) )
>> +        panic("GIC interfaces not page aligned");
>> +
>> +    set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED);
>> +    BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) !=
>> +                 FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE);
>> +    set_fixmap(FIXMAP_GICC1, gic.cbase >> PAGE_SHIFT, DEV_SHARED);
>> +    if ( platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
>> +        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x10, 
>> DEV_SHARED);
>> +    else
>> +        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x1, 
>> DEV_SHARED);
>> +    set_fixmap(FIXMAP_GICH, gic.hbase >> PAGE_SHIFT, DEV_SHARED);
>> +
>> +    /* Global settings: interrupt distributor */
>> +    spin_lock_init(&gic.lock);
>> +    spin_lock(&gic.lock);
>> +
>> +    gic_smp_init();
>> +    gic_dist_init();
>> +    gic_cpu_init();
>> +    gic_hyp_init();
>> +
>> +    register_gic_ops(&gic_ops);
>> +    spin_unlock(&gic.lock);
>> +}
>> +
>> +/*
>> + * Local variables:
>> + * mode: C
>> + * c-file-style: "BSD"
>> + * c-basic-offset: 4
>> + * indent-tabs-mode: nil
>> + * End:
>> + */
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index bb718f6..e0859ae 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -33,68 +33,46 @@
>>  #include <asm/domain.h>
>>  #include <asm/platform.h>
>>
>> -#include <asm/gic_v2_defs.h>
>>  #include <asm/gic.h>
>>
>> -/* Access to the GIC Distributor registers through the fixmap */
>> -#define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
>> -#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
>> -#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH))
>>  static void gic_restore_pending_irqs(struct vcpu *v);
>>
>> -struct gic_state_data {
>> -    uint32_t gic_hcr;
>> -    uint32_t gic_vmcr;
>> -    uint32_t gic_apr;
>> -    uint32_t gic_lr[64];
>> -};
>> -
>> -/* Global state */
>> -static struct {
>> -    paddr_t dbase;       /* Address of distributor registers */
>> -    paddr_t cbase;       /* Address of CPU interface registers */
>> -    paddr_t hbase;       /* Address of virtual interface registers */
>> -    paddr_t vbase;       /* Address of virtual cpu interface registers */
>> -    unsigned int lines;  /* Number of interrupts (SPIs + PPIs + SGIs) */
>> -    struct dt_irq maintenance; /* IRQ maintenance */
>> -    unsigned int cpus;
>> -    spinlock_t lock;
>> -} gic;
>> -
>>  static irq_desc_t irq_desc[NR_IRQS];
>>  static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
>>  static DEFINE_PER_CPU(uint64_t, lr_mask);
>>
>> -static unsigned nr_lrs;
>> -
>> -/* The GIC mapping of CPU interfaces does not necessarily match the
>> - * logical CPU numbering. Let's use mapping as returned by the GIC
>> - * itself
>> - */
>> -static DEFINE_PER_CPU(u8, gic_cpu_id);
>> +static struct gic_hw_operations *gic_hw_ops;
>>
>> -/* Maximum cpu interface per GIC */
>> -#define NR_GIC_CPU_IF 8
>> +spinlock_t gic_lock;
>>
>> -static unsigned int gic_cpu_mask(const cpumask_t *cpumask)
>> +void register_gic_ops(struct gic_hw_operations *ops)
>>  {
>> -    unsigned int cpu;
>> -    unsigned int mask = 0;
>> -    cpumask_t possible_mask;
>> +    gic_hw_ops = ops;
>> +}
>>
>> -    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
>> -    for_each_cpu(cpu, &possible_mask)
>> -    {
>> -        ASSERT(cpu < NR_GIC_CPU_IF);
>> -        mask |= per_cpu(gic_cpu_id, cpu);
>> -    }
>> +void update_cpu_lr_mask(void)
>> +{
>> +    this_cpu(lr_mask) = 0ULL;
>> +}
>>
>> -    return mask;
>> +int gic_hw_version(void)
>> +{
>> +   return gic_hw_ops->gic_type();
>>  }
>>
>>  unsigned int gic_number_lines(void)
>>  {
>> -    return gic.lines;
>> +    return gic_hw_ops->nr_lines();
>> +}
>> +
>> +unsigned long gic_data_rdist_rd_base(void)
>> +{
>> +   return gic_hw_ops->read_cpu_rbase();
>> +}
>> +
>> +unsigned long gic_data_rdist_sgi_base(void)
>> +{
>> +   return gic_hw_ops->read_cpu_sgi_rbase();
>>  }
>>
>>  irq_desc_t *__irq_to_desc(int irq)
>> @@ -105,43 +83,21 @@ irq_desc_t *__irq_to_desc(int irq)
>>
>>  void gic_save_state(struct vcpu *v)
>>  {
>> -    int i;
>> -    struct gic_state_data *d;
>> -    d = (struct gic_state_data *)v->arch.gic_state;
>> -
>>      ASSERT(!local_irq_is_enabled());
>>
>> -    /* 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.
>> -     */
>> -    for ( i=0; i<nr_lrs; i++)
>> -        d->gic_lr[i] = GICH[GICH_LR + i];
>>      v->arch.lr_mask = this_cpu(lr_mask);
>> -    d->gic_apr = GICH[GICH_APR];
>> -    d->gic_vmcr = GICH[GICH_VMCR];
>> -    /* Disable until next VCPU scheduled */
>> -    GICH[GICH_HCR] = 0;
>> +    gic_hw_ops->save_state(v);
>>      isb();
>>  }
>>
>>  void gic_restore_state(struct vcpu *v)
>>  {
>> -    int i;
>> -    struct gic_state_data *d;
>> -    d = (struct gic_state_data *)v->arch.gic_state;
>> -
>>      if ( is_idle_vcpu(v) )
>>          return;
>>
>>      this_cpu(lr_mask) = v->arch.lr_mask;
>> -    for ( i=0; i<nr_lrs; i++)
>> -        GICH[GICH_LR + i] = d->gic_lr[i];
>> -    GICH[GICH_APR] = d->gic_apr;
>> -    GICH[GICH_VMCR] = d->gic_vmcr;
>> -    GICH[GICH_HCR] = GICH_HCR_EN;
>> +    gic_hw_ops->restore_state(v);
>>      isb();
>> -
>>      gic_restore_pending_irqs(v);
>>  }
>>
>> @@ -151,12 +107,12 @@ static void gic_irq_enable(struct irq_desc *desc)
>>      unsigned long flags;
>>
>>      spin_lock_irqsave(&desc->lock, flags);
>> -    spin_lock(&gic.lock);
>> +    spin_lock(&gic_lock);
>>      desc->status &= ~IRQ_DISABLED;
>>      dsb();
>>      /* Enable routing */
>> -    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
>> -    spin_unlock(&gic.lock);
>> +    gic_hw_ops->enable_irq(irq);
>> +    spin_unlock(&gic_lock);
>>      spin_unlock_irqrestore(&desc->lock, flags);
>>  }
>>
>> @@ -166,11 +122,11 @@ static void gic_irq_disable(struct irq_desc *desc)
>>      unsigned long flags;
>>
>>      spin_lock_irqsave(&desc->lock, flags);
>> -    spin_lock(&gic.lock);
>> +    spin_lock(&gic_lock);
>>      /* Disable routing */
>> -    GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
>> +    gic_hw_ops->disable_irq(irq);
>>      desc->status |= IRQ_DISABLED;
>> -    spin_unlock(&gic.lock);
>> +    spin_unlock(&gic_lock);
>>      spin_unlock_irqrestore(&desc->lock, flags);
>>  }
>>
>> @@ -194,17 +150,16 @@ static void gic_host_irq_end(struct irq_desc *desc)
>>  {
>>      int irq = desc->irq;
>>      /* Lower the priority */
>> -    GICC[GICC_EOIR] = irq;
>> -    /* Deactivate */
>> -    GICC[GICC_DIR] = irq;
>> +    gic_hw_ops->eoi_irq(irq);
>> +    gic_hw_ops->deactivate_irq(irq);
>>  }
>>
>>  static void gic_guest_irq_end(struct irq_desc *desc)
>>  {
>>      int irq = desc->irq;
>>      /* Lower the priority of the IRQ */
>> -    GICC[GICC_EOIR] = irq;
>>      /* Deactivation happens in maintenance interrupt / via GICV */
>> +    gic_hw_ops->eoi_irq(irq);
>>  }
>>
>>  static void gic_irq_set_affinity(struct irq_desc *desc, const cpumask_t 
>> *mask)
>> @@ -243,27 +198,7 @@ static void gic_set_irq_properties(unsigned int irq, 
>> bool_t level,
>>                                     const cpumask_t *cpu_mask,
>>                                     unsigned int priority)
>>  {
>> -    volatile unsigned char *bytereg;
>> -    uint32_t cfg, edgebit;
>> -    unsigned int mask = gic_cpu_mask(cpu_mask);
>> -
>> -    /* Set edge / level */
>> -    cfg = GICD[GICD_ICFGR + irq / 16];
>> -    edgebit = 2u << (2 * (irq % 16));
>> -    if ( level )
>> -        cfg &= ~edgebit;
>> -    else
>> -        cfg |= edgebit;
>> -    GICD[GICD_ICFGR + irq / 16] = cfg;
>> -
>> -    /* Set target CPU mask (RAZ/WI on uniprocessor) */
>> -    bytereg = (unsigned char *) (GICD + GICD_ITARGETSR);
>> -    bytereg[irq] = mask;
>> -
>> -    /* Set priority */
>> -    bytereg = (unsigned char *) (GICD + GICD_IPRIORITYR);
>> -    bytereg[irq] = priority;
>> -
>> +    return gic_hw_ops->set_irq_property(irq, level, cpu_mask, priority);
>>  }
>>
>>  /* Program the GIC to route an interrupt */
>> @@ -273,8 +208,8 @@ static int gic_route_irq(unsigned int irq, bool_t level,
>>      struct irq_desc *desc = irq_to_desc(irq);
>>      unsigned long flags;
>>
>> -    ASSERT(priority <= 0xff);     /* Only 8 bits of priority */
>> -    ASSERT(irq < gic.lines);      /* Can't route interrupts that don't 
>> exist */
>> +    ASSERT(priority <= 0xff);  /* Only 8 bits of priority */
>> +    ASSERT(irq < gic_number_lines());
>>
>>      if ( desc->action != NULL )
>>          return -EBUSY;
>> @@ -286,9 +221,9 @@ static int gic_route_irq(unsigned int irq, bool_t level,
>>
>>      desc->handler = &gic_host_irq_type;
>>
>> -    spin_lock(&gic.lock);
>> +    spin_lock(&gic_lock);
>>      gic_set_irq_properties(irq, level, cpu_mask, priority);
>> -    spin_unlock(&gic.lock);
>> +    spin_unlock(&gic_lock);
>>
>>      spin_unlock_irqrestore(&desc->lock, flags);
>>      return 0;
>> @@ -305,119 +240,6 @@ void gic_route_dt_irq(const struct dt_irq *irq, const 
>> cpumask_t *cpu_mask,
>>      gic_route_irq(irq->irq, level, cpu_mask, priority);
>>  }
>>
>> -static void __init gic_dist_init(void)
>> -{
>> -    uint32_t type;
>> -    uint32_t cpumask;
>> -    int i;
>> -
>> -    cpumask = GICD[GICD_ITARGETSR] & 0xff;
>> -    cpumask |= cpumask << 8;
>> -    cpumask |= cpumask << 16;
>> -
>> -    /* Disable the distributor */
>> -    GICD[GICD_CTLR] = 0;
>> -
>> -    type = GICD[GICD_TYPER];
>> -    gic.lines = 32 * ((type & GICD_TYPE_LINES) + 1);
>> -    gic.cpus = 1 + ((type & GICD_TYPE_CPUS) >> 5);
>> -    printk("GIC: %d lines, %d cpu%s%s (IID %8.8x).\n",
>> -           gic.lines, gic.cpus, (gic.cpus == 1) ? "" : "s",
>> -           (type & GICD_TYPE_SEC) ? ", secure" : "",
>> -           GICD[GICD_IIDR]);
>> -
>> -    /* Default all global IRQs to level, active low */
>> -    for ( i = 32; i < gic.lines; i += 16 )
>> -        GICD[GICD_ICFGR + i / 16] = 0x0;
>> -
>> -    /* Route all global IRQs to this CPU */
>> -    for ( i = 32; i < gic.lines; i += 4 )
>> -        GICD[GICD_ITARGETSR + i / 4] = cpumask;
>> -
>> -    /* Default priority for global interrupts */
>> -    for ( i = 32; i < gic.lines; i += 4 )
>> -        GICD[GICD_IPRIORITYR + i / 4] =
>> -            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | 
>> GIC_PRI_IRQ;
>> -
>> -    /* Disable all global interrupts */
>> -    for ( i = 32; i < gic.lines; i += 32 )
>> -        GICD[GICD_ICENABLER + i / 32] = (uint32_t)~0ul;
>> -
>> -    /* Turn on the distributor */
>> -    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
>> -}
>> -
>> -static void __cpuinit gic_cpu_init(void)
>> -{
>> -    int i;
>> -
>> -    this_cpu(gic_cpu_id) = GICD[GICD_ITARGETSR] & 0xff;
>> -
>> -    /* The first 32 interrupts (PPI and SGI) are banked per-cpu, so
>> -     * even though they are controlled with GICD registers, they must
>> -     * be set up here with the other per-cpu state. */
>> -    GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
>> -    GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */
>> -    /* Set SGI priorities */
>> -    for (i = 0; i < 16; i += 4)
>> -        GICD[GICD_IPRIORITYR + i / 4] =
>> -            GIC_PRI_IPI<<24 | GIC_PRI_IPI<<16 | GIC_PRI_IPI<<8 | 
>> GIC_PRI_IPI;
>> -    /* Set PPI priorities */
>> -    for (i = 16; i < 32; i += 4)
>> -        GICD[GICD_IPRIORITYR + i / 4] =
>> -            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | 
>> GIC_PRI_IRQ;
>> -
>> -    /* Local settings: interface controller */
>> -    GICC[GICC_PMR] = 0xff;                /* Don't mask by priority */
>> -    GICC[GICC_BPR] = 0;                   /* Finest granularity of priority 
>> */
>> -    GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI;    /* Turn on delivery 
>> */
>> -}
>> -
>> -static void gic_cpu_disable(void)
>> -{
>> -    GICC[GICC_CTLR] = 0;
>> -}
>> -
>> -static void __cpuinit gic_hyp_init(void)
>> -{
>> -    uint32_t vtr;
>> -
>> -    vtr = GICH[GICH_VTR];
>> -    nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
>> -
>> -    GICH[GICH_MISR] = GICH_MISR_EOI;
>> -    this_cpu(lr_mask) = 0ULL;
>> -}
>> -
>> -static void __cpuinit gic_hyp_disable(void)
>> -{
>> -    GICH[GICH_HCR] = 0;
>> -}
>> -
>> -/* Set up the per-CPU parts of the GIC for a secondary CPU */
>> -static int  __cpuinit gic_init_secondary_cpu(struct notifier_block *nfb,
>> -                                        unsigned long action, void *hcpu)
>> -{
>> -    if (action == CPU_STARTING)
>> -    {
>> -        spin_lock(&gic.lock);
>> -        gic_cpu_init();
>> -        gic_hyp_init();
>> -        spin_unlock(&gic.lock);
>> -    }
>> -    return NOTIFY_DONE;
>> -}
>> -
>> -static struct notifier_block gic_cpu_nb = {
>> -    .notifier_call = gic_init_secondary_cpu,
>> -    .priority = 100
>> -};
>> -
>> -static void gic_smp_init(void)
>> -{
>> -   register_cpu_notifier(&gic_cpu_nb);
>> -}
>> -
>>  int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
>>                    unsigned int *out_hwirq,
>>                    unsigned int *out_type)
>> @@ -438,124 +260,25 @@ int gic_irq_xlate(const u32 *intspec, unsigned int 
>> intsize,
>>      return 0;
>>  }
>>
>> -/* Set up the GIC */
>> -void __init gic_init(void)
>> -{
>> -    static const struct dt_device_match gic_ids[] __initconst =
>> -    {
>> -        DT_MATCH_GIC,
>> -        { /* sentinel */ },
>> -    };
>> -    struct dt_device_node *node;
>> -    int res;
>> -
>> -    node = dt_find_interrupt_controller(gic_ids);
>> -    if ( !node )
>> -        panic("Unable to find compatible GIC in the device tree");
>> -
>> -    dt_device_set_used_by(node, DOMID_XEN);
>> -
>> -    res = dt_device_get_address(node, 0, &gic.dbase, NULL);
>> -    if ( res || !gic.dbase || (gic.dbase & ~PAGE_MASK) )
>> -        panic("GIC: Cannot find a valid address for the distributor");
>> -
>> -    res = dt_device_get_address(node, 1, &gic.cbase, NULL);
>> -    if ( res || !gic.cbase || (gic.cbase & ~PAGE_MASK) )
>> -        panic("GIC: Cannot find a valid address for the CPU");
>> -
>> -    res = dt_device_get_address(node, 2, &gic.hbase, NULL);
>> -    if ( res || !gic.hbase || (gic.hbase & ~PAGE_MASK) )
>> -        panic("GIC: Cannot find a valid address for the hypervisor");
>> -
>> -    res = dt_device_get_address(node, 3, &gic.vbase, NULL);
>> -    if ( res || !gic.vbase || (gic.vbase & ~PAGE_MASK) )
>> -        panic("GIC: Cannot find a valid address for the virtual CPU");
>> -
>> -    res = dt_device_get_irq(node, 0, &gic.maintenance);
>> -    if ( res )
>> -        panic("GIC: Cannot find the maintenance IRQ");
>> -
>> -    /* Set the GIC as the primary interrupt controller */
>> -    dt_interrupt_controller = node;
>> -
>> -    /* TODO: Add check on distributor, cpu size */
>> -
>> -    printk("GIC initialization:\n"
>> -              "        gic_dist_addr=%"PRIpaddr"\n"
>> -              "        gic_cpu_addr=%"PRIpaddr"\n"
>> -              "        gic_hyp_addr=%"PRIpaddr"\n"
>> -              "        gic_vcpu_addr=%"PRIpaddr"\n"
>> -              "        gic_maintenance_irq=%u\n",
>> -              gic.dbase, gic.cbase, gic.hbase, gic.vbase,
>> -              gic.maintenance.irq);
>> -
>> -    if ( (gic.dbase & ~PAGE_MASK) || (gic.cbase & ~PAGE_MASK) ||
>> -         (gic.hbase & ~PAGE_MASK) || (gic.vbase & ~PAGE_MASK) )
>> -        panic("GIC interfaces not page aligned");
>> -
>> -    set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED);
>> -    BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) !=
>> -                 FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE);
>> -    set_fixmap(FIXMAP_GICC1, gic.cbase >> PAGE_SHIFT, DEV_SHARED);
>> -    if ( platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
>> -        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x10, 
>> DEV_SHARED);
>> -    else
>> -        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x1, 
>> DEV_SHARED);
>> -    set_fixmap(FIXMAP_GICH, gic.hbase >> PAGE_SHIFT, DEV_SHARED);
>> -
>> -    /* Global settings: interrupt distributor */
>> -    spin_lock_init(&gic.lock);
>> -    spin_lock(&gic.lock);
>> -
>> -    gic_smp_init();
>> -    gic_dist_init();
>> -    gic_cpu_init();
>> -    gic_hyp_init();
>> -
>> -    spin_unlock(&gic.lock);
>> -}
>> -
>>  void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
>>  {
>> -    unsigned int mask = 0;
>> -    cpumask_t online_mask;
>> -
>> -    ASSERT(sgi < 16); /* There are only 16 SGIs */
>> -
>> -    cpumask_and(&online_mask, cpumask, &cpu_online_map);
>> -    mask = gic_cpu_mask(&online_mask);
>> -
>> -    dsb();
>> -
>> -    GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST
>> -        | (mask<<GICD_SGI_TARGET_SHIFT)
>> -        | sgi;
>> +    gic_hw_ops->send_sgi(cpumask, sgi);
>>  }
>>
>> -void send_SGI_one(unsigned int cpu, enum gic_sgi sgi)
>> +static void send_SGI_one(unsigned int cpu, enum gic_sgi sgi)
>>  {
>> -    ASSERT(cpu < NR_GIC_CPU_IF);  /* Targets bitmap only supports 8 CPUs */
>>      send_SGI_mask(cpumask_of(cpu), sgi);
>>  }
>>
>> -void send_SGI_self(enum gic_sgi sgi)
>> -{
>> -    ASSERT(sgi < 16); /* There are only 16 SGIs */
>> -
>> -    dsb();
>> -
>> -    GICD[GICD_SGIR] = GICD_SGI_TARGET_SELF
>> -        | sgi;
>> -}
>> -
>>  void send_SGI_allbutself(enum gic_sgi sgi)
>>  {
>> -   ASSERT(sgi < 16); /* There are only 16 SGIs */
>> +    cpumask_t all_others_mask;
>> +    ASSERT(sgi < 16); /* There are only 16 SGIs */
>>
>> -   dsb();
>> +    cpumask_andnot(&all_others_mask, &cpu_possible_map, 
>> cpumask_of(smp_processor_id()));
>>
>> -   GICD[GICD_SGIR] = GICD_SGI_TARGET_OTHERS
>> -       | sgi;
>> +    dsb();
>> +    send_SGI_mask(&all_others_mask, sgi);
>>  }
>>
>>  void smp_send_state_dump(unsigned int cpu)
>> @@ -568,16 +291,15 @@ void gic_disable_cpu(void)
>>  {
>>      ASSERT(!local_irq_is_enabled());
>>
>> -    spin_lock(&gic.lock);
>> -    gic_cpu_disable();
>> -    gic_hyp_disable();
>> -    spin_unlock(&gic.lock);
>> +    spin_lock(&gic_lock);
>> +    gic_hw_ops->disable_interface();
>> +    spin_unlock(&gic_lock);
>>  }
>>
>>  void gic_route_ppis(void)
>>  {
>>      /* GIC maintenance */
>> -    gic_route_dt_irq(&gic.maintenance, cpumask_of(smp_processor_id()),
>> +    gic_route_dt_irq(gic_hw_ops->get_maintenance_irq(), 
>> cpumask_of(smp_processor_id()),
>>                       GIC_PRI_IRQ);
>>      /* Route timer interrupt */
>>      route_timer_interrupt();
>> @@ -652,20 +374,10 @@ int __init setup_dt_irq(const struct dt_irq *irq, 
>> struct irqaction *new)
>>      return rc;
>>  }
>>
>> -static inline void gic_set_lr(int lr, struct pending_irq *p,
>> +static void gic_set_lr(int lr, struct pending_irq *p,
>>          unsigned int state)
>>  {
>> -    int maintenance_int = GICH_LR_MAINTENANCE_IRQ;
>> -
>> -    BUG_ON(lr >= nr_lrs);
>> -    BUG_ON(lr < 0);
>> -    BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT));
>> -
>> -    GICH[GICH_LR + lr] = state |
>> -        maintenance_int |
>> -        ((p->priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
>> -        ((p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
>> -
>> +    gic_hw_ops->update_lr(lr, p->irq, state, p->priority);
>>      set_bit(GIC_IRQ_GUEST_VISIBLE, &p->status);
>>      clear_bit(GIC_IRQ_GUEST_PENDING, &p->status);
>>  }
>> @@ -693,10 +405,10 @@ void gic_remove_from_queues(struct vcpu *v, unsigned 
>> int virtual_irq)
>>      struct pending_irq *p = irq_to_pending(v, virtual_irq);
>>      unsigned long flags;
>>
>> -    spin_lock_irqsave(&gic.lock, flags);
>> +    spin_lock_irqsave(&gic_lock, flags);
>>      if ( !list_empty(&p->lr_queue) )
>>          list_del_init(&p->lr_queue);
>> -    spin_unlock_irqrestore(&gic.lock, flags);
>> +    spin_unlock_irqrestore(&gic_lock, flags);
>>  }
>>
>>  void gic_set_guest_irq(struct vcpu *v, unsigned int virtual_irq,
>> @@ -704,9 +416,9 @@ void gic_set_guest_irq(struct vcpu *v, unsigned int 
>> virtual_irq,
>>  {
>>      int i;
>>      unsigned long flags;
>> +    unsigned int nr_lrs = gic_hw_ops->nr_lrs();
>>
>> -    spin_lock_irqsave(&gic.lock, flags);
>> -
>> +    spin_lock_irqsave(&gic_lock, flags);
>>      if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
>>      {
>>          i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
>> @@ -720,7 +432,7 @@ void gic_set_guest_irq(struct vcpu *v, unsigned int 
>> virtual_irq,
>>      gic_add_to_lr_pending(v, irq_to_pending(v, virtual_irq));
>>
>>  out:
>> -    spin_unlock_irqrestore(&gic.lock, flags);
>> +    spin_unlock_irqrestore(&gic_lock, flags);
>>      return;
>>  }
>>
>> @@ -729,17 +441,18 @@ static void gic_restore_pending_irqs(struct vcpu *v)
>>      int i;
>>      struct pending_irq *p, *t;
>>      unsigned long flags;
>> +    unsigned int nr_lrs = gic_hw_ops->nr_lrs();
>>
>>      list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
>>      {
>>          i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
>>          if ( i >= nr_lrs ) return;
>>
>> -        spin_lock_irqsave(&gic.lock, flags);
>> +        spin_lock_irqsave(&gic_lock, flags);
>>          gic_set_lr(i, p, GICH_LR_PENDING);
>>          list_del_init(&p->lr_queue);
>>          set_bit(i, &this_cpu(lr_mask));
>> -        spin_unlock_irqrestore(&gic.lock, flags);
>> +        spin_unlock_irqrestore(&gic_lock, flags);
>>      }
>>
>>  }
>> @@ -749,11 +462,11 @@ void gic_clear_pending_irqs(struct vcpu *v)
>>      struct pending_irq *p, *t;
>>      unsigned long flags;
>>
>> -    spin_lock_irqsave(&gic.lock, flags);
>> +    spin_lock_irqsave(&gic_lock, flags);
>>      v->arch.lr_mask = 0;
>>      list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
>>          list_del_init(&p->lr_queue);
>> -    spin_unlock_irqrestore(&gic.lock, flags);
>> +    spin_unlock_irqrestore(&gic_lock, flags);
>>  }
>>
>>  static void gic_inject_irq_start(void)
>> @@ -809,7 +522,7 @@ int gic_route_irq_to_guest(struct domain *d, const 
>> struct dt_irq *irq,
>>      action->free_on_release = 1;
>>
>>      spin_lock_irqsave(&desc->lock, flags);
>> -    spin_lock(&gic.lock);
>> +    spin_lock(&gic_lock);
>>
>>      desc->handler = &gic_guest_irq_type;
>>      desc->status |= IRQ_GUEST;
>> @@ -830,15 +543,15 @@ int gic_route_irq_to_guest(struct domain *d, const 
>> struct dt_irq *irq,
>>      p->desc = desc;
>>
>>  out:
>> -    spin_unlock(&gic.lock);
>> +    spin_unlock(&gic_lock);
>>      spin_unlock_irqrestore(&desc->lock, flags);
>>      return retval;
>>  }
>>
>> -static void do_sgi(struct cpu_user_regs *regs, int othercpu, enum gic_sgi 
>> sgi)
>> +static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
>>  {
>>      /* Lower the priority */
>> -    GICC[GICC_EOIR] = sgi;
>> +    gic_hw_ops->eoi_irq(sgi);
>>
>>      switch (sgi)
>>      {
>> @@ -857,20 +570,17 @@ static void do_sgi(struct cpu_user_regs *regs, int 
>> othercpu, enum gic_sgi sgi)
>>      }
>>
>>      /* Deactivate */
>> -    GICC[GICC_DIR] = sgi;
>> +    gic_hw_ops->deactivate_irq(sgi);
>>  }
>>
>>  /* Accept an interrupt from the GIC and dispatch its handler */
>>  void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
>>  {
>> -    uint32_t intack;
>>      unsigned int irq;
>>
>>
>>      do  {
>> -        intack = GICC[GICC_IAR];
>> -        irq = intack & GICC_IA_IRQ;
>> -
>> +        irq = gic_hw_ops->ack_irq();
>>          if ( likely(irq >= 16 && irq < 1021) )
>>          {
>>              local_irq_enable();
>> @@ -879,8 +589,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int 
>> is_fiq)
>>          }
>>          else if (unlikely(irq < 16))
>>          {
>> -            unsigned int cpu = (intack & GICC_IA_CPU_MASK) >> 
>> GICC_IA_CPU_SHIFT;
>> -            do_sgi(regs, cpu, irq);
>> +            do_sgi(regs, irq);
>>          }
>>          else
>>          {
>> @@ -892,72 +601,31 @@ void gic_interrupt(struct cpu_user_regs *regs, int 
>> is_fiq)
>>
>>  int vcpu_gic_init(struct vcpu *v)
>>  {
>> -     v->arch.gic_state = xzalloc(struct gic_state_data);
>> -     if(!v->arch.gic_state)
>> -        return -ENOMEM;
>> -     return 0;
>> +     return gic_hw_ops->state_init(v);
>>  }
>>
>>  int gicv_setup(struct domain *d)
>>  {
>>      int ret;
>>
>> -    /*
>> -     * Domain 0 gets the hardware address.
>> -     * Guests get the virtual platform layout.
>> -     */
>> -    if ( d->domain_id == 0 )
>> -    {
>> -        d->arch.vgic.dbase = gic.dbase;
>> -        d->arch.vgic.cbase = gic.cbase;
>> -    }
>> -    else
>> -    {
>> -        d->arch.vgic.dbase = GUEST_GICD_BASE;
>> -        d->arch.vgic.cbase = GUEST_GICC_BASE;
>> -    }
>> -
>> -    d->arch.vgic.nr_lines = 0;
>> -
>> -    /*
>> -     * Map the gic virtual cpu interface in the gic cpu interface
>> -     * region of the guest.
>> -     *
>> -     * The second page is always mapped at +4K irrespective of the
>> -     * GIC_64K_STRIDE quirk. The DTB passed to the guest reflects this.
>> -     */
>> -    ret = map_mmio_regions(d, d->arch.vgic.cbase,
>> -                           d->arch.vgic.cbase + PAGE_SIZE - 1,
>> -                           gic.vbase);
>> -    if (ret)
>> -        return ret;
>> -
>> -    if ( !platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
>> -        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
>> -                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
>> -                               gic.vbase + PAGE_SIZE);
>> -    else
>> -        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
>> -                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
>> -                               gic.vbase + 16*PAGE_SIZE);
>> -
>> +    ret = gic_hw_ops->gicv_setup(d);
>>      return ret;
>>
>>  }
>>
>>  static void gic_irq_eoi(void *info)
>> -{
>> +{
>>      int virq = (uintptr_t) info;
>> -    GICC[GICC_DIR] = virq;
>> +    gic_hw_ops->deactivate_irq(virq);
>>  }
>>
>>  static void maintenance_interrupt(int irq, void *dev_id, struct 
>> cpu_user_regs *regs)
>>  {
>>      int i = 0, virq, pirq = -1;
>> -    uint32_t lr;
>>      struct vcpu *v = current;
>> -    uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 
>> 32);
>> +    unsigned long eisr = 0;
>>
>> +    eisr = gic_hw_ops->read_eisr();
>>      while ((i = find_next_bit((const long unsigned int *) &eisr,
>>                                64, i)) < 64) {
>>          struct pending_irq *p, *p2;
>> @@ -967,10 +635,9 @@ static void maintenance_interrupt(int irq, void 
>> *dev_id, struct cpu_user_regs *r
>>          cpu = -1;
>>          inflight = 0;
>>
>> -        spin_lock_irq(&gic.lock);
>> -        lr = GICH[GICH_LR + i];
>> -        virq = lr & GICH_LR_VIRTUAL_MASK;
>> -        GICH[GICH_LR + i] = 0;
>> +        spin_lock_irq(&gic_lock);
>> +        virq = gic_hw_ops->update_lr_for_mi(i);
>> +
>>          clear_bit(i, &this_cpu(lr_mask));
>>
>>          p = irq_to_pending(v, virq);
>> @@ -995,7 +662,7 @@ static void maintenance_interrupt(int irq, void *dev_id, 
>> struct cpu_user_regs *r
>>              list_del_init(&p2->lr_queue);
>>              set_bit(i, &this_cpu(lr_mask));
>>          }
>> -        spin_unlock_irq(&gic.lock);
>> +        spin_unlock_irq(&gic_lock);
>>
>>          if ( !inflight )
>>          {
>> @@ -1018,22 +685,37 @@ static void maintenance_interrupt(int irq, void 
>> *dev_id, struct cpu_user_regs *r
>>      }
>>  }
>>
>> +/* Set up the GIC */
>> +void __init gic_init(void)
>> +{
>> +    static const struct dt_device_match gicv2_ids[] __initconst =
>> +    {
>> +        DT_MATCH_GIC,
>> +        { /* sentinel */ },
>> +    };
>> +    struct dt_device_node *node;
>> +
>> +    spin_lock_init(&gic_lock);
>> +
>> +    spin_lock(&gic_lock);
>> +    node = dt_find_interrupt_controller(gicv2_ids);
>> +    if ( node )
>> +    {
>> +        gicv2_init();
>> +        spin_unlock(&gic_lock);
>> +        return;
>> +    }
>> +    spin_unlock(&gic_lock);
>> +    if ( !node )
>> +        panic("Unable to find compatible GIC in the device tree");
>> +}
>> +
>>  void gic_dump_info(struct vcpu *v)
>>  {
>> -    int i;
>>      struct pending_irq *p;
>> -    struct gic_state_data *d;
>> -    d = (struct gic_state_data *)v->arch.gic_state;
>>
>>      printk("GICH_LRs (vcpu %d) mask=%"PRIx64"\n", v->vcpu_id, 
>> v->arch.lr_mask);
>> -    if ( v == current )
>> -    {
>> -        for ( i = 0; i < nr_lrs; i++ )
>> -            printk("   HW_LR[%d]=%x\n", i, GICH[GICH_LR + i]);
>> -    } else {
>> -        for ( i = 0; i < nr_lrs; i++ )
>> -            printk("   VCPU_LR[%d]=%x\n", i, d->gic_lr[i]);
>> -    }
>> +    gic_hw_ops->dump_state(v);
>>
>>      list_for_each_entry ( p, &v->arch.vgic.inflight_irqs, inflight )
>>      {
>> @@ -1049,7 +731,7 @@ void gic_dump_info(struct vcpu *v)
>>
>>  void __cpuinit init_maintenance_interrupt(void)
>>  {
>> -    request_dt_irq(&gic.maintenance, maintenance_interrupt,
>> +    request_dt_irq(gic_hw_ops->get_maintenance_irq(), maintenance_interrupt,
>>                     "irq-maintenance", NULL);
>>  }
>>
>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>> index 18656fd..4244491 100644
>> --- a/xen/include/asm-arm/gic.h
>> +++ b/xen/include/asm-arm/gic.h
>> @@ -39,6 +39,8 @@
>>  #define GIC_PRI_IPI        0x90 /* IPIs must preempt normal interrupts */
>>  #define GIC_PRI_HIGHEST    0x80 /* Higher priorities belong to Secure-World 
>> */
>>
>> +#define GICH_LR_PENDING    1
>> +#define GICH_LR_ACTIVE     2
>>
>>  #ifndef __ASSEMBLY__
>>  #include <xen/device_tree.h>
>> @@ -46,12 +48,15 @@
>>  #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
>>                          DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")
>>
>> +extern int gic_hw_version(void);
>>  extern int domain_vgic_init(struct domain *d);
>>  extern void domain_vgic_free(struct domain *d);
>>
>>  extern int vcpu_vgic_init(struct vcpu *v);
>>  extern int vcpu_gic_init(struct vcpu *v);
>>
>> +extern void gicv2_init(void);
>> +
>>  extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq,int 
>> virtual);
>>  extern void vgic_clear_pending_irqs(struct vcpu *v);
>>  extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
>> @@ -88,14 +93,47 @@ extern int gicv_setup(struct domain *d);
>>  extern void gic_save_state(struct vcpu *v);
>>  extern void gic_restore_state(struct vcpu *v);
>>
>> +#define GIC_VERSION_V2 0x2
>> +
>>  /* SGI (AKA IPIs) */
>>  enum gic_sgi {
>>      GIC_SGI_EVENT_CHECK = 0,
>>      GIC_SGI_DUMP_STATE  = 1,
>>      GIC_SGI_CALL_FUNCTION = 2,
>>  };
>> +
>> +struct gic_hw_operations {
>> +    int (*gic_type)(void);
>> +    struct dt_irq * (*get_maintenance_irq)(void);
>> +    unsigned int (*nr_lines)(void);
>> +    unsigned int (*nr_lrs)(void);
>> +    int (*state_init)(struct vcpu *);
>> +    void (*save_state)(struct vcpu *);
>> +    void (*restore_state)(struct vcpu *);
>> +    void (*dump_state)(struct vcpu *);
>> +    int (*gicv_setup)(struct domain *);
>> +    void (*enable_irq)(int);
>> +    void (*disable_irq)(int);
>> +    void (*eoi_irq)(int);
>> +    void (*deactivate_irq)(int);
>> +    unsigned int (*ack_irq)(void);
>> +    void (*set_irq_property)(unsigned int irq, bool_t level,
>> +                            const cpumask_t *cpu_mask,
>> +                            unsigned int priority);
>> +    void (*send_sgi)(const cpumask_t *, enum gic_sgi);
>> +    void (*disable_interface)(void);
>> +    void (*update_lr)(int lr, unsigned int virtual_irq,
>> +                          unsigned int state, unsigned int priority);
>> +    unsigned int (*update_lr_for_mi)(int lr);
>> +    unsigned long (*read_eisr)(void);
>> +    unsigned long (*read_cpu_rbase)(void);
>> +    unsigned long (*read_cpu_sgi_rbase)(void);
>> +};
>> +
>> +extern void register_gic_ops(struct gic_hw_operations *);
>> +
>> +extern void update_cpu_lr_mask(void);
>>  extern void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi);
>> -extern void send_SGI_one(unsigned int cpu, enum gic_sgi sgi);
>>  extern void send_SGI_self(enum gic_sgi sgi);
>>  extern void send_SGI_allbutself(enum gic_sgi sgi);
>>
>> diff --git a/xen/include/asm-arm/gic_v2_defs.h 
>> b/xen/include/asm-arm/gic_v2_defs.h
>> index 2366685..5ddd48a 100644
>> --- a/xen/include/asm-arm/gic_v2_defs.h
>> +++ b/xen/include/asm-arm/gic_v2_defs.h
>> @@ -119,8 +119,6 @@
>>  #define GICH_LR_STATE_SHIFT     28
>>  #define GICH_LR_PRIORITY_SHIFT  23
>>  #define GICH_LR_MAINTENANCE_IRQ (1<<19)
>> -#define GICH_LR_PENDING         (1<<28)
>> -#define GICH_LR_ACTIVE          (1<<29)
>>  #define GICH_LR_GRP1            (1<<30)
>>  #define GICH_LR_HW              (1<<31)
>>  #define GICH_LR_CPUID_SHIFT     9
>> --
>> 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®.