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