From patchwork Fri Jul 10 10:45:14 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjun Guo X-Patchwork-Id: 51027 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f200.google.com (mail-lb0-f200.google.com [209.85.217.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 06E412290A for ; Fri, 10 Jul 2015 10:46:41 +0000 (UTC) Received: by lbnk3 with SMTP id k3sf20113743lbn.2 for ; Fri, 10 Jul 2015 03:46:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=zZzkr/Y4VEQVvP2fUL8i2kqDXss6WINZlkVrbzOSJ1Y=; b=XS5G8iCsbRCq3zPBdfVr/rS9bZJVrGHAwsZpHqKmJP9/CHpCptTadq/twrKaKmEx13 AyNkZaSfPCM88u6Fz/hTdLR/b0WoV0W7aPbyCRIZcOa2WJ+IgCjh4OxrVEPw1jPvUq9b 1jwx3AlPafUsMgOZnBrWRDwKrSZwhbp97Qc6ubqfZR0g6WdH4gqE5o+2bCXoqVdNq2wC GeUqvDca2EziDprYHFcFgFPpHT/CkAxTeeu0rQknecklu+1T/RukTD0lGQ4cmszDOnw2 sEW+dVKBuBVfswFCBjj6LHj5cQ23frDgKHrY5F9qRt1kODutW5nnN5IjThp6p9DeL15x Lmkg== X-Gm-Message-State: ALoCoQmhjZ5pPeotYPiBhvu0n/bn5PmkS6a3pgbPv17Ov53IMhAdfbikpEaA9YdBceefcD81WXor X-Received: by 10.180.90.106 with SMTP id bv10mr1512734wib.6.1436525200009; Fri, 10 Jul 2015 03:46:40 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.7.105 with SMTP id i9ls439948laa.96.gmail; Fri, 10 Jul 2015 03:46:39 -0700 (PDT) X-Received: by 10.152.246.37 with SMTP id xt5mr19166735lac.83.1436525199836; Fri, 10 Jul 2015 03:46:39 -0700 (PDT) Received: from mail-la0-f45.google.com (mail-la0-f45.google.com. [209.85.215.45]) by mx.google.com with ESMTPS id us12si7340184lbb.107.2015.07.10.03.46.39 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Jul 2015 03:46:39 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.45 as permitted sender) client-ip=209.85.215.45; Received: by lagc2 with SMTP id c2so259953351lag.3 for ; Fri, 10 Jul 2015 03:46:39 -0700 (PDT) X-Received: by 10.152.18.162 with SMTP id x2mr19363874lad.73.1436525199690; Fri, 10 Jul 2015 03:46:39 -0700 (PDT) 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.108.230 with SMTP id hn6csp1288156lbb; Fri, 10 Jul 2015 03:46:38 -0700 (PDT) X-Received: by 10.68.181.163 with SMTP id dx3mr40244309pbc.5.1436525197652; Fri, 10 Jul 2015 03:46:37 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k16si13984505pdm.244.2015.07.10.03.46.36; Fri, 10 Jul 2015 03:46:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-acpi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754466AbbGJKqb (ORCPT + 6 others); Fri, 10 Jul 2015 06:46:31 -0400 Received: from mail-pd0-f178.google.com ([209.85.192.178]:35447 "EHLO mail-pd0-f178.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754393AbbGJKqW (ORCPT ); Fri, 10 Jul 2015 06:46:22 -0400 Received: by pdrg1 with SMTP id g1so50587627pdr.2 for ; Fri, 10 Jul 2015 03:46:22 -0700 (PDT) X-Received: by 10.68.57.172 with SMTP id j12mr40657094pbq.95.1436525182294; Fri, 10 Jul 2015 03:46:22 -0700 (PDT) Received: from localhost (211-79-127-12.veetime.com. [211.79.127.12]) by smtp.googlemail.com with ESMTPSA id u8sm9109578pdj.46.2015.07.10.03.46.20 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 10 Jul 2015 03:46:21 -0700 (PDT) From: Hanjun Guo To: Marc Zyngier , Jason Cooper , Will Deacon , Catalin Marinas , "Rafael J. Wysocki" Cc: Thomas Gleixner , Jiang Liu , Lorenzo Pieralisi , Arnd Bergmann , Tomasz Nowicki , Grant Likely , Mark Brown , Wei Huang , linux-arm-kernel@lists.infradead.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, linaro-acpi@lists.linaro.org, Hanjun Guo Subject: [PATCH v3 8/8] irqchip / gicv3 / ACPI: Add GICR support via GICC structures Date: Fri, 10 Jul 2015 18:45:14 +0800 Message-Id: <1436525114-14425-9-git-send-email-hanjun.guo@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1436525114-14425-1-git-send-email-hanjun.guo@linaro.org> References: <1436525114-14425-1-git-send-email-hanjun.guo@linaro.org> Sender: linux-acpi-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: hanjun.guo@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.215.45 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-Post: , List-Help: , List-Archive: List-Unsubscribe: , On systems supporting GICv3 and above, the field of GICR Base Address holds the 64-bit physical address of the associated Redistributor if the GIC Redistributors are not in the always-on power domain, so instead of init GICR regions via GIC redistributor stricture, init it with GICR base address in GICC structures. Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-acpi.c | 35 ++++++- drivers/irqchip/irq-gic-v3.c | 180 ++++++++++++++++++++++++++++++++--- include/linux/irqchip/arm-gic-acpi.h | 2 + 3 files changed, 203 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index b87a581..792e5ea 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE; static phys_addr_t dist_phy_base __initdata; +u8 __init acpi_gic_version(void) +{ + return gic_version; +} + static int __init acpi_gic_parse_distributor(struct acpi_subtable_header *header, const unsigned long end) @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc; + + gicc = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(gicc, end)) + return -EINVAL; + + /* + * If GICC is enabled but has no valid gicr base address, then it + * means GICR is not presented via GICC + */ + if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address) + return -ENODEV; + + return 0; +} + +static int __init match_gic_redist(struct acpi_subtable_header *header, const unsigned long end) { return 0; @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void) count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, match_gic_redist, 0); - /* that's true if we have at least one GIC redistributor entry */ + /* has at least one GIC redistributor entry */ + if (count > 0) + return true; + + /* else try to find GICR base in GICC entries */ + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_parse_madt_gicc, 0); + return count > 0; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 91d2f9a..fd617d6 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -389,9 +389,8 @@ static void __init gic_dist_init(void) writeq_relaxed(affinity, base + GICD_IROUTER + i * 8); } -static int gic_populate_rdist(void) +static int gic_populate_rdist_with_regions(u64 mpidr) { - u64 mpidr = cpu_logical_map(smp_processor_id()); u64 typer; u32 aff; int i; @@ -439,6 +438,34 @@ static int gic_populate_rdist(void) } while (!(typer & GICR_TYPER_LAST)); } + return -ENODEV; +} + +#ifdef CONFIG_ACPI +/* + * Populate redist when GIC redistributor address is presented in ACPI + * MADT GICC entries + */ +static int gic_populate_rdist_with_gicr_base(u64 mpidr); +#else +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr) +{ + return -ENODEV; +} +#endif + +static int gic_populate_rdist(void) +{ + u64 mpidr = cpu_logical_map(smp_processor_id()); + + if (!gic_data.nr_redist_regions) { + if (!gic_populate_rdist_with_gicr_base(mpidr)) + return 0; + } else { + if (!gic_populate_rdist_with_regions(mpidr)) + return 0; + } + /* We couldn't even deal with ourselves... */ WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n", smp_processor_id(), (unsigned long long)mpidr); @@ -907,6 +934,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); #endif #ifdef CONFIG_ACPI + +struct acpi_gicc_redist { + struct list_head list; + u64 mpidr; + phys_addr_t phys_base; + void __iomem *redist_base; +}; + +static LIST_HEAD(redist_list); + static struct redist_region *redist_regs __initdata; static u32 nr_redist_regions __initdata; static phys_addr_t dist_phy_base __initdata; @@ -940,6 +977,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size) return 0; } +static void __init +gic_acpi_release_redist_regions(void) +{ + int i; + + for (i = 0; i < nr_redist_regions; i++) + if (redist_regs[i].redist_base) + iounmap(redist_regs[i].redist_base); + kfree(redist_regs); +} + static int __init gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, const unsigned long end) @@ -973,10 +1021,101 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr) +{ + struct acpi_gicc_redist *redist; + + redist = kzalloc(sizeof(*redist), GFP_KERNEL); + if (!redist) + return -ENOMEM; + + redist->mpidr = mpidr; + redist->phys_base = phys_base; + + if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3) + /* RD_base + SGI_base */ + redist->redist_base = ioremap(phys_base, 2 * SZ_64K); + else + /* + * RD_base + SGI_base + VLPI_base, + * we don't map reserved page as it's buggy to access it + */ + redist->redist_base = ioremap(phys_base, 3 * SZ_64K); + + if (!redist->redist_base) { + kfree(redist); + return -ENOMEM; + } + + list_add(&redist->list, &redist_list); + return 0; +} + +static void __init +gic_acpi_release_gicc_redist(void) +{ + struct acpi_gicc_redist *redist, *t; + + list_for_each_entry_safe(redist, t, &redist_list, list) { + list_del(&redist->list); + iounmap(redist->redist_base); + kfree(redist); + } +} + +static int __init +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc; + + gicc = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(gicc, end)) + return -EINVAL; + + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return -ENODEV; + + return gic_acpi_add_gicc_redist(gicc->gicr_base_address, + gicc->arm_mpidr); +} + +static int gic_populate_rdist_with_gicr_base(u64 mpidr) +{ + struct acpi_gicc_redist *redist; + void __iomem *ptr; + u32 reg; + + list_for_each_entry(redist, &redist_list, list) { + if (redist->mpidr != mpidr) + continue; + + ptr = redist->redist_base; + reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK; + if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) { + pr_warn("No redistributor present @%p\n", ptr); + return -ENODEV; + } + + gic_data_rdist_rd_base() = ptr; + gic_data_rdist()->phys_base = redist->phys_base; + pr_info("CPU%d: found redistributor %llx phys base:%pa\n", + smp_processor_id(), + (unsigned long long)mpidr, + &gic_data_rdist()->phys_base); + return 0; + } + + return -ENODEV; +} + +static int __init gic_acpi_init(struct acpi_table_header *table) { - int count, i, err = 0; + int count, err = 0; void __iomem *dist_base; + bool no_gicr_entries = false; /* Get distributor base address */ count = acpi_parse_entries(ACPI_SIG_MADT, @@ -1003,29 +1142,44 @@ gic_acpi_init(struct acpi_table_header *table) goto out_dist_unmap; } - /* Collect redistributor base addresses */ + /* Collect redistributor base addresses in GICR entries */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_parse_madt_redist, table, ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); if (count <= 0) { - pr_info("No valid GICR entries exist\n"); - err = -EINVAL; - goto out_redist_unmap; + pr_info("No valid GICR entries exist, try GICC entries\n"); + gic_acpi_release_redist_regions(); + no_gicr_entries = true; + } else { + goto init_base; } + /* Collect redistributor base addresses in GICC entries */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_gicc, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + if (count <= 0) { + pr_info("No valid GICC entries exist\n"); + goto out_release_redist; + } + +init_base: err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0, NULL); if (err) - goto out_redist_unmap; + goto out_release_redist; gsi_cfg_data_add(gic_data.domain, gsi_base, gsi_base + gic_data.irq_nr); return 0; -out_redist_unmap: - for (i = 0; i < nr_redist_regions; i++) - if (redist_regs[i].redist_base) - iounmap(redist_regs[i].redist_base); - kfree(redist_regs); +out_release_redist: + if (no_gicr_entries) { + if (!list_empty(&redist_list)) + gic_acpi_release_gicc_redist(); + } else { + gic_acpi_release_redist_regions(); + } out_dist_unmap: iounmap(dist_base); return err; diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index 56cd82c..0d43f515 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -21,5 +21,7 @@ #define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) #define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K) +u8 acpi_gic_version(void); + #endif /* CONFIG_ACPI */ #endif /* ARM_GIC_ACPI_H_ */