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 /* Callback for SLIT parsing */ 46 void __init acpi_numa_slit_init(struct acpi_table_slit *slit) 47 { 48 int i, j; 49 50 for (i = 0; i < slit->locality_count; i++) 51 for (j = 0; j < slit->locality_count; j++) 52 numa_set_distance(pxm_to_node(i), pxm_to_node(j), 53 slit->entry[slit->locality_count * i + j]); 54 } 55 56 /* Callback for Proximity Domain -> x2APIC mapping */ 57 void __init 58 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) 59 { 60 int pxm, node; 61 int apic_id; 62 63 if (srat_disabled()) 64 return; 65 if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { 66 bad_srat(); 67 return; 68 } 69 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 70 return; 71 pxm = pa->proximity_domain; 72 apic_id = pa->apic_id; 73 if (!cpu_has_x2apic && (apic_id >= 0xff)) { 74 printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n", 75 pxm, apic_id); 76 return; 77 } 78 node = setup_node(pxm); 79 if (node < 0) { 80 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 81 bad_srat(); 82 return; 83 } 84 85 if (apic_id >= MAX_LOCAL_APIC) { 86 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 87 return; 88 } 89 set_apicid_to_node(apic_id, node); 90 node_set(node, numa_nodes_parsed); 91 acpi_numa = 1; 92 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", 93 pxm, apic_id, node); 94 } 95 96 /* Callback for Proximity Domain -> LAPIC mapping */ 97 void __init 98 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) 99 { 100 int pxm, node; 101 int apic_id; 102 103 if (srat_disabled()) 104 return; 105 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { 106 bad_srat(); 107 return; 108 } 109 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 110 return; 111 pxm = pa->proximity_domain_lo; 112 if (acpi_srat_revision >= 2) 113 pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; 114 node = setup_node(pxm); 115 if (node < 0) { 116 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 117 bad_srat(); 118 return; 119 } 120 121 if (get_uv_system_type() >= UV_X2APIC) 122 apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; 123 else 124 apic_id = pa->apic_id; 125 126 if (apic_id >= MAX_LOCAL_APIC) { 127 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 128 return; 129 } 130 131 set_apicid_to_node(apic_id, node); 132 node_set(node, numa_nodes_parsed); 133 acpi_numa = 1; 134 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", 135 pxm, apic_id, node); 136 } 137 138 #ifdef CONFIG_MEMORY_HOTPLUG 139 static inline int save_add_info(void) {return 1;} 140 #else 141 static inline int save_add_info(void) {return 0;} 142 #endif 143 144 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ 145 void __init 146 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) 147 { 148 u64 start, end; 149 int node, pxm; 150 151 if (srat_disabled()) 152 return; 153 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { 154 bad_srat(); 155 return; 156 } 157 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) 158 return; 159 160 if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) 161 return; 162 start = ma->base_address; 163 end = start + ma->length; 164 pxm = ma->proximity_domain; 165 if (acpi_srat_revision <= 1) 166 pxm &= 0xff; 167 node = setup_node(pxm); 168 if (node < 0) { 169 printk(KERN_ERR "SRAT: Too many proximity domains.\n"); 170 bad_srat(); 171 return; 172 } 173 174 if (numa_add_memblk(node, start, end) < 0) { 175 bad_srat(); 176 return; 177 } 178 179 printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm, 180 start, end); 181 } 182 183 void __init acpi_numa_arch_fixup(void) {} 184 185 int __init x86_acpi_numa_init(void) 186 { 187 int ret; 188 189 ret = acpi_numa_init(); 190 if (ret < 0) 191 return ret; 192 return srat_disabled() ? -EINVAL : 0; 193 } 194