From patchwork Sat Jan 23 09:39:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjun Guo X-Patchwork-Id: 60256 Delivered-To: patch@linaro.org Received: by 10.112.130.2 with SMTP id oa2csp358248lbb; Sat, 23 Jan 2016 01:44:28 -0800 (PST) X-Received: by 10.98.10.198 with SMTP id 67mr10786304pfk.75.1453542268081; Sat, 23 Jan 2016 01:44:28 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y27si16247293pfi.79.2016.01.23.01.44.27; Sat, 23 Jan 2016 01:44:28 -0800 (PST) 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; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-acpi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-acpi-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751735AbcAWJoY (ORCPT + 6 others); Sat, 23 Jan 2016 04:44:24 -0500 Received: from szxga01-in.huawei.com ([58.251.152.64]:51742 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752577AbcAWJoS (ORCPT ); Sat, 23 Jan 2016 04:44:18 -0500 Received: from 172.24.1.49 (EHLO szxeml428-hub.china.huawei.com) ([172.24.1.49]) by szxrg01-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id DDP83230; Sat, 23 Jan 2016 17:40:31 +0800 (CST) Received: from localhost (10.177.17.188) by szxeml428-hub.china.huawei.com (10.82.67.183) with Microsoft SMTP Server id 14.3.235.1; Sat, 23 Jan 2016 17:40:21 +0800 From: Hanjun Guo To: "Rafael J. Wysocki" , Will Deacon , Catalin Marinas CC: , , , Ganapatrao Kulkarni , Lorenzo Pieralisi , Shannon Zhao , "Steve Capper" , Mark Rutland , Robert Richter , Hanjun Guo Subject: [PATCH v3 05/12] arm64, acpi, numa: NUMA support based on SRAT and SLIT Date: Sat, 23 Jan 2016 17:39:20 +0800 Message-ID: <1453541967-3744-6-git-send-email-guohanjun@huawei.com> X-Mailer: git-send-email 1.7.10.msysgit.1 In-Reply-To: <1453541967-3744-1-git-send-email-guohanjun@huawei.com> References: <1453541967-3744-1-git-send-email-guohanjun@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.177.17.188] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020202.56A34A90.0072, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 4e5ef4717760a13e76ec94a9b8babac6 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org From: Hanjun Guo Introduce a new file to hold ACPI based NUMA information parsing from SRAT and SLIT. SRAT includes the CPU ACPI ID to Proximity Domain mappings and memory ranges to Proximity Domain mapping. SLIT has the information of inter node distances(relative number for access latency). Signed-off-by: Hanjun Guo Signed-off-by: Ganapatrao Kulkarni --- arch/arm64/include/asm/acpi.h | 8 ++ arch/arm64/include/asm/numa.h | 3 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/acpi_numa.c | 235 ++++++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/smp.c | 3 + arch/arm64/mm/numa.c | 5 +- 6 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 arch/arm64/kernel/acpi_numa.c -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index caafd63..6db9c6f 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -96,4 +96,12 @@ static inline const char *acpi_get_enable_method(int cpu) pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr); #endif +#ifdef CONFIG_ACPI_NUMA +int arm64_acpi_numa_init(void); +void acpi_numa_set_node_info(unsigned int cpu, u64 hwid); +#else +static inline int arm64_acpi_numa_init(void) { return -ENODEV; } +static inline void acpi_numa_set_node_info(unsigned int cpu, u64 hwid) { } +#endif /* CONFIG_ACPI_NUMA */ + #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/include/asm/numa.h b/arch/arm64/include/asm/numa.h index 54deb38..1beb194 100644 --- a/arch/arm64/include/asm/numa.h +++ b/arch/arm64/include/asm/numa.h @@ -6,6 +6,8 @@ #ifdef CONFIG_NUMA +#define NR_NODE_MEMBLKS (MAX_NUMNODES * 2) + /* currently, arm64 implements flat NUMA topology */ #define parent_node(node) (node) @@ -43,6 +45,7 @@ struct device_node; int __init arm64_of_numa_init(void); void __init of_numa_set_node_info(unsigned int cpu, struct device_node *dn); #else +static inline int arm64_of_numa_init(void) { return -ENODEV; } static inline void of_numa_set_node_info(unsigned int cpu, struct device_node *dn) { } #endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7987763..555c4a5 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -42,6 +42,7 @@ arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o arm64-obj-$(CONFIG_OF_NUMA) += of_numa.o +arm64-obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/acpi_numa.c b/arch/arm64/kernel/acpi_numa.c new file mode 100644 index 0000000..f7f7533 --- /dev/null +++ b/arch/arm64/kernel/acpi_numa.c @@ -0,0 +1,235 @@ +/* + * ACPI 5.1 based NUMA setup for ARM64 + * Lots of code was borrowed from arch/x86/mm/srat.c + * + * Copyright 2004 Andi Kleen, SuSE Labs. + * Copyright (C) 2013-2016, Linaro Ltd. + * Author: Hanjun Guo + * + * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. + * + * Called from acpi_numa_init while reading the SRAT and SLIT tables. + * Assumes all memory regions belonging to a single proximity domain + * are in one chunk. Holes between them will be included in the node. + */ + +#define pr_fmt(fmt) "ACPI: NUMA: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int acpi_numa __initdata; +static int cpus_in_srat; + +struct __node_cpu_hwid { + u32 node_id; /* logical node containing this CPU */ + u64 cpu_hwid; /* MPIDR for this CPU */ +}; + +static struct __node_cpu_hwid early_node_cpu_hwid[NR_CPUS] = { +[0 ... NR_CPUS - 1] = {NUMA_NO_NODE, PHYS_CPUID_INVALID} }; + +static __init void bad_srat(void) +{ + pr_err("SRAT not used.\n"); + acpi_numa = -1; +} + +static __init inline int srat_disabled(void) +{ + return acpi_numa < 0; +} + +void __init acpi_numa_set_node_info(unsigned int cpu, u64 hwid) +{ + int nid = 0, i; + + for (i = 0; i < cpus_in_srat; i++) { + if (hwid == early_node_cpu_hwid[i].cpu_hwid) { + nid = early_node_cpu_hwid[i].node_id; + break; + } + } + + cpu_to_node_map[cpu] = nid; +} + +/* + * Callback for SLIT parsing. + * It will get the distance information presented by SLIT + * and init the distance matrix of numa nodes + */ +void __init acpi_numa_slit_init(struct acpi_table_slit *slit) +{ + int i, j; + + for (i = 0; i < slit->locality_count; i++) { + const int from_node = pxm_to_node(i); + + if (from_node == NUMA_NO_NODE) + continue; + + for (j = 0; j < slit->locality_count; j++) { + const int to_node = pxm_to_node(j); + + if (to_node == NUMA_NO_NODE) + continue; + + pr_debug("SLIT: Distance[%d][%d] = %d\n", + from_node, to_node, + slit->entry[ + slit->locality_count * i + j]); + numa_set_distance(from_node, to_node, + slit->entry[slit->locality_count * i + j]); + } + } +} + +static int __init get_mpidr_in_madt(int acpi_id, u64 *mpidr) +{ + unsigned long madt_end, entry; + struct acpi_table_madt *madt; + acpi_size tbl_size; + + if (ACPI_FAILURE(acpi_get_table_with_size(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt, &tbl_size))) + return -ENODEV; + + entry = (unsigned long)madt; + madt_end = entry + madt->header.length; + + /* Parse all entries looking for a match. */ + entry += sizeof(struct acpi_table_madt); + while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + struct acpi_subtable_header *header = + (struct acpi_subtable_header *)entry; + + if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) { + struct acpi_madt_generic_interrupt *gicc = + container_of(header, + struct acpi_madt_generic_interrupt, header); + + if ((gicc->flags & ACPI_MADT_ENABLED) && + (gicc->uid == acpi_id)) { + *mpidr = gicc->arm_mpidr; + early_acpi_os_unmap_memory(madt, tbl_size); + return 0; + } + } + entry += header->length; + } + + early_acpi_os_unmap_memory(madt, tbl_size); + return -ENODEV; +} + +/* Callback for Proximity Domain -> ACPI processor UID mapping */ +void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) +{ + int pxm, node; + u64 mpidr; + + if (srat_disabled()) + return; + + if (pa->header.length < sizeof(struct acpi_srat_gicc_affinity)) { + bad_srat(); + return; + } + + if (!(pa->flags & ACPI_SRAT_GICC_ENABLED)) + return; + + if (cpus_in_srat >= NR_CPUS) { + pr_warn_once("SRAT: cpu_to_node_map[%d] is too small, may not be able to use all cpus\n", + NR_CPUS); + return; + } + + pxm = pa->proximity_domain; + node = acpi_map_pxm_to_node(pxm); + + if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) { + pr_err("SRAT: Too many proximity domains %d\n", pxm); + bad_srat(); + return; + } + + if (get_mpidr_in_madt(pa->acpi_processor_uid, &mpidr)) { + pr_warn("SRAT: PXM %d with ACPI ID %d has no valid MPIDR in MADT\n", + pxm, pa->acpi_processor_uid); + bad_srat(); + return; + } + + early_node_cpu_hwid[cpus_in_srat].node_id = node; + early_node_cpu_hwid[cpus_in_srat].cpu_hwid = mpidr; + node_set(node, numa_nodes_parsed); + acpi_numa = 1; + cpus_in_srat++; + pr_info("SRAT: PXM %d -> MPIDR 0x%Lx -> Node %d cpu %d\n", + pxm, mpidr, node, cpus_in_srat); +} + +/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ +int __init acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) +{ + u64 start, end; + int node, pxm; + + if (srat_disabled()) + return -EINVAL; + + if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { + bad_srat(); + return -EINVAL; + } + + /* Ignore disabled entries */ + if (!(ma->flags & ACPI_SRAT_MEM_ENABLED)) + return -EINVAL; + + start = ma->base_address; + end = start + ma->length; + pxm = ma->proximity_domain; + + node = acpi_map_pxm_to_node(pxm); + + if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) { + pr_err("SRAT: Too many proximity domains.\n"); + bad_srat(); + return -EINVAL; + } + + pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n", + node, pxm, + (unsigned long long) start, (unsigned long long) end - 1); + + if (numa_add_memblk(node, start, (end - start)) < 0) { + bad_srat(); + return -EINVAL; + } + + return 0; +} + +int __init arm64_acpi_numa_init(void) +{ + int ret; + + ret = acpi_numa_init(); + if (ret) + return ret; + + return srat_disabled() ? -EINVAL : 0; +} diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index a2a8c2d..112a892 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -447,6 +447,9 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) /* map the logical cpu id to cpu MPIDR */ cpu_logical_map(cpu_count) = hwid; + /* map logical cpu to node */ + acpi_numa_set_node_info(cpu_count, hwid); + cpu_count++; } diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 9e8704b..e974995 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -385,10 +386,8 @@ void __init arm64_numa_init(void) { int ret = -ENODEV; -#ifdef CONFIG_OF_NUMA if (!numa_off) - ret = numa_init(arm64_of_numa_init); -#endif + ret = numa_init(acpi_disabled ? arm64_of_numa_init : arm64_acpi_numa_init); if (ret) numa_init(dummy_numa_init);