]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
arm64, ACPI, NUMA: NUMA support based on SRAT and SLIT
authorHanjun Guo <hanjun.guo@linaro.org>
Tue, 24 May 2016 22:35:44 +0000 (15:35 -0700)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 30 May 2016 12:27:09 +0000 (14:27 +0200)
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 <hanjun.guo@linaro.org>
Signed-off-by: Ganapatrao Kulkarni <gkulkarni@caviumnetworks.com>
[rrichter@cavium.com Reworked for numa v10 series ]
Signed-off-by: Robert Richter <rrichter@cavium.com>
[david.daney@cavium.com reorderd and combinded with other patches in
Hanjun Guo's original set, removed get_mpidr_in_madt() and use
acpi_map_madt_entry() instead.]
Signed-off-by: David Daney <david.daney@cavium.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Dennis Chen <dennis.chen@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/numa.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/acpi_numa.c [new file with mode: 0644]
arch/arm64/kernel/smp.c
arch/arm64/mm/numa.c

index aee323b13802ad143e9774d2076a4b1c63731ece..4b13ecd3977a9848db88ed0fc2f40b6dd25e6d7e 100644 (file)
@@ -113,4 +113,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);
+int acpi_numa_get_nid(unsigned int cpu, u64 hwid);
+#else
+static inline int arm64_acpi_numa_init(void) { return -ENOSYS; }
+static inline int acpi_numa_get_nid(unsigned int cpu, u64 hwid) { return NUMA_NO_NODE; }
+#endif /* CONFIG_ACPI_NUMA */
+
 #endif /*_ASM_ACPI_H*/
index e9b4f2942335a45833d4501b75e1431eedd39756..600887e491fdf2af4ad30dcc0d1601908fcca087 100644 (file)
@@ -5,6 +5,8 @@
 
 #ifdef CONFIG_NUMA
 
+#define NR_NODE_MEMBLKS                (MAX_NUMNODES * 2)
+
 /* currently, arm64 implements flat NUMA topology */
 #define parent_node(node)      (node)
 
index 2173149d8954c6bfe15e562f3d014fa2a00a5ba4..a5125c6d1f87c338d559004b26ec1925f85e7b7f 100644 (file)
@@ -42,6 +42,7 @@ arm64-obj-$(CONFIG_EFI)                       += efi.o efi-entry.stub.o
 arm64-obj-$(CONFIG_PCI)                        += pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)   += armv8_deprecated.o
 arm64-obj-$(CONFIG_ACPI)               += acpi.o
+arm64-obj-$(CONFIG_ACPI_NUMA)          += acpi_numa.o
 arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL)        += acpi_parking_protocol.o
 arm64-obj-$(CONFIG_PARAVIRT)           += paravirt.o
 arm64-obj-$(CONFIG_RANDOMIZE_BASE)     += kaslr.o
diff --git a/arch/arm64/kernel/acpi_numa.c b/arch/arm64/kernel/acpi_numa.c
new file mode 100644 (file)
index 0000000..f85149c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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 <hanjun.guo@linaro.org>
+ *
+ * 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 <linux/acpi.h>
+#include <linux/bitmap.h>
+#include <linux/bootmem.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/memblock.h>
+#include <linux/mmzone.h>
+#include <linux/module.h>
+#include <linux/topology.h>
+
+#include <acpi/processor.h>
+#include <asm/numa.h>
+
+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} };
+
+int acpi_numa_get_nid(unsigned int cpu, u64 hwid)
+{
+       int i;
+
+       for (i = 0; i < cpus_in_srat; i++) {
+               if (hwid == early_node_cpu_hwid[i].cpu_hwid)
+                       return early_node_cpu_hwid[i].node_id;
+       }
+
+       return NUMA_NO_NODE;
+}
+
+/* Callback for Proximity Domain -> ACPI processor UID mapping */
+void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa)
+{
+       int pxm, node;
+       phys_cpuid_t mpidr;
+
+       if (srat_disabled())
+               return;
+
+       if (pa->header.length < sizeof(struct acpi_srat_gicc_affinity)) {
+               pr_err("SRAT: Invalid SRAT header length: %d\n",
+                       pa->header.length);
+               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;
+       }
+
+       mpidr = acpi_map_madt_entry(pa->acpi_processor_uid);
+       if (mpidr == PHYS_CPUID_INVALID) {
+               pr_err("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);
+       cpus_in_srat++;
+       pr_info("SRAT: PXM %d -> MPIDR 0x%Lx -> Node %d\n",
+               pxm, mpidr, node);
+}
+
+int __init arm64_acpi_numa_init(void)
+{
+       int ret;
+
+       ret = acpi_numa_init();
+       if (ret)
+               return ret;
+
+       return srat_disabled() ? -EINVAL : 0;
+}
index 678e0842cb3b72f891684ce502009168fc444627..d0993068c44c1999866907138fea0254c2c2826e 100644 (file)
@@ -560,6 +560,8 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
         */
        acpi_set_mailbox_entry(cpu_count, processor);
 
+       early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid));
+
        cpu_count++;
 }
 
index 1def1de51578a8912d46ef18e7b5604676b5403f..c7fe3ec70774a6c81cb0940940eba389ffa6acb7 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
 #include <linux/module.h>
@@ -391,7 +392,9 @@ static int __init dummy_numa_init(void)
 void __init arm64_numa_init(void)
 {
        if (!numa_off) {
-               if (!numa_init(of_numa_init))
+               if (!acpi_disabled && !numa_init(arm64_acpi_numa_init))
+                       return;
+               if (acpi_disabled && !numa_init(of_numa_init))
                        return;
        }