From patchwork Wed Feb 4 14:02:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parth Dixit X-Patchwork-Id: 44352 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f197.google.com (mail-lb0-f197.google.com [209.85.217.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 1BCF82029F for ; Wed, 4 Feb 2015 14:06:19 +0000 (UTC) Received: by mail-lb0-f197.google.com with SMTP id b6sf1502016lbj.0 for ; Wed, 04 Feb 2015 06:06:18 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:cc:subject:precedence:list-id:list-unsubscribe:list-post :list-help:list-subscribe:mime-version:content-type :content-transfer-encoding:sender:errors-to:x-original-sender :x-original-authentication-results:mailing-list:list-archive; bh=9UE+vF+SxPLtHdpzUAYigzFoJTmEPBuGInK3ldlWfP8=; b=gBbWrKBOtek8JoA066RUPpS4esbPCdxByPpvqtSmvva6347K/FLFHy4BHHQ9TeEeJf 23tamIdM0e7Mu24sr/kzcRLY/d4Bms7D1aTJJpS0hklqJOlT0PFwh9s71XokUtPai91F P4I4MrxWEAqHX/VEC3RnqTn/UumyLL4zIjEPtCE+o9phFJ+qGQrgmQ5V9hqnD/+K2KYu QC4V00j8xGN8lr7keQVwesySTDVUEeaklaj27EH5ObdMxtTMRngvvzuAB1CvTIqy2UHG xhVIe1N7VYIZBVgjepEvOVvcAGditXLQ2UYFlYrJcxtseL2hQYf1sG9Wt8HQwWCfqMRW O2Pg== X-Gm-Message-State: ALoCoQlhWzneu3zTz3F/XE2cAz4vrHPhtOsX8UhbUKLeA6jCQJN6MR0nxziGIkqXNLWy5s4uKxMZ X-Received: by 10.112.143.167 with SMTP id sf7mr3872422lbb.0.1423058778023; Wed, 04 Feb 2015 06:06:18 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.87.84 with SMTP id v20ls35175laz.57.gmail; Wed, 04 Feb 2015 06:06:17 -0800 (PST) X-Received: by 10.112.151.228 with SMTP id ut4mr30520225lbb.77.1423058777863; Wed, 04 Feb 2015 06:06:17 -0800 (PST) Received: from mail-lb0-f176.google.com (mail-lb0-f176.google.com. [209.85.217.176]) by mx.google.com with ESMTPS id a4si1373282lbg.132.2015.02.04.06.06.17 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Feb 2015 06:06:17 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.176 as permitted sender) client-ip=209.85.217.176; Received: by mail-lb0-f176.google.com with SMTP id z12so1644756lbi.7 for ; Wed, 04 Feb 2015 06:06:17 -0800 (PST) X-Received: by 10.152.2.41 with SMTP id 9mr9964771lar.59.1423058777714; Wed, 04 Feb 2015 06:06:17 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.35.133 with SMTP id h5csp507580lbj; Wed, 4 Feb 2015 06:06:16 -0800 (PST) X-Received: by 10.180.20.226 with SMTP id q2mr47425313wie.28.1423058774167; Wed, 04 Feb 2015 06:06:14 -0800 (PST) Received: from lists.xen.org (lists.xen.org. [50.57.142.19]) by mx.google.com with ESMTPS id iz17si4185504wic.42.2015.02.04.06.06.13 (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 04 Feb 2015 06:06:14 -0800 (PST) Received-SPF: none (google.com: xen-devel-bounces@lists.xen.org does not designate permitted sender hosts) client-ip=50.57.142.19; Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YJ0Zq-0007ng-6d; Wed, 04 Feb 2015 14:05:10 +0000 Received: from mail6.bemta4.messagelabs.com ([85.158.143.247]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YJ0Zn-0007kX-Ko for xen-devel@lists.xen.org; Wed, 04 Feb 2015 14:05:08 +0000 Received: from [85.158.143.35] by server-1.bemta-4.messagelabs.com id 54/E7-03000-31722D45; Wed, 04 Feb 2015 14:05:07 +0000 X-Env-Sender: parth.dixit@linaro.org X-Msg-Ref: server-14.tower-21.messagelabs.com!1423058704!12506973!1 X-Originating-IP: [209.85.220.51] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 6.13.4; banners=-,-,- X-VirusChecked: Checked Received: (qmail 25866 invoked from network); 4 Feb 2015 14:05:05 -0000 Received: from mail-pa0-f51.google.com (HELO mail-pa0-f51.google.com) (209.85.220.51) by server-14.tower-21.messagelabs.com with RC4-SHA encrypted SMTP; 4 Feb 2015 14:05:05 -0000 Received: by mail-pa0-f51.google.com with SMTP id fb1so2906211pad.10 for ; Wed, 04 Feb 2015 06:05:04 -0800 (PST) X-Received: by 10.66.119.172 with SMTP id kv12mr45565258pab.72.1423058704335; Wed, 04 Feb 2015 06:05:04 -0800 (PST) Received: from parthd-ubunutu.qualcomm.com ([202.46.23.62]) by mx.google.com with ESMTPSA id kg12sm2161881pbb.44.2015.02.04.06.04.58 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 04 Feb 2015 06:05:03 -0800 (PST) From: parth.dixit@linaro.org To: xen-devel@lists.xen.org Date: Wed, 4 Feb 2015 19:32:03 +0530 Message-Id: <1423058539-26403-20-git-send-email-parth.dixit@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1423058539-26403-1-git-send-email-parth.dixit@linaro.org> References: <1423058539-26403-1-git-send-email-parth.dixit@linaro.org> Cc: ian.campbell@citrix.com, Graeme Gregory , Naresh Bhat , julien.grall@linaro.org, tim@xen.org, Tomasz Nowicki , stefano.stabellini@citrix.com, Hanjun Guo , jbeulich@suse.com, Parth Dixit , christoffer.dall@linaro.org Subject: [Xen-devel] [PATCH RFC 19/35] ACPI / GICv2: Add GIC specific ACPI boot support X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: parth.dixit@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.176 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Archive: From: Naresh Bhat 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 Signed-off-by: Graeme Gregory Signed-off-by: Hanjun Guo Signed-off-by: Naresh Bhat Signed-off-by: Parth Dixit 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 +#include +#include +#include + +/* + * 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*/