1/* 2 * ACPI 3.0 based NUMA setup 3 * Copyright 2004 Andi Kleen, SuSE Labs. 4 * 5 * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. 6 * 7 * Called from acpi_numa_init while reading the SRAT and SLIT tables. 8 * Assumes all memory regions belonging to a single proximity domain 9 * are in one chunk. Holes between them will be included in the node. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/acpi.h> 14#include <linux/mmzone.h> 15#include <linux/bitmap.h> 16#include <linux/module.h> 17#include <linux/topology.h> 18#include <linux/bootmem.h> 19#include <linux/memblock.h> 20#include <linux/mm.h> 21#include <asm/proto.h> 22#include <asm/numa.h> 23#include <asm/e820.h> 24#include <asm/apic.h> 25#include <asm/uv/uv.h> 26 27int acpi_numa __initdata; 28 29static __init int setup_node(int pxm) 30{ 31 return acpi_map_pxm_to_node(pxm); 32} 33 34static __init void bad_srat(void) 35{ 36 printk(KERN_ERR "SRAT: SRAT not used.\n"); 37 acpi_numa = -1; 38} 39 40static __init inline int srat_disabled(void) 41{ 42 return acpi_numa < 0; 43} 44 45/* 46 * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for 47 * I/O localities since SRAT does not list them. I/O localities are 48 * not supported at this point. 49 */ 50void __init acpi_numa_slit_init(struct acpi_table_slit *slit) 51{ 52 int i, j; 53 54 for (i = 0; i < slit->locality_count; i++) { 55 const int from_node = pxm_to_node(i); 56 57 if (from_node == NUMA_NO_NODE) 58 continue; 59 60 for (j = 0; j < slit->locality_count; j++) { 61 const int to_node = pxm_to_node(j); 62 63 if (to_node == NUMA_NO_NODE) 64 continue; 65 66 numa_set_distance(from_node, to_node, 67 slit->entry[slit->locality_count * i + j]); 68 } 69 } 70} 71 72/* Callback for Proximity Domain -> x2APIC mapping */ 73void __init 74acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) 75{ 76 int pxm, node; 77 int apic_id; 78 79 if (srat_disabled()) 80 return; 81 if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { 82 bad_srat(); 83 return; 84 } 85 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 86 return; 87 pxm = pa->proximity_domain; 88 apic_id = pa->apic_id; 89 if (!apic->apic_id_valid(apic_id)) { 90 printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n", 91 pxm, apic_id); 92 return; 93 } 94 node = setup_node(pxm); 95 if (node < 0) { 96 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 97 bad_srat(); 98 return; 99 } 100 101 if (apic_id >= MAX_LOCAL_APIC) { 102 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 103 return; 104 } 105 set_apicid_to_node(apic_id, node); 106 node_set(node, numa_nodes_parsed); 107 acpi_numa = 1; 108 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", 109 pxm, apic_id, node); 110} 111 112/* Callback for Proximity Domain -> LAPIC mapping */ 113void __init 114acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) 115{ 116 int pxm, node; 117 int apic_id; 118 119 if (srat_disabled()) 120 return; 121 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { 122 bad_srat(); 123 return; 124 } 125 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 126 return; 127 pxm = pa->proximity_domain_lo; 128 if (acpi_srat_revision >= 2) 129 pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; 130 node = setup_node(pxm); 131 if (node < 0) { 132 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 133 bad_srat(); 134 return; 135 } 136 137 if (get_uv_system_type() >= UV_X2APIC) 138 apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; 139 else 140 apic_id = pa->apic_id; 141 142 if (apic_id >= MAX_LOCAL_APIC) { 143 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 144 return; 145 } 146 147 set_apicid_to_node(apic_id, node); 148 node_set(node, numa_nodes_parsed); 149 acpi_numa = 1; 150 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", 151 pxm, apic_id, node); 152} 153 154#ifdef CONFIG_MEMORY_HOTPLUG 155static inline int save_add_info(void) {return 1;} 156#else 157static inline int save_add_info(void) {return 0;} 158#endif 159 160/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ 161int __init 162acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) 163{ 164 u64 start, end; 165 u32 hotpluggable; 166 int node, pxm; 167 168 if (srat_disabled()) 169 goto out_err; 170 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) 171 goto out_err_bad_srat; 172 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) 173 goto out_err; 174 hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; 175 if (hotpluggable && !save_add_info()) 176 goto out_err; 177 178 start = ma->base_address; 179 end = start + ma->length; 180 pxm = ma->proximity_domain; 181 if (acpi_srat_revision <= 1) 182 pxm &= 0xff; 183 184 node = setup_node(pxm); 185 if (node < 0) { 186 printk(KERN_ERR "SRAT: Too many proximity domains.\n"); 187 goto out_err_bad_srat; 188 } 189 190 if (numa_add_memblk(node, start, end) < 0) 191 goto out_err_bad_srat; 192 193 node_set(node, numa_nodes_parsed); 194 195 pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s\n", 196 node, pxm, 197 (unsigned long long) start, (unsigned long long) end - 1, 198 hotpluggable ? " hotplug" : ""); 199 200 /* Mark hotplug range in memblock. */ 201 if (hotpluggable && memblock_mark_hotplug(start, ma->length)) 202 pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", 203 (unsigned long long)start, (unsigned long long)end - 1); 204 205 return 0; 206out_err_bad_srat: 207 bad_srat(); 208out_err: 209 return -1; 210} 211 212void __init acpi_numa_arch_fixup(void) {} 213 214int __init x86_acpi_numa_init(void) 215{ 216 int ret; 217 218 ret = acpi_numa_init(); 219 if (ret < 0) 220 return ret; 221 return srat_disabled() ? -EINVAL : 0; 222} 223