diff options
author | Tejun Heo <tj@kernel.org> | 2011-02-16 11:11:07 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-02-16 11:11:07 -0500 |
commit | ef396ec96c1a8ffd2b0bc67f1f79c7274de02b95 (patch) | |
tree | c0c996ba7b3d60195beb4e4b65790df1a9d79419 /arch/x86/mm | |
parent | 19095548704ecd0f32fd5deba01d56430ad7a344 (diff) |
x86-64, NUMA: Factor out memblk handling into numa_{add|register}_memblk()
Factor out memblk handling from srat_64.c into two functions in
numa_64.c. This patch doesn't introduce any behavior change. The
next patch will make all init methods use these functions.
- v2: Fixed build failure on 32bit due to misplaced NR_NODE_MEMBLKS.
Reported by Ingo.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Cc: Shaohui Zheng <shaohui.zheng@intel.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/mm')
-rw-r--r-- | arch/x86/mm/numa_64.c | 109 | ||||
-rw-r--r-- | arch/x86/mm/srat_64.c | 96 |
2 files changed, 112 insertions, 93 deletions
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 82ee3083b094..a1d702d2584c 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c | |||
@@ -33,6 +33,10 @@ struct memnode memnode; | |||
33 | static unsigned long __initdata nodemap_addr; | 33 | static unsigned long __initdata nodemap_addr; |
34 | static unsigned long __initdata nodemap_size; | 34 | static unsigned long __initdata nodemap_size; |
35 | 35 | ||
36 | static int num_node_memblks __initdata; | ||
37 | static struct bootnode node_memblk_range[NR_NODE_MEMBLKS] __initdata; | ||
38 | static int memblk_nodeid[NR_NODE_MEMBLKS] __initdata; | ||
39 | |||
36 | struct bootnode numa_nodes[MAX_NUMNODES] __initdata; | 40 | struct bootnode numa_nodes[MAX_NUMNODES] __initdata; |
37 | 41 | ||
38 | /* | 42 | /* |
@@ -184,6 +188,43 @@ static void * __init early_node_mem(int nodeid, unsigned long start, | |||
184 | return NULL; | 188 | return NULL; |
185 | } | 189 | } |
186 | 190 | ||
191 | static __init int conflicting_memblks(unsigned long start, unsigned long end) | ||
192 | { | ||
193 | int i; | ||
194 | for (i = 0; i < num_node_memblks; i++) { | ||
195 | struct bootnode *nd = &node_memblk_range[i]; | ||
196 | if (nd->start == nd->end) | ||
197 | continue; | ||
198 | if (nd->end > start && nd->start < end) | ||
199 | return memblk_nodeid[i]; | ||
200 | if (nd->end == end && nd->start == start) | ||
201 | return memblk_nodeid[i]; | ||
202 | } | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | int __init numa_add_memblk(int nid, u64 start, u64 end) | ||
207 | { | ||
208 | int i; | ||
209 | |||
210 | i = conflicting_memblks(start, end); | ||
211 | if (i == nid) { | ||
212 | printk(KERN_WARNING "NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n", | ||
213 | nid, start, end, numa_nodes[i].start, numa_nodes[i].end); | ||
214 | } else if (i >= 0) { | ||
215 | printk(KERN_ERR "NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n", | ||
216 | nid, start, end, i, | ||
217 | numa_nodes[i].start, numa_nodes[i].end); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | node_memblk_range[num_node_memblks].start = start; | ||
222 | node_memblk_range[num_node_memblks].end = end; | ||
223 | memblk_nodeid[num_node_memblks] = nid; | ||
224 | num_node_memblks++; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
187 | static __init void cutoff_node(int i, unsigned long start, unsigned long end) | 228 | static __init void cutoff_node(int i, unsigned long start, unsigned long end) |
188 | { | 229 | { |
189 | struct bootnode *nd = &numa_nodes[i]; | 230 | struct bootnode *nd = &numa_nodes[i]; |
@@ -246,6 +287,71 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) | |||
246 | node_set_online(nodeid); | 287 | node_set_online(nodeid); |
247 | } | 288 | } |
248 | 289 | ||
290 | int __init numa_register_memblks(void) | ||
291 | { | ||
292 | int i; | ||
293 | |||
294 | /* | ||
295 | * Join together blocks on the same node, holes between | ||
296 | * which don't overlap with memory on other nodes. | ||
297 | */ | ||
298 | for (i = 0; i < num_node_memblks; ++i) { | ||
299 | int j, k; | ||
300 | |||
301 | for (j = i + 1; j < num_node_memblks; ++j) { | ||
302 | unsigned long start, end; | ||
303 | |||
304 | if (memblk_nodeid[i] != memblk_nodeid[j]) | ||
305 | continue; | ||
306 | start = min(node_memblk_range[i].end, | ||
307 | node_memblk_range[j].end); | ||
308 | end = max(node_memblk_range[i].start, | ||
309 | node_memblk_range[j].start); | ||
310 | for (k = 0; k < num_node_memblks; ++k) { | ||
311 | if (memblk_nodeid[i] == memblk_nodeid[k]) | ||
312 | continue; | ||
313 | if (start < node_memblk_range[k].end && | ||
314 | end > node_memblk_range[k].start) | ||
315 | break; | ||
316 | } | ||
317 | if (k < num_node_memblks) | ||
318 | continue; | ||
319 | start = min(node_memblk_range[i].start, | ||
320 | node_memblk_range[j].start); | ||
321 | end = max(node_memblk_range[i].end, | ||
322 | node_memblk_range[j].end); | ||
323 | printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n", | ||
324 | memblk_nodeid[i], | ||
325 | node_memblk_range[i].start, | ||
326 | node_memblk_range[i].end, | ||
327 | node_memblk_range[j].start, | ||
328 | node_memblk_range[j].end, | ||
329 | start, end); | ||
330 | node_memblk_range[i].start = start; | ||
331 | node_memblk_range[i].end = end; | ||
332 | k = --num_node_memblks - j; | ||
333 | memmove(memblk_nodeid + j, memblk_nodeid + j+1, | ||
334 | k * sizeof(*memblk_nodeid)); | ||
335 | memmove(node_memblk_range + j, node_memblk_range + j+1, | ||
336 | k * sizeof(*node_memblk_range)); | ||
337 | --j; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | memnode_shift = compute_hash_shift(node_memblk_range, num_node_memblks, | ||
342 | memblk_nodeid); | ||
343 | if (memnode_shift < 0) { | ||
344 | printk(KERN_ERR "NUMA: No NUMA node hash function found. Contact maintainer\n"); | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | for (i = 0; i < num_node_memblks; i++) | ||
349 | memblock_x86_register_active_regions(memblk_nodeid[i], | ||
350 | node_memblk_range[i].start >> PAGE_SHIFT, | ||
351 | node_memblk_range[i].end >> PAGE_SHIFT); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
249 | #ifdef CONFIG_NUMA_EMU | 355 | #ifdef CONFIG_NUMA_EMU |
250 | /* Numa emulation */ | 356 | /* Numa emulation */ |
251 | static struct bootnode nodes[MAX_NUMNODES] __initdata; | 357 | static struct bootnode nodes[MAX_NUMNODES] __initdata; |
@@ -653,6 +759,9 @@ void __init initmem_init(void) | |||
653 | nodes_clear(mem_nodes_parsed); | 759 | nodes_clear(mem_nodes_parsed); |
654 | nodes_clear(node_possible_map); | 760 | nodes_clear(node_possible_map); |
655 | nodes_clear(node_online_map); | 761 | nodes_clear(node_online_map); |
762 | num_node_memblks = 0; | ||
763 | memset(node_memblk_range, 0, sizeof(node_memblk_range)); | ||
764 | memset(memblk_nodeid, 0, sizeof(memblk_nodeid)); | ||
656 | memset(numa_nodes, 0, sizeof(numa_nodes)); | 765 | memset(numa_nodes, 0, sizeof(numa_nodes)); |
657 | 766 | ||
658 | if (numa_init[i]() < 0) | 767 | if (numa_init[i]() < 0) |
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c index 82b1087963a2..341b37193c76 100644 --- a/arch/x86/mm/srat_64.c +++ b/arch/x86/mm/srat_64.c | |||
@@ -30,30 +30,11 @@ static struct acpi_table_slit *acpi_slit; | |||
30 | 30 | ||
31 | static struct bootnode nodes_add[MAX_NUMNODES]; | 31 | static struct bootnode nodes_add[MAX_NUMNODES]; |
32 | 32 | ||
33 | static int num_node_memblks __initdata; | ||
34 | static struct bootnode node_memblk_range[NR_NODE_MEMBLKS] __initdata; | ||
35 | static int memblk_nodeid[NR_NODE_MEMBLKS] __initdata; | ||
36 | |||
37 | static __init int setup_node(int pxm) | 33 | static __init int setup_node(int pxm) |
38 | { | 34 | { |
39 | return acpi_map_pxm_to_node(pxm); | 35 | return acpi_map_pxm_to_node(pxm); |
40 | } | 36 | } |
41 | 37 | ||
42 | static __init int conflicting_memblks(unsigned long start, unsigned long end) | ||
43 | { | ||
44 | int i; | ||
45 | for (i = 0; i < num_node_memblks; i++) { | ||
46 | struct bootnode *nd = &node_memblk_range[i]; | ||
47 | if (nd->start == nd->end) | ||
48 | continue; | ||
49 | if (nd->end > start && nd->start < end) | ||
50 | return memblk_nodeid[i]; | ||
51 | if (nd->end == end && nd->start == start) | ||
52 | return memblk_nodeid[i]; | ||
53 | } | ||
54 | return -1; | ||
55 | } | ||
56 | |||
57 | static __init void bad_srat(void) | 38 | static __init void bad_srat(void) |
58 | { | 39 | { |
59 | int i; | 40 | int i; |
@@ -233,7 +214,6 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | |||
233 | struct bootnode *nd; | 214 | struct bootnode *nd; |
234 | unsigned long start, end; | 215 | unsigned long start, end; |
235 | int node, pxm; | 216 | int node, pxm; |
236 | int i; | ||
237 | 217 | ||
238 | if (srat_disabled()) | 218 | if (srat_disabled()) |
239 | return; | 219 | return; |
@@ -255,16 +235,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | |||
255 | bad_srat(); | 235 | bad_srat(); |
256 | return; | 236 | return; |
257 | } | 237 | } |
258 | i = conflicting_memblks(start, end); | 238 | |
259 | if (i == node) { | 239 | if (numa_add_memblk(node, start, end) < 0) { |
260 | printk(KERN_WARNING | ||
261 | "SRAT: Warning: PXM %d (%lx-%lx) overlaps with itself (%Lx-%Lx)\n", | ||
262 | pxm, start, end, numa_nodes[i].start, numa_nodes[i].end); | ||
263 | } else if (i >= 0) { | ||
264 | printk(KERN_ERR | ||
265 | "SRAT: PXM %d (%lx-%lx) overlaps with PXM %d (%Lx-%Lx)\n", | ||
266 | pxm, start, end, node_to_pxm(i), | ||
267 | numa_nodes[i].start, numa_nodes[i].end); | ||
268 | bad_srat(); | 240 | bad_srat(); |
269 | return; | 241 | return; |
270 | } | 242 | } |
@@ -285,11 +257,6 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | |||
285 | } | 257 | } |
286 | } else | 258 | } else |
287 | update_nodes_add(node, start, end); | 259 | update_nodes_add(node, start, end); |
288 | |||
289 | node_memblk_range[num_node_memblks].start = start; | ||
290 | node_memblk_range[num_node_memblks].end = end; | ||
291 | memblk_nodeid[num_node_memblks] = node; | ||
292 | num_node_memblks++; | ||
293 | } | 260 | } |
294 | 261 | ||
295 | /* Sanity check to catch more bad SRATs (they are amazingly common). | 262 | /* Sanity check to catch more bad SRATs (they are amazingly common). |
@@ -341,68 +308,11 @@ int __init acpi_scan_nodes(void) | |||
341 | if (acpi_numa <= 0) | 308 | if (acpi_numa <= 0) |
342 | return -1; | 309 | return -1; |
343 | 310 | ||
344 | /* | 311 | if (numa_register_memblks() < 0) { |
345 | * Join together blocks on the same node, holes between | ||
346 | * which don't overlap with memory on other nodes. | ||
347 | */ | ||
348 | for (i = 0; i < num_node_memblks; ++i) { | ||
349 | int j, k; | ||
350 | |||
351 | for (j = i + 1; j < num_node_memblks; ++j) { | ||
352 | unsigned long start, end; | ||
353 | |||
354 | if (memblk_nodeid[i] != memblk_nodeid[j]) | ||
355 | continue; | ||
356 | start = min(node_memblk_range[i].end, | ||
357 | node_memblk_range[j].end); | ||
358 | end = max(node_memblk_range[i].start, | ||
359 | node_memblk_range[j].start); | ||
360 | for (k = 0; k < num_node_memblks; ++k) { | ||
361 | if (memblk_nodeid[i] == memblk_nodeid[k]) | ||
362 | continue; | ||
363 | if (start < node_memblk_range[k].end && | ||
364 | end > node_memblk_range[k].start) | ||
365 | break; | ||
366 | } | ||
367 | if (k < num_node_memblks) | ||
368 | continue; | ||
369 | start = min(node_memblk_range[i].start, | ||
370 | node_memblk_range[j].start); | ||
371 | end = max(node_memblk_range[i].end, | ||
372 | node_memblk_range[j].end); | ||
373 | printk(KERN_INFO "SRAT: Node %d " | ||
374 | "[%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n", | ||
375 | memblk_nodeid[i], | ||
376 | node_memblk_range[i].start, | ||
377 | node_memblk_range[i].end, | ||
378 | node_memblk_range[j].start, | ||
379 | node_memblk_range[j].end, | ||
380 | start, end); | ||
381 | node_memblk_range[i].start = start; | ||
382 | node_memblk_range[i].end = end; | ||
383 | k = --num_node_memblks - j; | ||
384 | memmove(memblk_nodeid + j, memblk_nodeid + j+1, | ||
385 | k * sizeof(*memblk_nodeid)); | ||
386 | memmove(node_memblk_range + j, node_memblk_range + j+1, | ||
387 | k * sizeof(*node_memblk_range)); | ||
388 | --j; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | memnode_shift = compute_hash_shift(node_memblk_range, num_node_memblks, | ||
393 | memblk_nodeid); | ||
394 | if (memnode_shift < 0) { | ||
395 | printk(KERN_ERR | ||
396 | "SRAT: No NUMA node hash function found. Contact maintainer\n"); | ||
397 | bad_srat(); | 312 | bad_srat(); |
398 | return -1; | 313 | return -1; |
399 | } | 314 | } |
400 | 315 | ||
401 | for (i = 0; i < num_node_memblks; i++) | ||
402 | memblock_x86_register_active_regions(memblk_nodeid[i], | ||
403 | node_memblk_range[i].start >> PAGE_SHIFT, | ||
404 | node_memblk_range[i].end >> PAGE_SHIFT); | ||
405 | |||
406 | /* for out of order entries in SRAT */ | 316 | /* for out of order entries in SRAT */ |
407 | sort_node_map(); | 317 | sort_node_map(); |
408 | if (!nodes_cover_memory(numa_nodes)) { | 318 | if (!nodes_cover_memory(numa_nodes)) { |