summaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/numa_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/numa_64.c')
-rw-r--r--arch/x86/mm/numa_64.c102
1 files changed, 40 insertions, 62 deletions
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 722039e0948..8ce61773590 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -48,10 +48,6 @@ static struct numa_meminfo numa_meminfo __initdata;
static int numa_distance_cnt;
static u8 *numa_distance;
-#ifdef CONFIG_NUMA_EMU
-static bool numa_emu_dist;
-#endif
-
/*
* Given a shift value, try to populate memnodemap[]
* Returns :
@@ -443,10 +439,6 @@ void __init numa_set_distance(int from, int to, int distance)
int __node_distance(int from, int to)
{
-#if defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA_EMU)
- if (numa_emu_dist)
- return acpi_emu_node_distance(from, to);
-#endif
if (from >= numa_distance_cnt || to >= numa_distance_cnt)
return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
return numa_distance[from * numa_distance_cnt + to];
@@ -559,56 +551,6 @@ static int __init emu_find_memblk_by_nid(int nid, const struct numa_meminfo *mi)
return -ENOENT;
}
-int __init find_node_by_addr(unsigned long addr)
-{
- const struct numa_meminfo *mi = &numa_meminfo;
- int i;
-
- for (i = 0; i < mi->nr_blks; i++) {
- /*
- * Find the real node that this emulated node appears on. For
- * the sake of simplicity, we only use a real node's starting
- * address to determine which emulated node it appears on.
- */
- if (addr >= mi->blk[i].start && addr < mi->blk[i].end)
- return mi->blk[i].nid;
- }
- return NUMA_NO_NODE;
-}
-
-static void __init fake_physnodes(int acpi, int amd,
- const struct numa_meminfo *ei)
-{
- static struct bootnode nodes[MAX_NUMNODES] __initdata;
- int i, nr_nodes = 0;
-
- for (i = 0; i < ei->nr_blks; i++) {
- int nid = ei->blk[i].nid;
-
- if (nodes[nid].start == nodes[nid].end) {
- nodes[nid].start = ei->blk[i].start;
- nodes[nid].end = ei->blk[i].end;
- nr_nodes++;
- } else {
- nodes[nid].start = min(ei->blk[i].start, nodes[nid].start);
- nodes[nid].end = max(ei->blk[i].end, nodes[nid].end);
- }
- }
-
- BUG_ON(acpi && amd);
-#ifdef CONFIG_ACPI_NUMA
- if (acpi)
- acpi_fake_nodes(nodes, nr_nodes);
-#endif
-#ifdef CONFIG_AMD_NUMA
- if (amd)
- amd_fake_nodes(nodes, nr_nodes);
-#endif
- if (!acpi && !amd)
- for (i = 0; i < nr_cpu_ids; i++)
- numa_set_node(i, 0);
-}
-
/*
* Sets up nid to range from @start to @end. The return value is -errno if
* something went wrong, 0 otherwise.
@@ -853,11 +795,13 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
* Sets up the system RAM area from start_pfn to last_pfn according to the
* numa=fake command-line option.
*/
-static bool __init numa_emulation(int acpi, int amd)
+static bool __init numa_emulation(void)
{
static struct numa_meminfo ei __initdata;
static struct numa_meminfo pi __initdata;
const u64 max_addr = max_pfn << PAGE_SHIFT;
+ int phys_dist_cnt = numa_distance_cnt;
+ u8 *phys_dist = NULL;
int i, j, ret;
memset(&ei, 0, sizeof(ei));
@@ -891,6 +835,25 @@ static bool __init numa_emulation(int acpi, int amd)
return false;
}
+ /*
+ * Copy the original distance table. It's temporary so no need to
+ * reserve it.
+ */
+ if (phys_dist_cnt) {
+ size_t size = phys_dist_cnt * sizeof(numa_distance[0]);
+ u64 phys;
+
+ phys = memblock_find_in_range(0,
+ (u64)max_pfn_mapped << PAGE_SHIFT,
+ size, PAGE_SIZE);
+ if (phys == MEMBLOCK_ERROR) {
+ pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n");
+ return false;
+ }
+ phys_dist = __va(phys);
+ memcpy(phys_dist, numa_distance, size);
+ }
+
/* commit */
numa_meminfo = ei;
@@ -913,8 +876,23 @@ static bool __init numa_emulation(int acpi, int amd)
if (emu_nid_to_phys[i] == NUMA_NO_NODE)
emu_nid_to_phys[i] = 0;
- fake_physnodes(acpi, amd, &ei);
- numa_emu_dist = true;
+ /* transform distance table */
+ numa_reset_distance();
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ for (j = 0; j < MAX_NUMNODES; j++) {
+ int physi = emu_nid_to_phys[i];
+ int physj = emu_nid_to_phys[j];
+ int dist;
+
+ if (physi >= phys_dist_cnt || physj >= phys_dist_cnt)
+ dist = physi == physj ?
+ LOCAL_DISTANCE : REMOTE_DISTANCE;
+ else
+ dist = phys_dist[physi * phys_dist_cnt + physj];
+
+ numa_set_distance(i, j, dist);
+ }
+ }
return true;
}
#endif /* CONFIG_NUMA_EMU */
@@ -970,7 +948,7 @@ void __init initmem_init(void)
* If requested, try emulation. If emulation is not used,
* build identity emu_nid_to_phys[] for numa_add_cpu()
*/
- if (!emu_cmdline || !numa_emulation(i == 0, i == 1))
+ if (!emu_cmdline || !numa_emulation())
for (j = 0; j < ARRAY_SIZE(emu_nid_to_phys); j++)
emu_nid_to_phys[j] = j;
#endif