[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH RFC 19/35] ACPI / GICv2: Add GIC specific ACPI boot support
On 4 February 2015 at 14:02, <parth.dixit@xxxxxxxxxx> wrote: > From: Naresh Bhat <naresh.bhat@xxxxxxxxxx> > > ACPI on Xen hypervisor uses MADT table for proper GIC initialization. > It needs to parse GIC related subtables, collect CPU interface and distributor > addresses and call driver initialization function (which is hardware > abstraction agnostic). In a similar way, FDT initialize GICv1/2. > > NOTE: This commit allow to initialize GICv1/2 only. > > Signed-off-by: Tomasz Nowicki <tomasz.nowicki@xxxxxxxxxx> > Signed-off-by: Graeme Gregory <graeme.gregory@xxxxxxxxxx> I do not recognise any of the code here and I'm pretty sure I have not worked on any of it. I am unsure what the rules on Signed-off-by: is but I think this one is wrong. Graeme > Signed-off-by: Hanjun Guo <hanjun.guo@xxxxxxxxxx> > Signed-off-by: Naresh Bhat <naresh.bhat@xxxxxxxxxx> > Signed-off-by: Parth Dixit <parth.dixit@xxxxxxxxxx> > > Conflicts: > > xen/arch/arm/irq.c > --- > xen/arch/arm/gic-v2.c | 271 > +++++++++++++++++++++++++++++++++++++++++++++ > xen/arch/arm/setup.c | 3 +- > xen/include/asm-arm/acpi.h | 2 + > 3 files changed, 275 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c > index faad1ff..cb1d205 100644 > --- a/xen/arch/arm/gic-v2.c > +++ b/xen/arch/arm/gic-v2.c > @@ -777,6 +777,277 @@ DT_DEVICE_START(gicv2, "GICv2:", DEVICE_GIC) > .init = gicv2_init, > DT_DEVICE_END > > +#if defined(CONFIG_ARM_64) && defined(CONFIG_ACPI) > + > +#include <xen/acpi.h> > +#include <xen/errno.h> > +#include <xen/vmap.h> > +#include <asm/acpi.h> > + > +/* > + * Hard code here, we can not get memory size from MADT (but FDT does), > + * this size can be inferred from GICv2 spec > + */ > + > +#define ACPI_GIC_DIST_MEM_SIZE 0x00010000 // (SZ_64K) > +#define ACPI_GIC_CPU_IF_MEM_SIZE 0x00002000 // (SZ_8K) > + > +static DEFINE_PER_CPU(u64, gic_percpu_cpu_base); > +static cpumask_t gic_acpi_cpu_mask; > +static u64 dist_phy_base; > + > +static int __init > +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, > + const unsigned long end) > +{ > + struct acpi_madt_generic_interrupt *processor; > + unsigned int cpu; > + > + processor = (struct acpi_madt_generic_interrupt *)header; > + > + if (BAD_MADT_ENTRY(processor, end)) > + return -EINVAL; > + for_each_possible_cpu(cpu) { > + /* > + * FIXME: This condition is failing. > + * In Xen we first want to bring/initialize the GIC in hypervisor > with single CPU > + * if (processor->mpidr == cpu_logical_map(cpu)) > + */ > + goto find; > + } > + > + printk("\nUnable to find CPU corresponding to GIC CPU entry [mpdir > %lx]\n", > + (long)processor->mpidr); > + > + return 0; > + > +find: > + /* Read from APIC table and fill up the GIC variables */ > + gicv2.dbase = processor->redist_base_address; > + gicv2.cbase = processor->base_address; > + gicv2.hbase = processor->gich_base_address; > + gicv2.vbase = processor->gicv_base_address; > + gicv2_info.maintenance_irq = processor->vgic_maintenance_interrupt; > + if( processor->flags & ACPI_MADT_ENABLED ) > + { > + if( processor->flags & ACPI_MADT_VGIC ) > + acpi_set_irq(gicv2_info.maintenance_irq, > DT_IRQ_TYPE_EDGE_BOTH); > + else > + acpi_set_irq(gicv2_info.maintenance_irq, > DT_IRQ_TYPE_LEVEL_MASK); > + } > + > + /* > + * Do not validate CPU i/f base, we can still use "Local Interrupt > + * Controller Address" from MADT header instead. > + */ > + per_cpu(gic_percpu_cpu_base, cpu) = processor->base_address; > + cpumask_set_cpu(cpu, &gic_acpi_cpu_mask); > + > + return 0; > +} > + > +static int __init > +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, > + const unsigned long end) > +{ > + struct acpi_madt_generic_distributor *dist; > + > + dist = (struct acpi_madt_generic_distributor *)header; > + > + if (BAD_MADT_ENTRY(dist, end)) > + return -EINVAL; > + > + dist_phy_base = dist->base_address; > + > + return 0; > +} > + > +static int gic_acpi_validate_init(u64 madt_cpu_addr) > +{ > + void __iomem *cpu_base, *dist_base; > + u64 gic_cpu_base = 0; > + unsigned int cpu; > + > + /* Process all GICC entries delivered by MADT */ > + if (!cpumask_empty(&gic_acpi_cpu_mask)) { > + /* > + * If MADT contains at least one GICC entry, it must be BSP > + * dedicated. > + */ > + if (!cpumask_test_cpu(0, &gic_acpi_cpu_mask)) { > + printk("GICC entries exist but unable to find BSP > GICC " > + "address\n"); > + goto madt_cpu_base; > + } > + > + /* > + * There is no support for non-banked GICv1/2 register in > ACPI > + * spec. All CPU interface addresses have to be the same. > + */ > + gic_cpu_base = per_cpu(gic_percpu_cpu_base, 0); > + for_each_cpu (cpu, &gic_acpi_cpu_mask) { > + if (gic_cpu_base != per_cpu(gic_percpu_cpu_base, > cpu)) { > + printk("GICC addresses are different, no > support" > + "for non-banked GICC registers > !!!\n"); > + gic_cpu_base = 0; > + goto madt_cpu_base; > + } > + } > + } > + > +madt_cpu_base: > + /* If no GICC address provided, use address from MADT header */ > + if (!gic_cpu_base) { > + if (!madt_cpu_addr) { > + printk("Unable to find GICC address\n"); > + return -EINVAL; > + } > + > + printk("Attempt to use Local Interrupt Controller Address" > + "as GICC base address\n"); > + gic_cpu_base = madt_cpu_addr; > + } > + > + cpu_base = ioremap(gic_cpu_base, ACPI_GIC_CPU_IF_MEM_SIZE); > + if (!cpu_base) { > + printk("Unable to map GICC registers\n"); > + return -ENOMEM; > + } > + > + dist_base = ioremap(dist_phy_base, ACPI_GIC_DIST_MEM_SIZE); > + if (!dist_base) { > + printk("Unable to map GICD registers\n"); > + iounmap(cpu_base); > + return -ENOMEM; > + } > + > + /* > + * FIXME: Initialize zero GIC instance (no multi-GIC support) based > on > + * addresses obtained from MADT. Also, set GIC as default IRQ domain > + * to allow for GSI registration and GSI to IRQ number translation > + * (see acpi_register_gsi() and acpi_gsi_to_irq()). > + * > + * gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); > + * irq_set_default_host(gic_data[0].domain); > + */ > + > + /* TODO: Add check on distributor, cpu size */ > + > + printk("GICv2 initialization from ACPI MADT table :\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", > + gicv2.dbase, gicv2.cbase, gicv2.hbase, gicv2.vbase, > + gicv2_info.maintenance_irq); > + > + if ( (gicv2.dbase & ~PAGE_MASK) || (gicv2.cbase & ~PAGE_MASK) || > + (gicv2.hbase & ~PAGE_MASK) || (gicv2.vbase & ~PAGE_MASK) ) > + panic("GICv2 interfaces not page aligned"); > + > + gicv2.map_dbase = ioremap_nocache(gicv2.dbase, PAGE_SIZE); > + if ( !gicv2.map_dbase ) > + panic("GICv2: Failed to ioremap for GIC distributor\n"); > + > + gicv2.map_cbase[0] = ioremap_nocache(gicv2.cbase, PAGE_SIZE); > + > + if ( platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) ) > + gicv2.map_cbase[1] = ioremap_nocache(gicv2.cbase + PAGE_SIZE * 0x10, > + PAGE_SIZE); > + else > + gicv2.map_cbase[1] = ioremap_nocache(gicv2.cbase + PAGE_SIZE, > PAGE_SIZE); > + > + if ( !gicv2.map_cbase[0] || !gicv2.map_cbase[1] ) > + panic("GICv2: Failed to ioremap for GIC CPU interface\n"); > + > + gicv2.map_hbase = ioremap_nocache(gicv2.hbase, PAGE_SIZE); > + if ( !gicv2.map_hbase ) > + panic("GICv2: Failed to ioremap for GIC Virtual interface\n"); > + > + /* Global settings: interrupt distributor */ > + spin_lock_init(&gicv2.lock); > + spin_lock(&gicv2.lock); > + > + gicv2_dist_init(); > + gicv2_cpu_init(); > + gicv2_hyp_init(); > + > + spin_unlock(&gicv2.lock); > + > + gicv2_info.hw_version = GIC_V2; > + register_gic_ops(&gicv2_ops); > + > + return 0; > +} > + > +int __init > +gic_v2_acpi_init(struct acpi_table_header *table) > +{ > + struct acpi_table_madt *madt; > + int count; > + > + /* Collect CPU base addresses */ > + count = acpi_parse_entries(sizeof(struct acpi_table_madt), > + gic_acpi_parse_madt_cpu, table, > + ACPI_MADT_TYPE_GENERIC_INTERRUPT, > + MAX_GIC_CPU_INTERFACE); > + if (count <= 0) { > + printk("Error during GICC entries parsing\n"); > + return -EINVAL; > + } > + > + /* > + * Find distributor base address. We expect one distributor entry > since > + * ACPI 5.0 spec neither support multi-GIC instances nor GIC cascade. > + */ > + count = acpi_parse_entries(sizeof(struct acpi_table_madt), > + gic_acpi_parse_madt_distributor, table, > + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, > + MAX_GIC_DISTRIBUTOR); > + if (count <= 0) { > + printk("Error during GICD entries parsing\n"); > + return -EINVAL; > + } > + > + madt = (struct acpi_table_madt *)table; > + return gic_acpi_validate_init((u64)madt->address); > +} > + > +static int __init acpi_parse_madt(struct acpi_table_header *table) > +{ > + struct acpi_table_madt *madt = NULL; > + madt = (struct acpi_table_madt *)table; > + > + if (!madt) > + return 1; > + else > + printk("Local APIC address 0x%08x\n", madt->address); > + > + return 0; > +} > + > +int __init acpi_gic_init() > +{ > + acpi_status status; > + int err; > + > + status = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt); > + > + if (ACPI_FAILURE(status)) { > + const char *msg = acpi_format_exception(status); > + printk("\nFailed to get MADT table, %s\n", msg); > + return 1; > + } > + > + err = acpi_table_parse(ACPI_SIG_MADT, gic_v2_acpi_init); > + if (err) > + printk("\nFailed to initialize GIC IRQ controller\n"); > + > + return 0; > +} > +#endif > + > /* > * Local variables: > * mode: C > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index 317b985..93c8a8a 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -784,11 +784,12 @@ void __init start_xen(unsigned long boot_phys_offset, > /* Comment for now take it after GIC initialization */ > #if defined(CONFIG_ACPI) && defined(CONFIG_ARM_64) > init_xen_acpi_time(); > + acpi_gic_init(); > #else > init_xen_time(); > + gic_init(); > #endif > > - gic_init(); > > p2m_vmid_allocator_init(); > > diff --git a/xen/include/asm-arm/acpi.h b/xen/include/asm-arm/acpi.h > index c2d25db..01ce28d 100644 > --- a/xen/include/asm-arm/acpi.h > +++ b/xen/include/asm-arm/acpi.h > @@ -106,5 +106,7 @@ static inline void acpi_disable_pci(void) > #endif > > #define MAX_GIC_CPU_INTERFACE 65535 > +#define MAX_GIC_DISTRIBUTOR 1 /* should be the same as > MAX_GIC_NR */ > +extern int __init acpi_gic_init(void); > > #endif /*_ASM_ARM_ACPI_H*/ > -- > 1.9.1 > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |