[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 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? > 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |