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 struct bootnode nodes_add[MAX_NUMNODES];
30
setup_node(int pxm)31 static __init int setup_node(int pxm)
32 {
33 return acpi_map_pxm_to_node(pxm);
34 }
35
bad_srat(void)36 static __init void bad_srat(void)
37 {
38 printk(KERN_ERR "SRAT: SRAT not used.\n");
39 acpi_numa = -1;
40 memset(nodes_add, 0, sizeof(nodes_add));
41 }
42
srat_disabled(void)43 static __init inline int srat_disabled(void)
44 {
45 return acpi_numa < 0;
46 }
47
48 /* Callback for SLIT parsing */
acpi_numa_slit_init(struct acpi_table_slit * slit)49 void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
50 {
51 int i, j;
52
53 for (i = 0; i < slit->locality_count; i++)
54 for (j = 0; j < slit->locality_count; j++)
55 numa_set_distance(pxm_to_node(i), pxm_to_node(j),
56 slit->entry[slit->locality_count * i + j]);
57 }
58
59 /* Callback for Proximity Domain -> x2APIC mapping */
60 void __init
acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity * pa)61 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
62 {
63 int pxm, node;
64 int apic_id;
65
66 if (srat_disabled())
67 return;
68 if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
69 bad_srat();
70 return;
71 }
72 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
73 return;
74 pxm = pa->proximity_domain;
75 node = setup_node(pxm);
76 if (node < 0) {
77 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
78 bad_srat();
79 return;
80 }
81
82 apic_id = pa->apic_id;
83 if (apic_id >= MAX_LOCAL_APIC) {
84 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
85 return;
86 }
87 set_apicid_to_node(apic_id, node);
88 node_set(node, numa_nodes_parsed);
89 acpi_numa = 1;
90 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
91 pxm, apic_id, node);
92 }
93
94 /* Callback for Proximity Domain -> LAPIC mapping */
95 void __init
acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity * pa)96 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
97 {
98 int pxm, node;
99 int apic_id;
100
101 if (srat_disabled())
102 return;
103 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
104 bad_srat();
105 return;
106 }
107 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
108 return;
109 pxm = pa->proximity_domain_lo;
110 node = setup_node(pxm);
111 if (node < 0) {
112 printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
113 bad_srat();
114 return;
115 }
116
117 if (get_uv_system_type() >= UV_X2APIC)
118 apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
119 else
120 apic_id = pa->apic_id;
121
122 if (apic_id >= MAX_LOCAL_APIC) {
123 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
124 return;
125 }
126
127 set_apicid_to_node(apic_id, node);
128 node_set(node, numa_nodes_parsed);
129 acpi_numa = 1;
130 printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
131 pxm, apic_id, node);
132 }
133
134 #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
save_add_info(void)135 static inline int save_add_info(void) {return 1;}
136 #else
save_add_info(void)137 static inline int save_add_info(void) {return 0;}
138 #endif
139 /*
140 * Update nodes_add[]
141 * This code supports one contiguous hot add area per node
142 */
143 static void __init
update_nodes_add(int node,unsigned long start,unsigned long end)144 update_nodes_add(int node, unsigned long start, unsigned long end)
145 {
146 unsigned long s_pfn = start >> PAGE_SHIFT;
147 unsigned long e_pfn = end >> PAGE_SHIFT;
148 int changed = 0;
149 struct bootnode *nd = &nodes_add[node];
150
151 /* I had some trouble with strange memory hotadd regions breaking
152 the boot. Be very strict here and reject anything unexpected.
153 If you want working memory hotadd write correct SRATs.
154
155 The node size check is a basic sanity check to guard against
156 mistakes */
157 if ((signed long)(end - start) < NODE_MIN_SIZE) {
158 printk(KERN_ERR "SRAT: Hotplug area too small\n");
159 return;
160 }
161
162 /* This check might be a bit too strict, but I'm keeping it for now. */
163 if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
164 printk(KERN_ERR
165 "SRAT: Hotplug area %lu -> %lu has existing memory\n",
166 s_pfn, e_pfn);
167 return;
168 }
169
170 /* Looks good */
171
172 if (nd->start == nd->end) {
173 nd->start = start;
174 nd->end = end;
175 changed = 1;
176 } else {
177 if (nd->start == end) {
178 nd->start = start;
179 changed = 1;
180 }
181 if (nd->end == start) {
182 nd->end = end;
183 changed = 1;
184 }
185 if (!changed)
186 printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
187 }
188
189 if (changed) {
190 node_set(node, numa_nodes_parsed);
191 printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
192 nd->start, nd->end);
193 }
194 }
195
196 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
197 void __init
acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity * ma)198 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
199 {
200 unsigned long start, end;
201 int node, pxm;
202
203 if (srat_disabled())
204 return;
205 if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
206 bad_srat();
207 return;
208 }
209 if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
210 return;
211
212 if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
213 return;
214 start = ma->base_address;
215 end = start + ma->length;
216 pxm = ma->proximity_domain;
217 node = setup_node(pxm);
218 if (node < 0) {
219 printk(KERN_ERR "SRAT: Too many proximity domains.\n");
220 bad_srat();
221 return;
222 }
223
224 if (numa_add_memblk(node, start, end) < 0) {
225 bad_srat();
226 return;
227 }
228
229 printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
230 start, end);
231
232 if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)
233 update_nodes_add(node, start, end);
234 }
235
acpi_numa_arch_fixup(void)236 void __init acpi_numa_arch_fixup(void) {}
237
x86_acpi_numa_init(void)238 int __init x86_acpi_numa_init(void)
239 {
240 int ret;
241
242 ret = acpi_numa_init();
243 if (ret < 0)
244 return ret;
245 return srat_disabled() ? -EINVAL : 0;
246 }
247
248 #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
memory_add_physaddr_to_nid(u64 start)249 int memory_add_physaddr_to_nid(u64 start)
250 {
251 int i, ret = 0;
252
253 for_each_node(i)
254 if (nodes_add[i].start <= start && nodes_add[i].end > start)
255 ret = i;
256
257 return ret;
258 }
259 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
260 #endif
261