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 27 int acpi_numa __initdata; 28 29 static __init int setup_node(int pxm) 30 { 31 return acpi_map_pxm_to_node(pxm); 32 } 33 34 static __init void bad_srat(void) 35 { 36 printk(KERN_ERR "SRAT: SRAT not used.\n"); 37 acpi_numa = -1; 38 } 39 40 static __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 */ 50 void __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 if (pxm_to_node(i) == NUMA_NO_NODE) 56 continue; 57 for (j = 0; j < slit->locality_count; j++) { 58 if (pxm_to_node(j) == NUMA_NO_NODE) 59 continue; 60 numa_set_distance(pxm_to_node(i), pxm_to_node(j), 61 slit->entry[slit->locality_count * i + j]); 62 } 63 } 64 } 65 66 /* Callback for Proximity Domain -> x2APIC mapping */ 67 void __init 68 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) 69 { 70 int pxm, node; 71 int apic_id; 72 73 if (srat_disabled()) 74 return; 75 if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { 76 bad_srat(); 77 return; 78 } 79 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 80 return; 81 pxm = pa->proximity_domain; 82 apic_id = pa->apic_id; 83 if (!apic->apic_id_valid(apic_id)) { 84 printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n", 85 pxm, apic_id); 86 return; 87 } 88 node = setup_node(pxm); 89 if (node < 0) { 90 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 91 bad_srat(); 92 return; 93 } 94 95 if (apic_id >= MAX_LOCAL_APIC) { 96 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 97 return; 98 } 99 set_apicid_to_node(apic_id, node); 100 node_set(node, numa_nodes_parsed); 101 acpi_numa = 1; 102 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", 103 pxm, apic_id, node); 104 } 105 106 /* Callback for Proximity Domain -> LAPIC mapping */ 107 void __init 108 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) 109 { 110 int pxm, node; 111 int apic_id; 112 113 if (srat_disabled()) 114 return; 115 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { 116 bad_srat(); 117 return; 118 } 119 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 120 return; 121 pxm = pa->proximity_domain_lo; 122 if (acpi_srat_revision >= 2) 123 pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; 124 node = setup_node(pxm); 125 if (node < 0) { 126 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 127 bad_srat(); 128 return; 129 } 130 131 if (get_uv_system_type() >= UV_X2APIC) 132 apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; 133 else 134 apic_id = pa->apic_id; 135 136 if (apic_id >= MAX_LOCAL_APIC) { 137 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 138 return; 139 } 140 141 set_apicid_to_node(apic_id, node); 142 node_set(node, numa_nodes_parsed); 143 acpi_numa = 1; 144 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", 145 pxm, apic_id, node); 146 } 147 148 #ifdef CONFIG_MEMORY_HOTPLUG 149 static inline int save_add_info(void) {return 1;} 150 #else 151 static inline int save_add_info(void) {return 0;} 152 #endif 153 154 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ 155 int __init 156 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) 157 { 158 u64 start, end; 159 u32 hotpluggable; 160 int node, pxm; 161 162 if (srat_disabled()) 163 goto out_err; 164 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) 165 goto out_err_bad_srat; 166 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) 167 goto out_err; 168 hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; 169 if (hotpluggable && !save_add_info()) 170 goto out_err; 171 172 start = ma->base_address; 173 end = start + ma->length; 174 pxm = ma->proximity_domain; 175 if (acpi_srat_revision <= 1) 176 pxm &= 0xff; 177 178 node = setup_node(pxm); 179 if (node < 0) { 180 printk(KERN_ERR "SRAT: Too many proximity domains.\n"); 181 goto out_err_bad_srat; 182 } 183 184 if (numa_add_memblk(node, start, end) < 0) 185 goto out_err_bad_srat; 186 187 node_set(node, numa_nodes_parsed); 188 189 pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s\n", 190 node, pxm, 191 (unsigned long long) start, (unsigned long long) end - 1, 192 hotpluggable ? " hotplug" : ""); 193 194 /* Mark hotplug range in memblock. */ 195 if (hotpluggable && memblock_mark_hotplug(start, ma->length)) 196 pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", 197 (unsigned long long)start, (unsigned long long)end - 1); 198 199 return 0; 200 out_err_bad_srat: 201 bad_srat(); 202 out_err: 203 return -1; 204 } 205 206 void __init acpi_numa_arch_fixup(void) {} 207 208 int __init x86_acpi_numa_init(void) 209 { 210 int ret; 211 212 ret = acpi_numa_init(); 213 if (ret < 0) 214 return ret; 215 return srat_disabled() ? -EINVAL : 0; 216 } 217