aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/mm
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2007-07-21 11:10:32 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-21 21:37:10 -0400
commit3484d79813707bb6045773953a809abba443dc20 (patch)
treea986c674698face8fc51132a1feeac53fa7946a2 /arch/x86_64/mm
parent3af044e0f832cfa3fcdce14dc30678b79dd36995 (diff)
x86_64: fake pxm-to-node mapping for fake numa
For NUMA emulation, our SLIT should represent the true NUMA topology of the system but our proximity domain to node ID mapping needs to reflect the emulated state. When NUMA emulation has successfully setup fake nodes on the system, a new function, acpi_fake_nodes() is called. This function determines the proximity domain (_PXM) for each true node found on the system. It then finds which emulated nodes have been allocated on this true node as determined by its starting address. The node ID to PXM mapping is changed so that each fake node ID points to the PXM of the true node that it is located on. If the machine failed to register a SLIT, then we assume there is no special requirement for emulated node affinity so we use the default LOCAL_DISTANCE, which is newly exported to this code, as our measurement if the emulated nodes appear in the same PXM. Otherwise, we use REMOTE_DISTANCE. PXM_INVAL and NID_INVAL are also exported to the ACPI header file so that we can compare node_to_pxm() results in generic code (in this case, the SRAT code). Cc: Len Brown <lenb@kernel.org> Signed-off-by: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86_64/mm')
-rw-r--r--arch/x86_64/mm/numa.c1
-rw-r--r--arch/x86_64/mm/srat.c76
2 files changed, 74 insertions, 3 deletions
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 51548947ad3b..30bf8043984d 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -484,6 +484,7 @@ out:
484 nodes[i].end >> PAGE_SHIFT); 484 nodes[i].end >> PAGE_SHIFT);
485 setup_node_bootmem(i, nodes[i].start, nodes[i].end); 485 setup_node_bootmem(i, nodes[i].start, nodes[i].end);
486 } 486 }
487 acpi_fake_nodes(nodes, num_nodes);
487 numa_init_array(); 488 numa_init_array();
488 return 0; 489 return 0;
489} 490}
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 0e0725db20b7..7ac8ff333e84 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -350,7 +350,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
350 350
351/* Sanity check to catch more bad SRATs (they are amazingly common). 351/* Sanity check to catch more bad SRATs (they are amazingly common).
352 Make sure the PXMs cover all memory. */ 352 Make sure the PXMs cover all memory. */
353static int nodes_cover_memory(void) 353static int __init nodes_cover_memory(const struct bootnode *nodes)
354{ 354{
355 int i; 355 int i;
356 unsigned long pxmram, e820ram; 356 unsigned long pxmram, e820ram;
@@ -406,7 +406,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
406 } 406 }
407 } 407 }
408 408
409 if (!nodes_cover_memory()) { 409 if (!nodes_cover_memory(nodes)) {
410 bad_srat(); 410 bad_srat();
411 return -1; 411 return -1;
412 } 412 }
@@ -440,6 +440,75 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
440 return 0; 440 return 0;
441} 441}
442 442
443#ifdef CONFIG_NUMA_EMU
444static int __init find_node_by_addr(unsigned long addr)
445{
446 int ret = NUMA_NO_NODE;
447 int i;
448
449 for_each_node_mask(i, nodes_parsed) {
450 /*
451 * Find the real node that this emulated node appears on. For
452 * the sake of simplicity, we only use a real node's starting
453 * address to determine which emulated node it appears on.
454 */
455 if (addr >= nodes[i].start && addr < nodes[i].end) {
456 ret = i;
457 break;
458 }
459 }
460 return i;
461}
462
463/*
464 * In NUMA emulation, we need to setup proximity domain (_PXM) to node ID
465 * mappings that respect the real ACPI topology but reflect our emulated
466 * environment. For each emulated node, we find which real node it appears on
467 * and create PXM to NID mappings for those fake nodes which mirror that
468 * locality. SLIT will now represent the correct distances between emulated
469 * nodes as a result of the real topology.
470 */
471void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
472{
473 int i;
474 int fake_node_to_pxm_map[MAX_NUMNODES] = {
475 [0 ... MAX_NUMNODES-1] = PXM_INVAL
476 };
477
478 printk(KERN_INFO "Faking PXM affinity for fake nodes on real "
479 "topology.\n");
480 for (i = 0; i < num_nodes; i++) {
481 int nid, pxm;
482
483 nid = find_node_by_addr(fake_nodes[i].start);
484 if (nid == NUMA_NO_NODE)
485 continue;
486 pxm = node_to_pxm(nid);
487 if (pxm == PXM_INVAL)
488 continue;
489 fake_node_to_pxm_map[i] = pxm;
490 }
491 for (i = 0; i < num_nodes; i++)
492 __acpi_map_pxm_to_node(fake_node_to_pxm_map[i], i);
493
494 nodes_clear(nodes_parsed);
495 for (i = 0; i < num_nodes; i++)
496 if (fake_nodes[i].start != fake_nodes[i].end)
497 node_set(i, nodes_parsed);
498 WARN_ON(!nodes_cover_memory(fake_nodes));
499}
500
501static int null_slit_node_compare(int a, int b)
502{
503 return node_to_pxm(a) == node_to_pxm(b);
504}
505#else
506static int null_slit_node_compare(int a, int b)
507{
508 return a == b;
509}
510#endif /* CONFIG_NUMA_EMU */
511
443void __init srat_reserve_add_area(int nodeid) 512void __init srat_reserve_add_area(int nodeid)
444{ 513{
445 if (found_add_area && nodes_add[nodeid].end) { 514 if (found_add_area && nodes_add[nodeid].end) {
@@ -464,7 +533,8 @@ int __node_distance(int a, int b)
464 int index; 533 int index;
465 534
466 if (!acpi_slit) 535 if (!acpi_slit)
467 return a == b ? LOCAL_DISTANCE : REMOTE_DISTANCE; 536 return null_slit_node_compare(a, b) ? LOCAL_DISTANCE :
537 REMOTE_DISTANCE;
468 index = acpi_slit->locality_count * node_to_pxm(a); 538 index = acpi_slit->locality_count * node_to_pxm(a);
469 return acpi_slit->entry[index + node_to_pxm(b)]; 539 return acpi_slit->entry[index + node_to_pxm(b)];
470} 540}