From patchwork Thu Jul 24 13:00:13 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjun Guo X-Patchwork-Id: 4617951 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DCF99C0514 for ; Thu, 24 Jul 2014 13:05:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D8D67200E5 for ; Thu, 24 Jul 2014 13:05:58 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BBE0F201DD for ; Thu, 24 Jul 2014 13:05:57 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XAIft-00016O-UM; Thu, 24 Jul 2014 13:03:09 +0000 Received: from mail-pd0-f173.google.com ([209.85.192.173]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XAIfF-0008Kk-65 for linux-arm-kernel@lists.infradead.org; Thu, 24 Jul 2014 13:02:33 +0000 Received: by mail-pd0-f173.google.com with SMTP id w10so3640029pde.32 for ; Thu, 24 Jul 2014 06:02:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=g9/1FBEqdlXFM4BvIPfJbzYXlkmwg/5KHD0coayvJJw=; b=mDRH1sgEkB7bljafvC35kD+jMn764O2fX0ujjeSMt84I+Mhgv738M0OgS6KuISXTfI EGwHnS89hSkD/AkNhH7xLDsoYHC7Xh690QEL6fay3H5ys8mGp3jbOJ6XrMisohSgI+Ey BwnxZ60k+xpBN5wGq/3++jk9IKPpIMwOe5+RJbN4FrbGZD3kdUkvqZhH9iywsMF+OFii Kbw1p2xdrmWylJ65MJ07ZGoVDrSU3wiRsbiHQVItFF+tlBsLM7M/ht2zjR9jsqdHCM91 6PBybS6YXdYJcVz1aBpdmezkpnU8YPaOkRuQXOrpxIG2sdj0Nqv0z0Uxe43YPgnC52i2 0ZHA== X-Gm-Message-State: ALoCoQkUX31iXzXp900WY26K9i3TbUIL5kCP8F2pLNPPc5I/ZX+MAMZVWfz9/R2SRpYRiR6MEgQU X-Received: by 10.70.94.100 with SMTP id db4mr10134073pdb.122.1406206928178; Thu, 24 Jul 2014 06:02:08 -0700 (PDT) Received: from localhost ([183.247.163.231]) by mx.google.com with ESMTPSA id rf14sm6293940pdb.73.2014.07.24.06.02.01 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Thu, 24 Jul 2014 06:02:07 -0700 (PDT) From: Hanjun Guo To: Catalin Marinas , "Rafael J. Wysocki" , Mark Rutland Subject: [PATCH 07/19] ARM64 / ACPI: Parse MADT to map logical cpu to MPIDR and get cpu_possible/present_map Date: Thu, 24 Jul 2014 21:00:13 +0800 Message-Id: <1406206825-15590-8-git-send-email-hanjun.guo@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1406206825-15590-1-git-send-email-hanjun.guo@linaro.org> References: <1406206825-15590-1-git-send-email-hanjun.guo@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140724_060229_367652_151EF7B4 X-CRM114-Status: GOOD ( 23.31 ) X-Spam-Score: -0.7 (/) Cc: Mark Brown , Liviu Dudau , Lv Zheng , Lorenzo Pieralisi , Daniel Lezcano , Robert Moore , linux-acpi@vger.kernel.org, Grant Likely , Charles.Garcia-Tobin@arm.com, Robert Richter , Jason Cooper , Arnd Bergmann , Marc Zyngier , Will Deacon , Tomasz Nowicki , linaro-acpi-private@linaro.org, Bjorn Helgaas , linux-arm-kernel@lists.infradead.org, Graeme Gregory , Randy Dunlap , linux-kernel@vger.kernel.org, Hanjun Guo , Sudeep Holla X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP MADT contains the information for MPIDR which is essential for SMP initialization, parse the GIC cpu interface structures to get the MPIDR value and map it to cpu_logical_map(), and add enabled cpu with valid MPIDR into cpu_possible_map and cpu_present_map. Signed-off-by: Hanjun Guo Signed-off-by: Tomasz Nowicki --- arch/arm64/include/asm/acpi.h | 2 + arch/arm64/kernel/acpi.c | 127 +++++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/smp.c | 10 +++- 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 67dac90..5ce85f8 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -50,6 +50,8 @@ static inline bool acpi_has_cpu_in_madt(void) extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0 +#define MAX_GIC_CPU_INTERFACE 65535 + #endif /* CONFIG_ACPI */ #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 374926f..801e268 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -22,6 +22,9 @@ #include #include +#include +#include + /* * We never plan to use RSDT on arm/arm64 as its deprecated in spec but this * variable is still required by the ACPI core @@ -42,6 +45,9 @@ int acpi_psci_present; /* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */ int acpi_psci_use_hvc; +/* Processors (GICC) with enabled flag in MADT */ +static int enabled_cpus; + /* * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. @@ -62,6 +68,122 @@ void __init __acpi_unmap_table(char *map, unsigned long size) early_iounmap(map, size); } +/** + * acpi_register_gic_cpu_interface - register a gic cpu interface and + * generates a logic cpu number + * @mpidr: CPU's hardware id to register, MPIDR represented in MADT + * @enabled: this cpu is enabled or not + * + * Returns the logic cpu number which maps to the gic cpu interface + */ +static int acpi_register_gic_cpu_interface(u64 mpidr, u8 enabled) +{ + int cpu; + + if (mpidr == INVALID_HWID) { + pr_info("Skip invalid cpu hardware ID\n"); + return -EINVAL; + } + + total_cpus++; + if (!enabled) + return -EINVAL; + + if (enabled_cpus >= NR_CPUS) { + pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n", + NR_CPUS, total_cpus, mpidr); + return -EINVAL; + } + + /* If it is the first CPU, no need to check duplicate MPIDRs */ + if (!enabled_cpus) + goto skip_mpidr_check; + + /* + * Duplicate MPIDRs are a recipe for disaster. Scan + * all initialized entries and check for + * duplicates. If any is found just ignore the CPU. + */ + for_each_present_cpu(cpu) { + if (cpu_logical_map(cpu) == mpidr) { + pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n", + mpidr); + return -EINVAL; + } + } + +skip_mpidr_check: + enabled_cpus++; + + /* allocate a logic cpu id for the new comer */ + if (cpu_logical_map(0) == mpidr) { + /* + * boot_cpu_init() already hold bit 0 in cpu_present_mask + * for BSP, no need to allocte again. + */ + cpu = 0; + } else { + cpu = cpumask_next_zero(-1, cpu_present_mask); + } + + /* map the logic cpu id to cpu MPIDR */ + cpu_logical_map(cpu) = mpidr; + + set_cpu_possible(cpu, true); + set_cpu_present(cpu, true); + + return cpu; +} + +static int __init +acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *processor; + + processor = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + acpi_register_gic_cpu_interface(processor->mpidr, + processor->flags & ACPI_MADT_ENABLED); + + return 0; +} + +/* + * Parse GIC cpu interface related entries in MADT + * returns 0 on success, < 0 on error + */ +static int __init acpi_parse_madt_gic_cpu_interface_entries(void) +{ + int count; + + /* + * do a partial walk of MADT to determine how many CPUs + * we have including disabled CPUs, and get information + * we need for SMP init + */ + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + acpi_parse_gic_cpu_interface, MAX_GIC_CPU_INTERFACE); + + if (!count) { + pr_err("No GIC CPU interface entries present\n"); + return -ENODEV; + } else if (count < 0) { + pr_err("Error parsing GIC CPU interface entry\n"); + return count; + } + + /* Make boot-up look pretty */ + pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); + + return 0; +} + static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; @@ -122,6 +244,11 @@ int __init acpi_boot_init(void) if (err) pr_err("Can't find FADT\n"); + /* Get the boot CPU's MPIDR before MADT parsing */ + cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; + + err = acpi_parse_madt_gic_cpu_interface_entries(); + return err; } diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 40f38f4..8f1d37c 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -458,7 +459,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (err) continue; - set_cpu_present(cpu, true); + /* + * In ACPI mode, cpu_present_map was initialised when + * MADT table was parsed which before this function + * is called. + */ + if (acpi_disabled) + set_cpu_present(cpu, true); + max_cpus--; } }