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 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 */ 73 void __init 74 acpi_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 */ 113 void __init 114 acpi_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 155 static inline int save_add_info(void) {return 1;} 156 #else 157 static inline int save_add_info(void) {return 0;} 158 #endif 159 160 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ 161 int __init 162 acpi_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%s\n", 196 node, pxm, 197 (unsigned long long) start, (unsigned long long) end - 1, 198 hotpluggable ? " hotplug" : "", 199 ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : ""); 200 201 /* Mark hotplug range in memblock. */ 202 if (hotpluggable && memblock_mark_hotplug(start, ma->length)) 203 pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", 204 (unsigned long long)start, (unsigned long long)end - 1); 205 206 return 0; 207 out_err_bad_srat: 208 bad_srat(); 209 out_err: 210 return -1; 211 } 212 213 void __init acpi_numa_arch_fixup(void) {} 214 215 int __init x86_acpi_numa_init(void) 216 { 217 int ret; 218 219 ret = acpi_numa_init(); 220 if (ret < 0) 221 return ret; 222 return srat_disabled() ? -EINVAL : 0; 223 } 224