1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 27b2600f8STejun Heo /* 37b2600f8STejun Heo * ACPI 3.0 based NUMA setup 47b2600f8STejun Heo * Copyright 2004 Andi Kleen, SuSE Labs. 57b2600f8STejun Heo * 67b2600f8STejun Heo * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. 77b2600f8STejun Heo * 87b2600f8STejun Heo * Called from acpi_numa_init while reading the SRAT and SLIT tables. 97b2600f8STejun Heo * Assumes all memory regions belonging to a single proximity domain 107b2600f8STejun Heo * are in one chunk. Holes between them will be included in the node. 117b2600f8STejun Heo */ 127b2600f8STejun Heo 137b2600f8STejun Heo #include <linux/kernel.h> 147b2600f8STejun Heo #include <linux/acpi.h> 157b2600f8STejun Heo #include <linux/mmzone.h> 167b2600f8STejun Heo #include <linux/bitmap.h> 174b599fedSPaul Gortmaker #include <linux/init.h> 187b2600f8STejun Heo #include <linux/topology.h> 197b2600f8STejun Heo #include <linux/mm.h> 207b2600f8STejun Heo #include <asm/proto.h> 217b2600f8STejun Heo #include <asm/numa.h> 2266441bd3SIngo Molnar #include <asm/e820/api.h> 237b2600f8STejun Heo #include <asm/apic.h> 247b2600f8STejun Heo #include <asm/uv/uv.h> 257b2600f8STejun Heo 267b2600f8STejun Heo /* Callback for Proximity Domain -> x2APIC mapping */ 277b2600f8STejun Heo void __init 287b2600f8STejun Heo acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) 297b2600f8STejun Heo { 307b2600f8STejun Heo int pxm, node; 317b2600f8STejun Heo int apic_id; 327b2600f8STejun Heo 337b2600f8STejun Heo if (srat_disabled()) 347b2600f8STejun Heo return; 357b2600f8STejun Heo if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { 367b2600f8STejun Heo bad_srat(); 377b2600f8STejun Heo return; 387b2600f8STejun Heo } 397b2600f8STejun Heo if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 407b2600f8STejun Heo return; 417b2600f8STejun Heo pxm = pa->proximity_domain; 42a35fd282SYinghai Lu apic_id = pa->apic_id; 43b7157acfSSteffen Persvold if (!apic->apic_id_valid(apic_id)) { 44a35fd282SYinghai Lu printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n", 45a35fd282SYinghai Lu pxm, apic_id); 46a35fd282SYinghai Lu return; 47a35fd282SYinghai Lu } 482faeff1dSHanjun Guo node = acpi_map_pxm_to_node(pxm); 497b2600f8STejun Heo if (node < 0) { 507b2600f8STejun Heo printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 517b2600f8STejun Heo bad_srat(); 527b2600f8STejun Heo return; 537b2600f8STejun Heo } 547b2600f8STejun Heo 557b2600f8STejun Heo if (apic_id >= MAX_LOCAL_APIC) { 567b2600f8STejun Heo printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 577b2600f8STejun Heo return; 587b2600f8STejun Heo } 597b2600f8STejun Heo set_apicid_to_node(apic_id, node); 607b2600f8STejun Heo node_set(node, numa_nodes_parsed); 617b2600f8STejun Heo printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", 627b2600f8STejun Heo pxm, apic_id, node); 637b2600f8STejun Heo } 647b2600f8STejun Heo 657b2600f8STejun Heo /* Callback for Proximity Domain -> LAPIC mapping */ 667b2600f8STejun Heo void __init 677b2600f8STejun Heo acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) 687b2600f8STejun Heo { 697b2600f8STejun Heo int pxm, node; 707b2600f8STejun Heo int apic_id; 717b2600f8STejun Heo 727b2600f8STejun Heo if (srat_disabled()) 737b2600f8STejun Heo return; 747b2600f8STejun Heo if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { 757b2600f8STejun Heo bad_srat(); 767b2600f8STejun Heo return; 777b2600f8STejun Heo } 787b2600f8STejun Heo if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 797b2600f8STejun Heo return; 807b2600f8STejun Heo pxm = pa->proximity_domain_lo; 81cd298f60SKurt Garloff if (acpi_srat_revision >= 2) 82cd298f60SKurt Garloff pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; 832faeff1dSHanjun Guo node = acpi_map_pxm_to_node(pxm); 847b2600f8STejun Heo if (node < 0) { 857b2600f8STejun Heo printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 867b2600f8STejun Heo bad_srat(); 877b2600f8STejun Heo return; 887b2600f8STejun Heo } 897b2600f8STejun Heo 907b2600f8STejun Heo if (get_uv_system_type() >= UV_X2APIC) 917b2600f8STejun Heo apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; 927b2600f8STejun Heo else 937b2600f8STejun Heo apic_id = pa->apic_id; 947b2600f8STejun Heo 957b2600f8STejun Heo if (apic_id >= MAX_LOCAL_APIC) { 967b2600f8STejun Heo printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 977b2600f8STejun Heo return; 987b2600f8STejun Heo } 997b2600f8STejun Heo 1007b2600f8STejun Heo set_apicid_to_node(apic_id, node); 1017b2600f8STejun Heo node_set(node, numa_nodes_parsed); 1027b2600f8STejun Heo printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", 1037b2600f8STejun Heo pxm, apic_id, node); 1047b2600f8STejun Heo } 1057b2600f8STejun Heo 1067b2600f8STejun Heo int __init x86_acpi_numa_init(void) 1077b2600f8STejun Heo { 1087b2600f8STejun Heo int ret; 1097b2600f8STejun Heo 1107b2600f8STejun Heo ret = acpi_numa_init(); 1117b2600f8STejun Heo if (ret < 0) 1127b2600f8STejun Heo return ret; 1137b2600f8STejun Heo return srat_disabled() ? -EINVAL : 0; 1147b2600f8STejun Heo } 115