[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 13/16] xen/arm: Add support for GIC v3
On Mon, 26 May 2014, vijay.kilari@xxxxxxxxx wrote: > From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> > > Add support for GIC v3 specification System register access(SRE) > is enabled to access cpu and virtual interface regiseters based > on kernel GICv3 driver. > > This patch adds only basic v3 support. > Does not support Interrupt Translation support (ITS) > > Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> > --- > xen/arch/arm/Makefile | 1 + > xen/arch/arm/gic-v3.c | 1125 > +++++++++++++++++++++++++++++++++++++ > xen/include/asm-arm/domain.h | 8 + > xen/include/asm-arm/gic.h | 20 + > xen/include/asm-arm/gic_v3_defs.h | 157 ++++++ > xen/include/asm-arm/processor.h | 14 + > xen/include/xen/lib.h | 2 + > 7 files changed, 1327 insertions(+) > > diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile > index 20f59f4..1684c09 100644 > --- a/xen/arch/arm/Makefile > +++ b/xen/arch/arm/Makefile > @@ -11,6 +11,7 @@ obj-y += domctl.o > obj-y += sysctl.o > obj-y += domain_build.o > obj-y += gic.o gic-v2.o > +obj-$(CONFIG_ARM_64) += gic-v3.o > obj-y += io.o > obj-y += irq.o > obj-y += kernel.o > diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c > new file mode 100644 > index 0000000..7543fb4 > --- /dev/null > +++ b/xen/arch/arm/gic-v3.c > @@ -0,0 +1,1125 @@ > +/* > + * xen/arch/arm/gic-v3.c > + * > + * ARM Generic Interrupt Controller support v3 version > + * based on xen/arch/arm/gic-v2.c and kernel GICv3 driver > + * > + * Copyright (C) 2012,2013 - ARM Ltd > + * Marc Zyngier <marc.zyngier@xxxxxxx> > + * > + * Vijaya Kumar K <vijaya.kumar@xxxxxxxxxxxxxxxxxx>, Cavium Inc > + * ported to Xen > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#include <xen/config.h> > +#include <xen/lib.h> > +#include <xen/init.h> > +#include <xen/cpu.h> > +#include <xen/mm.h> > +#include <xen/irq.h> > +#include <xen/sched.h> > +#include <xen/errno.h> > +#include <xen/delay.h> > +#include <xen/device_tree.h> > +#include <xen/libfdt/libfdt.h> > +#include <asm/p2m.h> > +#include <asm/domain.h> > +#include <asm/platform.h> > +#include <asm/io.h> > +#include <asm/device.h> > +#include <asm/gic.h> > +#include <asm/gic_v3_defs.h> > + > +struct rdist_region { > + paddr_t base; > + paddr_t size; > + void __iomem *map_base; > +}; > + > +/* Global state */ > +static struct { > + paddr_t dbase; /* Address of distributor registers */ > + paddr_t dbase_size; > + void __iomem *map_dbase; /* Mapped address of distributor registers */ > + struct rdist_region *rdist_regions; > + uint32_t rdist_stride; > + unsigned int rdist_count; /* Number of rdist regions count */ > + unsigned int nr_priorities; > + spinlock_t lock; > +}gicv3; > + > +static struct gic_info gicv3_info; > + > +/* per-cpu re-distributor base */ > +static DEFINE_PER_CPU(void __iomem*, rbase); > + > +#define GICD (gicv3.map_dbase) > +#define GICD_RDIST_BASE (this_cpu(rbase)) > +#define GICD_RDIST_SGI_BASE (GICD_RDIST_BASE + SZ_64K) > + > +/* > + * Saves all 16(Max) LR registers. Though number of LRs implemented > + * is implementation specific. > + */ > +static inline void gicv3_save_lr(int nr_lrs, struct vcpu *v) > +{ > + /* Fall through for all the cases */ > + switch ( nr_lrs ) > + { > + case 16: > + v->arch.gic.v3.lr[15] = READ_SYSREG(ICH_LR15_EL2); > + case 15: > + v->arch.gic.v3.lr[14] = READ_SYSREG(ICH_LR14_EL2); > + case 14: > + v->arch.gic.v3.lr[13] = READ_SYSREG(ICH_LR13_EL2); > + case 13: > + v->arch.gic.v3.lr[12] = READ_SYSREG(ICH_LR12_EL2); > + case 12: > + v->arch.gic.v3.lr[11] = READ_SYSREG(ICH_LR11_EL2); > + case 11: > + v->arch.gic.v3.lr[10] = READ_SYSREG(ICH_LR10_EL2); > + case 10: > + v->arch.gic.v3.lr[9] = READ_SYSREG(ICH_LR9_EL2); > + case 9: > + v->arch.gic.v3.lr[8] = READ_SYSREG(ICH_LR8_EL2); > + case 8: > + v->arch.gic.v3.lr[7] = READ_SYSREG(ICH_LR7_EL2); > + case 7: > + v->arch.gic.v3.lr[6] = READ_SYSREG(ICH_LR6_EL2); > + case 6: > + v->arch.gic.v3.lr[5] = READ_SYSREG(ICH_LR5_EL2); > + case 5: > + v->arch.gic.v3.lr[4] = READ_SYSREG(ICH_LR4_EL2); > + case 4: > + v->arch.gic.v3.lr[3] = READ_SYSREG(ICH_LR3_EL2); > + case 3: > + v->arch.gic.v3.lr[2] = READ_SYSREG(ICH_LR2_EL2); > + case 2: > + v->arch.gic.v3.lr[1] = READ_SYSREG(ICH_LR1_EL2); > + case 1: > + v->arch.gic.v3.lr[0] = READ_SYSREG(ICH_LR0_EL2); > + break; > + default: > + BUG(); > + } > +} > + > +/* > + * Restores all 16(Max) LR registers. Though number of LRs implemented > + * is implementation specific. > + */ > +static inline void gicv3_restore_lr(int nr_lrs, const struct vcpu *v) > +{ > + /* Fall through for all the cases */ > + switch ( nr_lrs ) > + { > + case 16: > + WRITE_SYSREG(v->arch.gic.v3.lr[15], ICH_LR15_EL2); > + case 15: > + WRITE_SYSREG(v->arch.gic.v3.lr[14], ICH_LR14_EL2); > + case 14: > + WRITE_SYSREG(v->arch.gic.v3.lr[13], ICH_LR13_EL2); > + case 13: > + WRITE_SYSREG(v->arch.gic.v3.lr[12], ICH_LR12_EL2); > + case 12: > + WRITE_SYSREG(v->arch.gic.v3.lr[11], ICH_LR11_EL2); > + case 11: > + WRITE_SYSREG(v->arch.gic.v3.lr[10], ICH_LR10_EL2); > + case 10: > + WRITE_SYSREG(v->arch.gic.v3.lr[9], ICH_LR9_EL2); > + case 9: > + WRITE_SYSREG(v->arch.gic.v3.lr[8], ICH_LR8_EL2); > + case 8: > + WRITE_SYSREG(v->arch.gic.v3.lr[7], ICH_LR7_EL2); > + case 7: > + WRITE_SYSREG(v->arch.gic.v3.lr[6], ICH_LR6_EL2); > + case 6: > + WRITE_SYSREG(v->arch.gic.v3.lr[5], ICH_LR5_EL2); > + case 5: > + WRITE_SYSREG(v->arch.gic.v3.lr[4], ICH_LR4_EL2); > + case 4: > + WRITE_SYSREG(v->arch.gic.v3.lr[3], ICH_LR3_EL2); > + case 3: > + WRITE_SYSREG(v->arch.gic.v3.lr[2], ICH_LR2_EL2); > + case 2: > + WRITE_SYSREG(v->arch.gic.v3.lr[1], ICH_LR1_EL2); > + case 1: > + WRITE_SYSREG(v->arch.gic.v3.lr[0], ICH_LR0_EL2); > + break; > + default: > + BUG(); > + } > +} Given that the number of LR registers has grown up quite a bit from GICv2, we should optimize this code and only save and restore the registers that are actually in used by checking on lr_mask. It would also help performances if we restored them in ascending order. > +static uint64_t gicv3_ich_read_lr(int lr) > +{ > + switch ( lr ) > + { > + case 0: return READ_SYSREG(ICH_LR0_EL2); > + case 1: return READ_SYSREG(ICH_LR1_EL2); > + case 2: return READ_SYSREG(ICH_LR2_EL2); > + case 3: return READ_SYSREG(ICH_LR3_EL2); > + case 4: return READ_SYSREG(ICH_LR4_EL2); > + case 5: return READ_SYSREG(ICH_LR5_EL2); > + case 6: return READ_SYSREG(ICH_LR6_EL2); > + case 7: return READ_SYSREG(ICH_LR7_EL2); > + case 8: return READ_SYSREG(ICH_LR8_EL2); > + case 9: return READ_SYSREG(ICH_LR9_EL2); > + case 10: return READ_SYSREG(ICH_LR10_EL2); > + case 11: return READ_SYSREG(ICH_LR11_EL2); > + case 12: return READ_SYSREG(ICH_LR12_EL2); > + case 13: return READ_SYSREG(ICH_LR13_EL2); > + case 14: return READ_SYSREG(ICH_LR14_EL2); > + case 15: return READ_SYSREG(ICH_LR15_EL2); > + default: > + BUG(); > + } > +} > + > +static void gicv3_ich_write_lr(int lr, uint64_t val) > +{ > + switch ( lr ) > + { > + case 0: > + WRITE_SYSREG(val, ICH_LR0_EL2); > + break; > + case 1: > + WRITE_SYSREG(val, ICH_LR1_EL2); > + break; > + case 2: > + WRITE_SYSREG(val, ICH_LR2_EL2); > + break; > + case 3: > + WRITE_SYSREG(val, ICH_LR3_EL2); > + break; > + case 4: > + WRITE_SYSREG(val, ICH_LR4_EL2); > + break; > + case 5: > + WRITE_SYSREG(val, ICH_LR5_EL2); > + break; > + case 6: > + WRITE_SYSREG(val, ICH_LR6_EL2); > + break; > + case 7: > + WRITE_SYSREG(val, ICH_LR7_EL2); > + break; > + case 8: > + WRITE_SYSREG(val, ICH_LR8_EL2); > + break; > + case 9: > + WRITE_SYSREG(val, ICH_LR9_EL2); > + break; > + case 10: > + WRITE_SYSREG(val, ICH_LR10_EL2); > + break; > + case 11: > + WRITE_SYSREG(val, ICH_LR11_EL2); > + break; > + case 12: > + WRITE_SYSREG(val, ICH_LR12_EL2); > + break; > + case 13: > + WRITE_SYSREG(val, ICH_LR13_EL2); > + break; > + case 14: > + WRITE_SYSREG(val, ICH_LR14_EL2); > + break; > + case 15: > + WRITE_SYSREG(val, ICH_LR15_EL2); > + break; > + default: > + return; > + } > +} > + > +/* > + * System Register Enable (SRE). Enable to access CPU & Virtual > + * interface registers as system registers in EL2 > + */ > +static void gicv3_enable_sre(void) > +{ > + uint32_t val; > + > + val = READ_SYSREG32(ICC_SRE_EL2); > + val |= GICC_SRE_EL2_SRE | GICC_SRE_EL2_ENEL1 | > + GICC_SRE_EL2_DFB | GICC_SRE_EL2_DIB; > + > + WRITE_SYSREG32(val, ICC_SRE_EL2); > + isb(); > +} > + > +/* Wait for completion of a distributor change */ > +static void gicv3_do_wait_for_rwp(void __iomem *base) > +{ > + uint32_t val; > + bool_t timeout = 0; > + s_time_t deadline = NOW() + MILLISECS(1000); > + > + do { > + val = readl_relaxed(base + GICD_CTLR); > + if ( !(val & GICD_CTLR_RWP) ) > + break; > + if ( NOW() > deadline ) > + { > + timeout = 1; > + break; > + } > + cpu_relax(); > + udelay(1); > + } while ( 1 ); > + > + if ( timeout ) > + dprintk(XENLOG_ERR, "RWP timeout\n"); > +} > + > +static void gicv3_dist_wait_for_rwp(void) > +{ > + gicv3_do_wait_for_rwp(GICD); > +} > + > +static void gicv3_redist_wait_for_rwp(void) > +{ > + gicv3_do_wait_for_rwp(GICD_RDIST_BASE); > +} > + > +static void gicv3_wait_for_rwp(int irq) > +{ > + if ( irq < NR_LOCAL_IRQS ) > + gicv3_redist_wait_for_rwp(); > + else > + gicv3_dist_wait_for_rwp(); > +} > + > +static unsigned int gicv3_get_cpu_from_mask(const cpumask_t *cpumask) > +{ > + unsigned int cpu; > + cpumask_t possible_mask; > + > + cpumask_and(&possible_mask, cpumask, &cpu_possible_map); > + cpu = cpumask_any(&possible_mask); > + > + return cpu; > +} > + > +static void restore_aprn_regs(const union gic_state_data *d) > +{ > + /* Write APRn register based on number of priorities > + platform has implemented */ > + switch ( gicv3.nr_priorities ) > + { > + case 7: > + WRITE_SYSREG32(d->v3.apr0[2], ICH_AP0R2_EL2); > + WRITE_SYSREG32(d->v3.apr1[2], ICH_AP1R2_EL2); > + /* Fall through */ > + case 6: > + WRITE_SYSREG32(d->v3.apr0[1], ICH_AP0R1_EL2); > + WRITE_SYSREG32(d->v3.apr1[1], ICH_AP1R1_EL2); > + /* Fall through */ > + case 5: > + WRITE_SYSREG32(d->v3.apr0[0], ICH_AP0R0_EL2); > + WRITE_SYSREG32(d->v3.apr1[0], ICH_AP1R0_EL2); > + break; > + default: > + BUG(); > + } > +} > + > +static void save_aprn_regs(union gic_state_data *d) > +{ > + /* Read APRn register based on number of priorities > + platform has implemented */ > + switch ( gicv3.nr_priorities ) > + { > + case 7: > + d->v3.apr0[2] = READ_SYSREG32(ICH_AP0R2_EL2); > + d->v3.apr1[2] = READ_SYSREG32(ICH_AP1R2_EL2); > + /* Fall through */ > + case 6: > + d->v3.apr0[1] = READ_SYSREG32(ICH_AP0R1_EL2); > + d->v3.apr1[1] = READ_SYSREG32(ICH_AP1R1_EL2); > + /* Fall through */ > + case 5: > + d->v3.apr0[0] = READ_SYSREG32(ICH_AP0R0_EL2); > + d->v3.apr1[0] = READ_SYSREG32(ICH_AP1R0_EL2); > + break; > + default: > + BUG(); > + } > +} > + > +static void gicv3_save_state(struct vcpu *v) > +{ > + > + /* No need for spinlocks here because interrupts are disabled around > + * this call and it only accesses struct vcpu fields that cannot be > + * accessed simultaneously by another pCPU. > + */ > + dsb(sy); > + gicv3_save_lr(gicv3_info.nr_lrs, v); > + save_aprn_regs(&v->arch.gic); > + v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2); > +} > + > +static void gicv3_restore_state(const struct vcpu *v) > +{ > + gicv3_restore_lr(gicv3_info.nr_lrs, v); > + restore_aprn_regs(&v->arch.gic); > + WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2); > +} Shouldn't we restore vmcr first? Before writing to the LRs? Should we save/restore SRE_EL1 too? Also looking at the Linux code, it seems that SRE_EL1 and VMCR_EL2 might have strange interactions, in fact Linux disables SRE_EL1 before writing to VMCR_EL2 (see restore_vgic_v3_state). > +static void gicv3_dump_state(const struct vcpu *v) > +{ > + int i; > + > + if ( v == current ) > + { > + for ( i = 0; i < gicv3_info.nr_lrs; i++ ) > + printk(" HW_LR[%d]=%lx\n", i, gicv3_ich_read_lr(i)); > + } > + else > + { > + for ( i = 0; i < gicv3_info.nr_lrs; i++ ) > + printk(" VCPU_LR[%d]=%lx\n", i, v->arch.gic.v3.lr[i]); > + } > +} > + > +static void gicv3_enable_irq(struct irq_desc *irqd) > +{ > + int irq = irqd->irq; > + > + /* Enable routing */ > + if ( irq < NR_GIC_LOCAL_IRQS ) > + writel_relaxed((1u << irq), GICD_RDIST_SGI_BASE + GICR_ISENABLER0); > + else > + writel_relaxed((1u << (irq % 32)), > + GICD + GICD_ISENABLER + (irq / 32) * 4); > + > + gicv3_wait_for_rwp(irq); > +} > + > +static void gicv3_disable_irq(struct irq_desc *irqd) > +{ > + /* Disable routing */ > + if ( irqd->irq < NR_GIC_LOCAL_IRQS ) > + writel_relaxed((1u << irqd->irq), > + GICD_RDIST_SGI_BASE + GICR_ICENABLER0); > + else > + writel_relaxed(1u << (irqd->irq % 32), > + GICD + GICD_ICENABLER + ((irqd->irq / 32) * 4)); > +} Strangely we have a wait in gicv3_enable_irq but not a wait in gicv3_disable_irq. Is that deliberate? > +static void gicv3_eoi_irq(struct irq_desc *irqd) > +{ > + /* Lower the priority */ > + WRITE_SYSREG32(irqd->irq, ICC_EOIR1_EL1); We need an isb here. > +} > + > +static void gicv3_dir_irq(int irq) > +{ > + /* Deactivate */ > + WRITE_SYSREG32(irq, ICC_DIR_EL1); > +} I am not sure if this needs an isb or not. > +static unsigned int gicv3_read_irq(void) > +{ > + return (READ_SYSREG32(ICC_IAR1_EL1) & GICC_IA_IRQ); > +} > + > +static inline uint64_t gicv3_mpidr_to_affinity(uint64_t mpidr) > +{ > + return (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 | > + MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 | > + MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | > + MPIDR_AFFINITY_LEVEL(mpidr, 0)); > +} > + > +static void gicv3_set_irq_properties(struct irq_desc *desc, > + const cpumask_t *cpu_mask, > + unsigned int priority) > +{ > + unsigned long flags; > + uint32_t cfg, edgebit; > + uint64_t affinity; > + void __iomem *base; > + unsigned int cpu = gicv3_get_cpu_from_mask(cpu_mask); > + unsigned int irq = desc->irq; > + unsigned int type = desc->arch.type; > + > + spin_lock_irqsave(&gicv3.lock, flags); > + > + /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */ > + if ( irq >= NR_GIC_SGI ) > + { > + if ( irq < NR_GIC_LOCAL_IRQS) > + base = GICD + GICD_ICFGR + (irq / 16) * 4; > + else > + base = GICD_RDIST_SGI_BASE + GICR_ICFGR1; > + > + cfg = readl_relaxed(base); > + > + edgebit = 2u << (2 * (irq % 16)); > + if ( type & DT_IRQ_TYPE_LEVEL_MASK ) > + cfg &= ~edgebit; > + else if ( type & DT_IRQ_TYPE_EDGE_BOTH ) > + cfg |= edgebit; > + > + writel_relaxed(cfg, base); > + } > + > + affinity = gicv3_mpidr_to_affinity(cpu_logical_map(cpu)); > + /* Make sure we don't broadcast the interrupt */ > + affinity &= ~GICD_IROUTER_SPI_MODE_ANY; > + > + if ( irq >= NR_GIC_LOCAL_IRQS ) > + writeq_relaxed(affinity, (GICD + GICD_IROUTER + irq * 8)); > + > + /* Set priority */ > + if ( irq < NR_GIC_LOCAL_IRQS ) > + writeb_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + > irq); > + else > + writeb_relaxed(priority, GICD + GICD_IPRIORITYR + irq); > + > + spin_unlock_irqrestore(&gicv3.lock, flags); > +} > + > +static void __init gicv3_dist_init(void) > +{ > + uint32_t type; > + uint32_t priority; > + uint64_t affinity; > + int i; > + > + /* Disable the distributor */ > + writel_relaxed(0, GICD + GICD_CTLR); > + > + type = readl_relaxed(GICD + GICD_TYPER); > + gicv3_info.nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1); > + > + printk("GICv3: %d lines, (IID %8.8x).\n", > + gicv3_info.nr_lines, readl_relaxed(GICD + GICD_IIDR)); > + > + /* Default all global IRQs to level, active low */ > + for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 16 ) > + writel_relaxed(0, GICD + GICD_ICFGR + (i / 16) * 4); > + > + /* Default priority for global interrupts */ > + for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 4 ) > + { > + priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 | > + GIC_PRI_IRQ << 8 | GIC_PRI_IRQ); > + writel_relaxed(priority, GICD + GICD_IPRIORITYR + (i / 4) * 4); > + } > + > + /* Disable all global interrupts */ > + for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i += 32 ) > + writel_relaxed(0xffffffff, GICD + GICD_ICENABLER + (i / 32) * 4); > + > + gicv3_dist_wait_for_rwp(); > + > + /* Turn on the distributor */ > + writel_relaxed(GICD_CTL_ENABLE | GICD_CTLR_ARE_NS | > + GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, GICD + > GICD_CTLR); > + > + /* Route all global IRQs to this CPU */ > + affinity = gicv3_mpidr_to_affinity(cpu_logical_map(smp_processor_id())); > + /* Make sure we don't broadcast the interrupt */ > + affinity &= ~GICD_IROUTER_SPI_MODE_ANY; > + > + for ( i = NR_GIC_LOCAL_IRQS; i < gicv3_info.nr_lines; i++ ) > + writeq_relaxed(affinity, GICD + GICD_IROUTER + i * 8); > +} > + > +static int gicv3_enable_redist(void) > +{ > + uint32_t val; > + bool_t timeout = 0; > + s_time_t deadline = NOW() + MILLISECS(1000); > + > + /* Wake up this CPU redistributor */ > + val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER); > + val &= ~GICR_WAKER_ProcessorSleep; > + writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER); > + > + do { > + val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER); > + if ( !(val & GICR_WAKER_ChildrenAsleep) ) > + break; > + if ( NOW() > deadline ) > + { > + timeout = 1; > + break; > + } > + cpu_relax(); > + udelay(1); > + } while ( timeout ); > + > + if ( timeout ) > + dprintk(XENLOG_ERR, "GICv3: Redist enable RWP timeout\n"); > + > + return 0; > +} > + > +static int __init gicv3_populate_rdist(void) > +{ > + int i; > + uint32_t aff; > + uint32_t reg; > + uint64_t typer; > + uint64_t mpidr = cpu_logical_map(smp_processor_id()); > + > + aff = gicv3_mpidr_to_affinity(mpidr); > + > + for ( i = 0; i < gicv3.rdist_count; i++ ) > + { > + void __iomem *ptr = gicv3.rdist_regions[i].map_base; > + > + reg = readl_relaxed(ptr + GICR_PIDR2) & GICR_PIDR2_ARCH_MASK; > + if ( reg != (GICV3_GICR_PIDR2 & GICR_PIDR2_ARCH_MASK) ) > + { > + dprintk(XENLOG_ERR, > + "GICv3: No redistributor present @%"PRIpaddr"\n", > + gicv3.rdist_regions[i].base); > + break; > + } > + > + do { > + typer = readq_relaxed(ptr + GICR_TYPER); > + > + if ( (typer >> 32) == aff ) > + { > + this_cpu(rbase) = ptr; > + printk("GICv3: CPU%d: Found redistributor in region %d > @%p\n", > + smp_processor_id(), i, ptr); > + return 0; > + } > + > + ptr += gicv3.rdist_stride; > + if ( typer & GICR_TYPER_VLPIS ) > + ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */ > + > + } while ( !(typer & GICR_TYPER_LAST) ); > + } > + > + dprintk(XENLOG_ERR, "GICv3: CPU%d: mpidr %lx has no re-distributor!\n", > + smp_processor_id(), mpidr); > + return -ENODEV; > +} > + > +static int __cpuinit gicv3_cpu_init(void) > +{ > + int i; > + uint32_t priority; > + > + /* Register ourselves with the rest of the world */ > + if ( gicv3_populate_rdist() ) > + return -ENODEV; > + > + if ( gicv3_enable_redist() ) > + return -ENODEV; > + > + /* Set priority on PPI and SGI interrupts */ > + priority = (GIC_PRI_IPI << 24 | GIC_PRI_IPI << 16 | GIC_PRI_IPI << 8 | > + GIC_PRI_IPI); > + for (i = 0; i < NR_GIC_SGI; i += 4) > + writel_relaxed(priority, > + GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4); > + > + priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 | GIC_PRI_IRQ << 8 | > + GIC_PRI_IRQ); > + for (i = NR_GIC_SGI; i < NR_GIC_LOCAL_IRQS; i += 4) > + writel_relaxed(priority, > + GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4); > + > + /* > + * Disable all PPI interrupts, ensure all SGI interrupts are > + * enabled. > + */ > + writel_relaxed(0xffff0000, GICD_RDIST_SGI_BASE + GICR_ICENABLER0); > + writel_relaxed(0x0000ffff, GICD_RDIST_SGI_BASE + GICR_ISENABLER0); > + > + gicv3_redist_wait_for_rwp(); > + > + /* Enable system registers */ > + gicv3_enable_sre(); > + > + /* No priority grouping */ > + WRITE_SYSREG32(0, ICC_BPR1_EL1); > + > + /* Set priority mask register */ > + WRITE_SYSREG32(DEFAULT_PMR_VALUE, ICC_PMR_EL1); > + > + /* EOI drops priority too (mode 0) */ > + WRITE_SYSREG32(GICC_CTLR_EL1_EOImode_drop, ICC_CTLR_EL1); > + > + /* Enable Group1 interrupts */ > + WRITE_SYSREG32(1, ICC_IGRPEN1_EL1); > + > + return 0; > +} > + > +static void gicv3_cpu_disable(void) > +{ > + WRITE_SYSREG32(0, ICC_CTLR_EL1); > +} > + > +static void __cpuinit gicv3_hyp_init(void) > +{ > + uint32_t vtr; > + > + vtr = READ_SYSREG32(ICH_VTR_EL2); > + gicv3_info.nr_lrs = (vtr & GICH_VTR_NRLRGS) + 1; > + gicv3.nr_priorities = ((vtr >> GICH_VTR_PRIBITS_SHIFT) & > + GICH_VTR_PRIBITS_MASK) + 1; > + > + ASSERT((gicv3.nr_priorities > 4 && gicv3.nr_priorities < 8)); > + > + WRITE_SYSREG32(GICH_VMCR_EOI | GICH_VMCR_VENG1, ICH_VMCR_EL2); > + WRITE_SYSREG32(GICH_HCR_EN, ICH_HCR_EL2); > + > + update_cpu_lr_mask(); > +} > + > +/* Set up the per-CPU parts of the GIC for a secondary CPU */ > +static int gicv3_secondary_cpu_init(void) > +{ > + int res; > + > + spin_lock(&gicv3.lock); > + > + res = gicv3_cpu_init(); > + gicv3_hyp_init(); > + > + spin_unlock(&gicv3.lock); > + > + return res; > +} > + > +static void __cpuinit gicv3_hyp_disable(void) > +{ > + uint32_t vtr; > + > + vtr = READ_SYSREG32(ICH_HCR_EL2); > + vtr &= ~0x1; > + WRITE_SYSREG32( vtr, ICH_HCR_EL2); > +} > + > +static u16 gicv3_compute_target_list(int *base_cpu, const struct cpumask > *mask, > + uint64_t cluster_id) > +{ > + int cpu = *base_cpu; > + uint64_t mpidr = cpu_logical_map(cpu); > + u16 tlist = 0; > + > + while ( cpu < nr_cpu_ids ) > + { > + /* > + * If we ever get a cluster of more than 16 CPUs, just > + * scream and skip that CPU. > + */ > + if ( (mpidr & 0xff) >= 16 ) > + { > + dprintk(XENLOG_WARNING, "GICv3:Cluster with more than 16's > cpus\n"); > + goto out; > + } > + tlist |= 1 << (mpidr & 0xf); > + > + cpu = cpumask_next(cpu, mask); > + if ( cpu == nr_cpu_ids ) > + { > + cpu--; > + goto out; > + } > + > + mpidr = cpu_logical_map(cpu); > + if ( cluster_id != (mpidr & ~0xffUL) ) { > + cpu--; > + goto out; > + } > + } > +out: > + *base_cpu = cpu; > + > + return tlist; > +} > + > +static void gicv3_send_sgi(const cpumask_t *cpumask, enum gic_sgi sgi, > + uint8_t mode) > +{ > + int cpu = 0; > + uint64_t val; > + > + dsb(sy); > + > + for_each_cpu(cpu, cpumask) > + { > + uint64_t cluster_id = cpu_logical_map(cpu) & ~0xffUL; > + u16 tlist; > + > + /* Get targetlist for the cluster to send SGI */ > + tlist = gicv3_compute_target_list(&cpu, cpumask, cluster_id); > + > + /* > + * Prepare affinity path of the cluster for which SGI is generated > + * along with SGI number > + */ > + val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48 | > + MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32 | > + sgi << 24 | > + MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16 | > + tlist); > + > + WRITE_SYSREG(val, ICC_SGI1R_EL1); > + } > +} > + > +/* Shut down the per-CPU GIC interface */ > +static void gicv3_disable_interface(void) > +{ > + spin_lock(&gicv3.lock); > + > + gicv3_cpu_disable(); > + gicv3_hyp_disable(); > + > + spin_unlock(&gicv3.lock); > +} > + > +static void gicv3_update_lr(int lr, const struct pending_irq *p, > + unsigned int state) > +{ > + uint64_t grp = GICH_LR_GRP1; > + uint64_t val = 0; Could you please add a TODO comment here to remind us that one day we might need to handle GRP0 as well? > + BUG_ON(lr >= gicv3_info.nr_lrs); > + BUG_ON(lr < 0); > + > + val = (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp; > + val |= ((uint64_t)p->priority & 0xff) << GICH_LR_PRIORITY_SHIFT; > + val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << > GICH_LR_VIRTUAL_SHIFT; > + > + if ( p->desc != NULL ) > + val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK) > + << GICH_LR_PHYSICAL_SHIFT); > + > + gicv3_ich_write_lr(lr, val); > +} > + > +static void gicv3_clear_lr(int lr) > +{ > + gicv3_ich_write_lr(lr, 0); > +} > + > +static void gicv3_read_lr(int lr, struct gic_lr *lr_reg) > +{ > + uint64_t lrv; > + > + lrv = gicv3_ich_read_lr(lr); > + > + lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK; > + lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK; > + > + lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & > GICH_LR_PRIORITY_MASK; > + lr_reg->state = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK; > + lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK; > + lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK; > +} > + > +static void gicv3_write_lr(int lr_reg, const struct gic_lr *lr) > +{ > + uint64_t lrv = 0; > + > + lrv = ( ((u64)(lr->pirq & GICH_LR_PHYSICAL_MASK) << > GICH_LR_PHYSICAL_SHIFT)| > + ((u64)(lr->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT) | > + ((u64)(lr->priority & GICH_LR_PRIORITY_MASK) << > GICH_LR_PRIORITY_SHIFT)| > + ((u64)(lr->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) | > + ((u64)(lr->hw_status & GICH_LR_HW_MASK) << GICH_LR_HW_SHIFT) | > + ((u64)(lr->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) ); > + > + gicv3_ich_write_lr(lr_reg, lrv); > +} > + > +static int gicv_v3_init(struct domain *d) > +{ > + int i; > + > + /* > + * Domain 0 gets the hardware address. > + * Guests get the virtual platform layout. > + */ > + if ( d->domain_id == 0 ) > + { > + d->arch.vgic.dbase = gicv3.dbase; > + d->arch.vgic.dbase_size = gicv3.dbase_size; > + for ( i = 0; i < gicv3.rdist_count; i++ ) > + { > + d->arch.vgic.rbase[i] = gicv3.rdist_regions[i].base; > + d->arch.vgic.rbase_size[i] = gicv3.rdist_regions[i].size; > + } > + d->arch.vgic.rdist_stride = gicv3.rdist_stride; > + d->arch.vgic.rdist_count = gicv3.rdist_count; > + } > + else > + d->arch.vgic.dbase = GUEST_GICD_BASE; > + > + d->arch.vgic.nr_lines = 0; > + > + return 0; > +} > + > +static void gicv3_hcr_status(uint32_t flag, bool_t status) > +{ > + uint32_t hcr; > + > + hcr = READ_SYSREG32(ICH_HCR_EL2); > + if ( status ) > + WRITE_SYSREG32(hcr | flag, ICH_HCR_EL2); > + else > + WRITE_SYSREG32(hcr & (~flag), ICH_HCR_EL2); > +} > + > +static unsigned int gicv3_read_vmcr_priority(void) > +{ > + return ((READ_SYSREG32(ICH_VMCR_EL2) >> GICH_VMCR_PRIORITY_SHIFT) & > + GICH_VMCR_PRIORITY_MASK); > +} > + > +static void gicv3_irq_enable(struct irq_desc *desc) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&gicv3.lock, flags); > + desc->status &= ~IRQ_DISABLED; > + dsb(sy); > + /* Enable routing */ > + gicv3_enable_irq(desc); > + spin_unlock_irqrestore(&gicv3.lock, flags); > +} > + > +static void gicv3_irq_disable(struct irq_desc *desc) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&gicv3.lock, flags); > + /* Disable routing */ > + gicv3_disable_irq(desc); > + desc->status |= IRQ_DISABLED; > + spin_unlock_irqrestore(&gicv3.lock, flags); > +} > + > +static unsigned int gicv3_irq_startup(struct irq_desc *desc) > +{ > + gicv3_irq_enable(desc); > + > + return 0; > +} > + > +static void gicv3_irq_shutdown(struct irq_desc *desc) > +{ > + gicv3_irq_disable(desc); > +} > + > +static void gicv3_irq_ack(struct irq_desc *desc) > +{ > + /* No ACK -- reading IAR has done this for us */ > +} > + > +static void gicv3_host_irq_end(struct irq_desc *desc) > +{ > + /* Lower the priority */ > + gicv3_eoi_irq(desc); > + /* Deactivate */ > + gicv3_dir_irq(desc->irq); > +} > + > +static void gicv3_guest_irq_end(struct irq_desc *desc) > +{ > + /* Lower the priority of the IRQ */ > + gicv3_eoi_irq(desc); > + /* Deactivation happens in maintenance interrupt / via GICV */ > +} > + > +static void gicv3_irq_set_affinity(struct irq_desc *desc, const cpumask_t > *mask) > +{ > + BUG(); > +} > + > +const static hw_irq_controller gicv3_host_irq_type = { > + .typename = "gic-v3", > + .startup = gicv3_irq_startup, > + .shutdown = gicv3_irq_shutdown, > + .enable = gicv3_irq_enable, > + .disable = gicv3_irq_disable, > + .ack = gicv3_irq_ack, > + .end = gicv3_host_irq_end, > + .set_affinity = gicv3_irq_set_affinity, > +}; > + > +const static hw_irq_controller gicv3_guest_irq_type = { > + .typename = "gic-v3", > + .startup = gicv3_irq_startup, > + .shutdown = gicv3_irq_shutdown, > + .enable = gicv3_irq_enable, > + .disable = gicv3_irq_disable, > + .ack = gicv3_irq_ack, > + .end = gicv3_guest_irq_end, > + .set_affinity = gicv3_irq_set_affinity, > +}; > + > +const static struct gic_hw_operations gicv3_ops = { > + .info = &gicv3_info, > + .save_state = gicv3_save_state, > + .restore_state = gicv3_restore_state, > + .dump_state = gicv3_dump_state, > + .gicv_setup = gicv_v3_init, > + .gic_host_irq_type = &gicv3_host_irq_type, > + .gic_guest_irq_type = &gicv3_guest_irq_type, > + .eoi_irq = gicv3_eoi_irq, > + .deactivate_irq = gicv3_dir_irq, > + .read_irq = gicv3_read_irq, > + .set_irq_properties = gicv3_set_irq_properties, > + .send_SGI = gicv3_send_sgi, > + .disable_interface = gicv3_disable_interface, > + .update_lr = gicv3_update_lr, > + .update_hcr_status = gicv3_hcr_status, > + .clear_lr = gicv3_clear_lr, > + .read_lr = gicv3_read_lr, > + .write_lr = gicv3_write_lr, > + .read_vmcr_priority = gicv3_read_vmcr_priority, > + .secondary_init = gicv3_secondary_cpu_init, > +}; > + > +/* Set up the GIC */ > +static int __init gicv3_init(struct dt_device_node *node, const void *data) > +{ > + struct rdist_region *rdist_regs; > + int res, i; > + uint32_t reg; > + > + dt_device_set_used_by(node, DOMID_XEN); > + > + res = dt_device_get_address(node, 0, &gicv3.dbase, &gicv3.dbase_size); > + if ( res || !gicv3.dbase ) > + panic("GICv3: Cannot find a valid distributor address"); > + > + if ( (gicv3.dbase & ~PAGE_MASK) || (gicv3.dbase_size & ~PAGE_MASK) ) > + panic("GICv3: Found unaligned distributor address %"PRIpaddr"", > + gicv3.dbase); > + > + gicv3.map_dbase = ioremap_nocache(gicv3.dbase, gicv3.dbase_size); > + if ( !gicv3.map_dbase ) > + panic("GICv3: Failed to ioremap for GIC distributor\n"); > + > + reg = readl_relaxed(GICD + GICD_PIDR2) & GICD_PIDR2_ARCH_MASK; > + if ( reg != (GICV3_GICD_PIDR2 & GICD_PIDR2_ARCH_MASK) ) > + panic("GICv3: no distributor detected\n"); > + > + if ( !dt_property_read_u32(node, "#redistributor-regions", > + &gicv3.rdist_count) ) > + gicv3.rdist_count = 1; > + > + if ( gicv3.rdist_count > MAX_RDIST_COUNT ) > + panic("GICv3: Number of redistributor regions is more than \ > + %d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); > + > + rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); > + if ( !rdist_regs ) > + panic("GICv3: Failed to allocate memory for rdist regions\n"); > + > + for ( i = 0; i < gicv3.rdist_count; i++ ) > + { > + uint64_t rdist_base, rdist_size; > + > + res = dt_device_get_address(node, 1 + i, &rdist_base, &rdist_size); > + if ( res || !rdist_base ) > + panic("GICv3: No rdist base found for region %d\n", i); > + > + rdist_regs[i].base = rdist_base; > + rdist_regs[i].size = rdist_size; > + } > + > + /* If stride is not set in dt. Set default to 2 * SZ_64K */ > + if ( !dt_property_read_u32(node, "redistributor-stride", > &gicv3.rdist_stride) ) > + gicv3.rdist_stride = 2 * SZ_64K; > + > + gicv3.rdist_regions= rdist_regs; > + > + res = platform_get_irq(node, 0); > + if ( res < 0 ) > + panic("GICv3: Cannot find the maintenance IRQ"); > + gicv3_info.maintenance_irq = res; > + > + /* Set the GIC as the primary interrupt controller */ > + dt_interrupt_controller = node; > + > + for ( i = 0; i < gicv3.rdist_count; i++ ) > + { > + /* map dbase & rdist regions */ > + gicv3.rdist_regions[i].map_base = > + ioremap_nocache(gicv3.rdist_regions[i].base, > + gicv3.rdist_regions[i].size); > + > + if ( !gicv3.rdist_regions[i].map_base ) > + panic("GICv3: Failed to ioremap rdist region for region %d\n", > i); > + } > + > + printk("GICv3 initialization:\n" > + " gic_dist_addr=%"PRIpaddr"\n" > + " gic_dist_size=%"PRIpaddr"\n" > + " gic_dist_mapaddr=%p\n" > + " gic_rdist_regions=%d\n" > + " gic_rdist_stride=%x\n" > + " gic_rdist_base=%"PRIpaddr"\n" > + " gic_rdist_base_size=%"PRIpaddr"\n" > + " gic_rdist_base_mapaddr=%p\n" > + " gic_maintenance_irq=%u\n", > + gicv3.dbase, gicv3.dbase_size, gicv3.map_dbase, gicv3.rdist_count, > + gicv3.rdist_stride, gicv3.rdist_regions[0].base, > + gicv3.rdist_regions[0].size, gicv3.rdist_regions[0].map_base, > + gicv3_info.maintenance_irq); > + > + spin_lock_init(&gicv3.lock); > + > + spin_lock(&gicv3.lock); > + > + gicv3_dist_init(); > + res = gicv3_cpu_init(); > + gicv3_hyp_init(); > + > + gicv3_info.hw_version = GIC_V3; > + /* Register hw ops*/ > + register_gic_ops(&gicv3_ops); > + > + spin_unlock(&gicv3.lock); > + > + return res; > +} > + > +static const char * const gicv3_dt_compat[] __initconst = > +{ > + DT_MATCH_GIC_V3_STRING1, > + NULL > +}; > + > +DT_DEVICE_START(gicv3, "GICv3", DEVICE_GIC) > + .compatible = gicv3_dt_compat, > + .init = gicv3_init, > +DT_DEVICE_END > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h > index 8a00aa1..66e246e 100644 > --- a/xen/include/asm-arm/domain.h > +++ b/xen/include/asm-arm/domain.h > @@ -154,6 +154,14 @@ struct arch_domain > /* Base address for guest GIC */ > paddr_t dbase; /* Distributor base address */ > paddr_t cbase; /* CPU base address */ > +#ifdef CONFIG_ARM_64 > + /* GIC V3 addressing */ > + paddr_t dbase_size; /* Distributor base size */ > + paddr_t rbase[MAX_RDIST_COUNT]; /* Re-Distributor base address > */ > + paddr_t rbase_size[MAX_RDIST_COUNT]; /* Re-Distributor size */ > + uint32_t rdist_stride; /* Re-Distributor stride */ > + int rdist_count; /* No. of Re-Distributors */ > +#endif > } vgic; > > struct vuart { > diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h > index 2aadcb6..b40beb5 100644 > --- a/xen/include/asm-arm/gic.h > +++ b/xen/include/asm-arm/gic.h > @@ -18,6 +18,10 @@ > #ifndef __ASM_ARM_GIC_H__ > #define __ASM_ARM_GIC_H__ > > +#define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS > +#define NR_GIC_SGI 16 > +#define MAX_RDIST_COUNT 4 > + > #define GICD_CTLR (0x000) > #define GICD_TYPER (0x004) > #define GICD_IIDR (0x008) > @@ -150,6 +154,20 @@ > #define DT_MATCH_GIC_V2 DT_MATCH_COMPATIBLE(DT_MATCH_GIC_V2_STRING_1), \ > DT_MATCH_COMPATIBLE(DT_MATCH_GIC_V2_STRING_2) > > +#define DT_MATCH_GIC_V3_STRING1 "arm,gic-v3" > + > +#define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE(DT_MATCH_GIC_V3_STRING1); > + > +/* > + * GICv3 registers that needs to be saved/restored > + */ > +struct gic_v3 { > + uint32_t hcr, vmcr; > + uint32_t apr0[4]; > + uint32_t apr1[4]; > + uint64_t lr[16]; > +}; > + > /* > * GICv2 register that needs to be saved/restored > * on VCPU context switch > @@ -166,6 +184,7 @@ struct gic_v2 { > */ > union gic_state_data { > struct gic_v2 v2; > + struct gic_v3 v3; > }; > > /* > @@ -251,6 +270,7 @@ void gic_clear_lrs(struct vcpu *v); > > enum gic_version { > GIC_V2 = 2, > + GIC_V3 = 3, > }; > > struct gic_info { > diff --git a/xen/include/asm-arm/gic_v3_defs.h > b/xen/include/asm-arm/gic_v3_defs.h > new file mode 100644 > index 0000000..6f393aa > --- /dev/null > +++ b/xen/include/asm-arm/gic_v3_defs.h > @@ -0,0 +1,157 @@ > +/* > + * ARM Generic Interrupt Controller v3 definitions > + * > + * Vijaya Kumar K <vijaya.kumar@xxxxxxxxxxxxxxxxxx> > + * Copyright (c) 2014 Cavium Inc. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#ifndef __ASM_ARM_GIC_V3_DEFS_H__ > +#define __ASM_ARM_GIC_V3_DEFS_H__ > + > +/* > + * Additional registers defined in GIC v3. > + * Common GICD registers are defined in gic.h > + */ > + > +#define GICD_STATUSR (0x010) > +#define GICD_SETSPI_NSR (0x040) > +#define GICD_CLRSPI_NSR (0x048) > +#define GICD_SETSPI_SR (0x050) > +#define GICD_CLRSPI_SR (0x058) > +#define GICD_IROUTER (0x6000) > +#define GICD_IROUTER31 (0x60F8) > +#define GICD_IROUTER32 (0x6100) > +#define GICD_IROUTERN (0x7FF8) > +#define GICD_PIDR0 (0xFFE0) > +#define GICD_PIDR1 (0xFFE4) > +#define GICD_PIDR2 (0xFFE8) > +#define GICD_PIDR3 (0xFFEC) > +#define GICD_PIDR4 (0xFFD0) > +#define GICD_PIDR5 (0xFFD4) > +#define GICD_PIDR7 (0xFFDC) > + > +#define GICC_SRE_EL2_SRE (1UL << 0) > +#define GICC_SRE_EL2_DFB (1UL << 1) > +#define GICC_SRE_EL2_DIB (1UL << 2) > +#define GICC_SRE_EL2_ENEL1 (1UL << 3) > + > +#define GICD_CTLR_RWP (1UL << 31) > +#define GICD_CTLR_ARE_NS (1U << 4) > +#define GICD_CTLR_ENABLE_G1A (1U << 1) > +#define GICD_CTLR_ENABLE_G1 (1U << 0) > +#define GICD_IROUTER_SPI_MODE_ANY (1UL << 31) > + > +#define GICC_CTLR_EL1_EOImode_drop (1U << 1) > + > +#define GICR_WAKER_ProcessorSleep (1U << 1) > +#define GICR_WAKER_ChildrenAsleep (1U << 2) > + > +#define GICV3_GICD_PIDR0 (0x92) > +#define GICV3_GICD_PIDR1 (0xb4) > +#define GICV3_GICD_PIDR2 (0x3b) > +#define GICV3_GICD_PIDR4 (0x04) > +#define GICD_PIDR2_ARCH_MASK (0xf0) > + > +#define GICV3_GICR_PIDR0 (0x93) > +#define GICV3_GICR_PIDR1 GICV3_GICD_PIDR1 > +#define GICV3_GICR_PIDR2 GICV3_GICD_PIDR2 > +#define GICV3_GICR_PIDR4 GICV3_GICD_PIDR4 > +#define GICR_PIDR2_ARCH_MASK GICD_PIDR2_ARCH_MASK > +#define GICR_SYNCR_NOT_BUSY 1 > +/* > + * Implementation defined value JEP106? > + * use physical hw value for now > + */ > +#define GICV3_GICD_IIDR_VAL 0x34c > +#define GICV3_GICR_IIDR_VAL GICV3_GICD_IIDR_VAL > + > +#define GICR_CTLR (0x0000) > +#define GICR_IIDR (0x0004) > +#define GICR_TYPER (0x0008) > +#define GICR_STATUSR (0x0010) > +#define GICR_WAKER (0x0014) > +#define GICR_SETLPIR (0x0040) > +#define GICR_CLRLPIR (0x0048) > +#define GICR_PROPBASER (0x0070) > +#define GICR_PENDBASER (0x0078) > +#define GICR_INVLPIR (0x00A0) > +#define GICR_INVALLR (0x00B0) > +#define GICR_SYNCR (0x00C0) > +#define GICR_MOVLPIR (0x100) > +#define GICR_MOVALLR (0x0110) > +#define GICR_PIDR0 GICD_PIDR0 > +#define GICR_PIDR1 GICD_PIDR1 > +#define GICR_PIDR2 GICD_PIDR2 > +#define GICR_PIDR3 GICD_PIDR3 > +#define GICR_PIDR4 GICD_PIDR4 > +#define GICR_PIDR5 GICD_PIDR5 > +#define GICR_PIDR7 GICD_PIDR7 > + > +/* GICR for SGI's & PPI's */ > + > +#define GICR_IGROUPR0 (0x0080) > +#define GICR_IGRPMODR0 (0x0F80) > +#define GICR_ISENABLER0 (0x0100) > +#define GICR_ICENABLER0 (0x0180) > +#define GICR_ISPENDR0 (0x0200) > +#define GICR_ICPENDR0 (0x0280) > +#define GICR_ISACTIVER0 (0x0300) > +#define GICR_ICACTIVER0 (0x0380) > +#define GICR_IPRIORITYR0 (0x0400) > +#define GICR_IPRIORITYR7 (0x041C) > +#define GICR_ICFGR0 (0x0C00) > +#define GICR_ICFGR1 (0x0C04) > +#define GICR_NSACR (0x0E00) > + > +#define GICR_TYPER_PLPIS (1U << 0) > +#define GICR_TYPER_VLPIS (1U << 1) > +#define GICR_TYPER_LAST (1U << 4) > + > +#define DEFAULT_PMR_VALUE 0xff > + > +#define GICH_VMCR_EOI (1 << 9) > +#define GICH_VMCR_VENG1 (1 << 1) > + > +#define GICH_LR_VIRTUAL_MASK 0xffff > +#define GICH_LR_VIRTUAL_SHIFT 0 > +#define GICH_LR_PHYSICAL_MASK 0x3ff > +#define GICH_LR_PHYSICAL_SHIFT 32 > +#define GICH_LR_STATE_MASK 0x3 > +#define GICH_LR_STATE_SHIFT 62 > +#define GICH_LR_PRIORITY_MASK 0xff > +#define GICH_LR_PRIORITY_SHIFT 48 > +#define GICH_LR_HW_MASK 0x1 > +#define GICH_LR_HW_SHIFT 61 > +#define GICH_LR_GRP_MASK 0x1 > +#define GICH_LR_GRP_SHIFT 60 > +#define GICH_LR_MAINTENANCE_IRQ (1UL<<41) > +#define GICH_LR_GRP1 (1UL<<60) > +#define GICH_LR_HW (1UL<<61) > + > +#define GICH_VTR_NRLRGS 0x3f > +#define GICH_VTR_PRIBITS_MASK 0x7 > +#define GICH_VTR_PRIBITS_SHIFT 29 > + > +#define GICH_VMCR_PRIORITY_MASK 0xff > +#define GICH_VMCR_PRIORITY_SHIFT 24 > + > +#endif /* __ASM_ARM_GIC_V3_DEFS_H__ */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h > index 3662749..5978b8a 100644 > --- a/xen/include/asm-arm/processor.h > +++ b/xen/include/asm-arm/processor.h > @@ -17,6 +17,20 @@ > #define MPIDR_HWID_MASK _AC(0xffffff,U) > #define MPIDR_INVALID (~MPIDR_HWID_MASK) > > +/* > + * Macros to extract affinity level. picked from kernel > + */ > + > +#define MPIDR_LEVEL_BITS_SHIFT 3 > +#define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT) > +#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) > + > +#define MPIDR_LEVEL_SHIFT(level) \ > + (((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT) > + > +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ > + ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK) > + > /* TTBCR Translation Table Base Control Register */ > #define TTBCR_EAE _AC(0x80000000,U) > #define TTBCR_N_MASK _AC(0x07,U) > diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h > index 1369b2b..499a798 100644 > --- a/xen/include/xen/lib.h > +++ b/xen/include/xen/lib.h > @@ -67,6 +67,8 @@ do { > \ > > #define reserve_bootmem(_p,_l) ((void)0) > > +#define SZ_64K 0x00010000 > + > struct domain; > > void cmdline_parse(const char *cmdline); > -- > 1.7.9.5 > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |