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 node = setup_node(pxm); 73 if (node < 0) { 74 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 75 bad_srat(); 76 return; 77 } 78 79 apic_id = pa->apic_id; 80 if (apic_id >= MAX_LOCAL_APIC) { 81 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 82 return; 83 } 84 set_apicid_to_node(apic_id, node); 85 node_set(node, numa_nodes_parsed); 86 acpi_numa = 1; 87 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", 88 pxm, apic_id, node); 89 } 90 91 /* Callback for Proximity Domain -> LAPIC mapping */ 92 void __init 93 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) 94 { 95 int pxm, node; 96 int apic_id; 97 98 if (srat_disabled()) 99 return; 100 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { 101 bad_srat(); 102 return; 103 } 104 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) 105 return; 106 pxm = pa->proximity_domain_lo; 107 node = setup_node(pxm); 108 if (node < 0) { 109 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); 110 bad_srat(); 111 return; 112 } 113 114 if (get_uv_system_type() >= UV_X2APIC) 115 apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; 116 else 117 apic_id = pa->apic_id; 118 119 if (apic_id >= MAX_LOCAL_APIC) { 120 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); 121 return; 122 } 123 124 set_apicid_to_node(apic_id, node); 125 node_set(node, numa_nodes_parsed); 126 acpi_numa = 1; 127 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", 128 pxm, apic_id, node); 129 } 130 131 #ifdef CONFIG_MEMORY_HOTPLUG 132 static inline int save_add_info(void) {return 1;} 133 #else 134 static inline int save_add_info(void) {return 0;} 135 #endif 136 137 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ 138 void __init 139 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) 140 { 141 u64 start, end; 142 int node, pxm; 143 144 if (srat_disabled()) 145 return; 146 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { 147 bad_srat(); 148 return; 149 } 150 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) 151 return; 152 153 if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) 154 return; 155 start = ma->base_address; 156 end = start + ma->length; 157 pxm = ma->proximity_domain; 158 node = setup_node(pxm); 159 if (node < 0) { 160 printk(KERN_ERR "SRAT: Too many proximity domains.\n"); 161 bad_srat(); 162 return; 163 } 164 165 if (numa_add_memblk(node, start, end) < 0) { 166 bad_srat(); 167 return; 168 } 169 170 printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm, 171 start, end); 172 } 173 174 void __init acpi_numa_arch_fixup(void) {} 175 176 int __init x86_acpi_numa_init(void) 177 { 178 int ret; 179 180 ret = acpi_numa_init(); 181 if (ret < 0) 182 return ret; 183 return srat_disabled() ? -EINVAL : 0; 184 } 185