1/* 2 * acpi_numa.c - ACPI NUMA support 3 * 4 * Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com> 5 * 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 * 24 */ 25#include <linux/module.h> 26#include <linux/init.h> 27#include <linux/kernel.h> 28#include <linux/types.h> 29#include <linux/errno.h> 30#include <linux/acpi.h> 31#include <linux/numa.h> 32#include <acpi/acpi_bus.h> 33 34#define PREFIX "ACPI: " 35 36#define ACPI_NUMA 0x80000000 37#define _COMPONENT ACPI_NUMA 38ACPI_MODULE_NAME("numa"); 39 40static nodemask_t nodes_found_map = NODE_MASK_NONE; 41 42/* maps to convert between proximity domain and logical node ID */ 43static int pxm_to_node_map[MAX_PXM_DOMAINS] 44 = { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE }; 45static int node_to_pxm_map[MAX_NUMNODES] 46 = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; 47 48unsigned char acpi_srat_revision __initdata; 49 50int pxm_to_node(int pxm) 51{ 52 if (pxm < 0) 53 return NUMA_NO_NODE; 54 return pxm_to_node_map[pxm]; 55} 56 57int node_to_pxm(int node) 58{ 59 if (node < 0) 60 return PXM_INVAL; 61 return node_to_pxm_map[node]; 62} 63 64void __acpi_map_pxm_to_node(int pxm, int node) 65{ 66 if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm]) 67 pxm_to_node_map[pxm] = node; 68 if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node]) 69 node_to_pxm_map[node] = pxm; 70} 71 72int acpi_map_pxm_to_node(int pxm) 73{ 74 int node = pxm_to_node_map[pxm]; 75 76 if (node < 0) { 77 if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) 78 return NUMA_NO_NODE; 79 node = first_unset_node(nodes_found_map); 80 __acpi_map_pxm_to_node(pxm, node); 81 node_set(node, nodes_found_map); 82 } 83 84 return node; 85} 86 87static void __init 88acpi_table_print_srat_entry(struct acpi_subtable_header *header) 89{ 90 91 ACPI_FUNCTION_NAME("acpi_table_print_srat_entry"); 92 93 if (!header) 94 return; 95 96 switch (header->type) { 97 98 case ACPI_SRAT_TYPE_CPU_AFFINITY: 99#ifdef ACPI_DEBUG_OUTPUT 100 { 101 struct acpi_srat_cpu_affinity *p = 102 (struct acpi_srat_cpu_affinity *)header; 103 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 104 "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", 105 p->apic_id, p->local_sapic_eid, 106 p->proximity_domain_lo, 107 (p->flags & ACPI_SRAT_CPU_ENABLED)? 108 "enabled" : "disabled")); 109 } 110#endif /* ACPI_DEBUG_OUTPUT */ 111 break; 112 113 case ACPI_SRAT_TYPE_MEMORY_AFFINITY: 114#ifdef ACPI_DEBUG_OUTPUT 115 { 116 struct acpi_srat_mem_affinity *p = 117 (struct acpi_srat_mem_affinity *)header; 118 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 119 "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s\n", 120 (unsigned long)p->base_address, 121 (unsigned long)p->length, 122 p->proximity_domain, 123 (p->flags & ACPI_SRAT_MEM_ENABLED)? 124 "enabled" : "disabled", 125 (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)? 126 " hot-pluggable" : "")); 127 } 128#endif /* ACPI_DEBUG_OUTPUT */ 129 break; 130 131 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: 132#ifdef ACPI_DEBUG_OUTPUT 133 { 134 struct acpi_srat_x2apic_cpu_affinity *p = 135 (struct acpi_srat_x2apic_cpu_affinity *)header; 136 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 137 "SRAT Processor (x2apicid[0x%08x]) in" 138 " proximity domain %d %s\n", 139 p->apic_id, 140 p->proximity_domain, 141 (p->flags & ACPI_SRAT_CPU_ENABLED) ? 142 "enabled" : "disabled")); 143 } 144#endif /* ACPI_DEBUG_OUTPUT */ 145 break; 146 default: 147 printk(KERN_WARNING PREFIX 148 "Found unsupported SRAT entry (type = 0x%x)\n", 149 header->type); 150 break; 151 } 152} 153 154/* 155 * A lot of BIOS fill in 10 (= no distance) everywhere. This messes 156 * up the NUMA heuristics which wants the local node to have a smaller 157 * distance than the others. 158 * Do some quick checks here and only use the SLIT if it passes. 159 */ 160static __init int slit_valid(struct acpi_table_slit *slit) 161{ 162 int i, j; 163 int d = slit->locality_count; 164 for (i = 0; i < d; i++) { 165 for (j = 0; j < d; j++) { 166 u8 val = slit->entry[d*i + j]; 167 if (i == j) { 168 if (val != LOCAL_DISTANCE) 169 return 0; 170 } else if (val <= LOCAL_DISTANCE) 171 return 0; 172 } 173 } 174 return 1; 175} 176 177static int __init acpi_parse_slit(struct acpi_table_header *table) 178{ 179 struct acpi_table_slit *slit; 180 181 if (!table) 182 return -EINVAL; 183 184 slit = (struct acpi_table_slit *)table; 185 186 if (!slit_valid(slit)) { 187 printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); 188 return -EINVAL; 189 } 190 acpi_numa_slit_init(slit); 191 192 return 0; 193} 194 195void __init __attribute__ ((weak)) 196acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) 197{ 198 printk(KERN_WARNING PREFIX 199 "Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id); 200 return; 201} 202 203 204static int __init 205acpi_parse_x2apic_affinity(struct acpi_subtable_header *header, 206 const unsigned long end) 207{ 208 struct acpi_srat_x2apic_cpu_affinity *processor_affinity; 209 210 processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header; 211 if (!processor_affinity) 212 return -EINVAL; 213 214 acpi_table_print_srat_entry(header); 215 216 /* let architecture-dependent part to do it */ 217 acpi_numa_x2apic_affinity_init(processor_affinity); 218 219 return 0; 220} 221 222static int __init 223acpi_parse_processor_affinity(struct acpi_subtable_header *header, 224 const unsigned long end) 225{ 226 struct acpi_srat_cpu_affinity *processor_affinity; 227 228 processor_affinity = (struct acpi_srat_cpu_affinity *)header; 229 if (!processor_affinity) 230 return -EINVAL; 231 232 acpi_table_print_srat_entry(header); 233 234 /* let architecture-dependent part to do it */ 235 acpi_numa_processor_affinity_init(processor_affinity); 236 237 return 0; 238} 239 240static int __init 241acpi_parse_memory_affinity(struct acpi_subtable_header * header, 242 const unsigned long end) 243{ 244 struct acpi_srat_mem_affinity *memory_affinity; 245 246 memory_affinity = (struct acpi_srat_mem_affinity *)header; 247 if (!memory_affinity) 248 return -EINVAL; 249 250 acpi_table_print_srat_entry(header); 251 252 /* let architecture-dependent part to do it */ 253 acpi_numa_memory_affinity_init(memory_affinity); 254 255 return 0; 256} 257 258static int __init acpi_parse_srat(struct acpi_table_header *table) 259{ 260 struct acpi_table_srat *srat; 261 if (!table) 262 return -EINVAL; 263 264 srat = (struct acpi_table_srat *)table; 265 acpi_srat_revision = srat->header.revision; 266 267 /* Real work done in acpi_table_parse_srat below. */ 268 269 return 0; 270} 271 272static int __init 273acpi_table_parse_srat(enum acpi_srat_type id, 274 acpi_table_entry_handler handler, unsigned int max_entries) 275{ 276 return acpi_table_parse_entries(ACPI_SIG_SRAT, 277 sizeof(struct acpi_table_srat), id, 278 handler, max_entries); 279} 280 281int __init acpi_numa_init(void) 282{ 283 int cnt = 0; 284 285 /* 286 * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= 287 * SRAT cpu entries could have different order with that in MADT. 288 * So go over all cpu entries in SRAT to get apicid to node mapping. 289 */ 290 291 /* SRAT: Static Resource Affinity Table */ 292 if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { 293 acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY, 294 acpi_parse_x2apic_affinity, 0); 295 acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, 296 acpi_parse_processor_affinity, 0); 297 cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, 298 acpi_parse_memory_affinity, 299 NR_NODE_MEMBLKS); 300 } 301 302 /* SLIT: System Locality Information Table */ 303 acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); 304 305 acpi_numa_arch_fixup(); 306 307 if (cnt <= 0) 308 return cnt ?: -ENOENT; 309 return 0; 310} 311 312int acpi_get_pxm(acpi_handle h) 313{ 314 unsigned long long pxm; 315 acpi_status status; 316 acpi_handle handle; 317 acpi_handle phandle = h; 318 319 do { 320 handle = phandle; 321 status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm); 322 if (ACPI_SUCCESS(status)) 323 return pxm; 324 status = acpi_get_parent(handle, &phandle); 325 } while (ACPI_SUCCESS(status)); 326 return -1; 327} 328 329int acpi_get_node(acpi_handle *handle) 330{ 331 int pxm, node = -1; 332 333 pxm = acpi_get_pxm(handle); 334 if (pxm >= 0 && pxm < MAX_PXM_DOMAINS) 335 node = acpi_map_pxm_to_node(pxm); 336 337 return node; 338} 339EXPORT_SYMBOL(acpi_get_node); 340