Skip to content

Commit d8b47fc

Browse files
hanjun-guorafaeljw
authored andcommitted
arm64, ACPI, NUMA: NUMA support based on SRAT and SLIT
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>
1 parent fb7c2ba commit d8b47fc

File tree

6 files changed

+129
-1
lines changed

6 files changed

+129
-1
lines changed

arch/arm64/include/asm/acpi.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,12 @@ static inline const char *acpi_get_enable_method(int cpu)
113113
pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
114114
#endif
115115

116+
#ifdef CONFIG_ACPI_NUMA
117+
int arm64_acpi_numa_init(void);
118+
int acpi_numa_get_nid(unsigned int cpu, u64 hwid);
119+
#else
120+
static inline int arm64_acpi_numa_init(void) { return -ENOSYS; }
121+
static inline int acpi_numa_get_nid(unsigned int cpu, u64 hwid) { return NUMA_NO_NODE; }
122+
#endif /* CONFIG_ACPI_NUMA */
123+
116124
#endif /*_ASM_ACPI_H*/

arch/arm64/include/asm/numa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#ifdef CONFIG_NUMA
77

8+
#define NR_NODE_MEMBLKS (MAX_NUMNODES * 2)
9+
810
/* currently, arm64 implements flat NUMA topology */
911
#define parent_node(node) (node)
1012

arch/arm64/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
4242
arm64-obj-$(CONFIG_PCI) += pci.o
4343
arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
4444
arm64-obj-$(CONFIG_ACPI) += acpi.o
45+
arm64-obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
4546
arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o
4647
arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o
4748
arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o

arch/arm64/kernel/acpi_numa.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* ACPI 5.1 based NUMA setup for ARM64
3+
* Lots of code was borrowed from arch/x86/mm/srat.c
4+
*
5+
* Copyright 2004 Andi Kleen, SuSE Labs.
6+
* Copyright (C) 2013-2016, Linaro Ltd.
7+
* Author: Hanjun Guo <hanjun.guo@linaro.org>
8+
*
9+
* Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
10+
*
11+
* Called from acpi_numa_init while reading the SRAT and SLIT tables.
12+
* Assumes all memory regions belonging to a single proximity domain
13+
* are in one chunk. Holes between them will be included in the node.
14+
*/
15+
16+
#define pr_fmt(fmt) "ACPI: NUMA: " fmt
17+
18+
#include <linux/acpi.h>
19+
#include <linux/bitmap.h>
20+
#include <linux/bootmem.h>
21+
#include <linux/kernel.h>
22+
#include <linux/mm.h>
23+
#include <linux/memblock.h>
24+
#include <linux/mmzone.h>
25+
#include <linux/module.h>
26+
#include <linux/topology.h>
27+
28+
#include <acpi/processor.h>
29+
#include <asm/numa.h>
30+
31+
static int cpus_in_srat;
32+
33+
struct __node_cpu_hwid {
34+
u32 node_id; /* logical node containing this CPU */
35+
u64 cpu_hwid; /* MPIDR for this CPU */
36+
};
37+
38+
static struct __node_cpu_hwid early_node_cpu_hwid[NR_CPUS] = {
39+
[0 ... NR_CPUS - 1] = {NUMA_NO_NODE, PHYS_CPUID_INVALID} };
40+
41+
int acpi_numa_get_nid(unsigned int cpu, u64 hwid)
42+
{
43+
int i;
44+
45+
for (i = 0; i < cpus_in_srat; i++) {
46+
if (hwid == early_node_cpu_hwid[i].cpu_hwid)
47+
return early_node_cpu_hwid[i].node_id;
48+
}
49+
50+
return NUMA_NO_NODE;
51+
}
52+
53+
/* Callback for Proximity Domain -> ACPI processor UID mapping */
54+
void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa)
55+
{
56+
int pxm, node;
57+
phys_cpuid_t mpidr;
58+
59+
if (srat_disabled())
60+
return;
61+
62+
if (pa->header.length < sizeof(struct acpi_srat_gicc_affinity)) {
63+
pr_err("SRAT: Invalid SRAT header length: %d\n",
64+
pa->header.length);
65+
bad_srat();
66+
return;
67+
}
68+
69+
if (!(pa->flags & ACPI_SRAT_GICC_ENABLED))
70+
return;
71+
72+
if (cpus_in_srat >= NR_CPUS) {
73+
pr_warn_once("SRAT: cpu_to_node_map[%d] is too small, may not be able to use all cpus\n",
74+
NR_CPUS);
75+
return;
76+
}
77+
78+
pxm = pa->proximity_domain;
79+
node = acpi_map_pxm_to_node(pxm);
80+
81+
if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
82+
pr_err("SRAT: Too many proximity domains %d\n", pxm);
83+
bad_srat();
84+
return;
85+
}
86+
87+
mpidr = acpi_map_madt_entry(pa->acpi_processor_uid);
88+
if (mpidr == PHYS_CPUID_INVALID) {
89+
pr_err("SRAT: PXM %d with ACPI ID %d has no valid MPIDR in MADT\n",
90+
pxm, pa->acpi_processor_uid);
91+
bad_srat();
92+
return;
93+
}
94+
95+
early_node_cpu_hwid[cpus_in_srat].node_id = node;
96+
early_node_cpu_hwid[cpus_in_srat].cpu_hwid = mpidr;
97+
node_set(node, numa_nodes_parsed);
98+
cpus_in_srat++;
99+
pr_info("SRAT: PXM %d -> MPIDR 0x%Lx -> Node %d\n",
100+
pxm, mpidr, node);
101+
}
102+
103+
int __init arm64_acpi_numa_init(void)
104+
{
105+
int ret;
106+
107+
ret = acpi_numa_init();
108+
if (ret)
109+
return ret;
110+
111+
return srat_disabled() ? -EINVAL : 0;
112+
}

arch/arm64/kernel/smp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
560560
*/
561561
acpi_set_mailbox_entry(cpu_count, processor);
562562

563+
early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid));
564+
563565
cpu_count++;
564566
}
565567

arch/arm64/mm/numa.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
*/
1919

20+
#include <linux/acpi.h>
2021
#include <linux/bootmem.h>
2122
#include <linux/memblock.h>
2223
#include <linux/module.h>
@@ -391,7 +392,9 @@ static int __init dummy_numa_init(void)
391392
void __init arm64_numa_init(void)
392393
{
393394
if (!numa_off) {
394-
if (!numa_init(of_numa_init))
395+
if (!acpi_disabled && !numa_init(arm64_acpi_numa_init))
396+
return;
397+
if (acpi_disabled && !numa_init(of_numa_init))
395398
return;
396399
}
397400

0 commit comments

Comments
 (0)