x86: Fix common misspellings
[pandora-kernel.git] / arch / x86 / mm / numa_64.c
index bd086eb..e8c00cc 100644 (file)
 #include <asm/e820.h>
 #include <asm/proto.h>
 #include <asm/dma.h>
-#include <asm/numa.h>
 #include <asm/acpi.h>
 #include <asm/amd_nb.h>
 
-struct numa_memblk {
-       u64                     start;
-       u64                     end;
-       int                     nid;
-};
-
-struct numa_meminfo {
-       int                     nr_blks;
-       struct numa_memblk      blk[NR_NODE_MEMBLKS];
-};
+#include "numa_internal.h"
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
@@ -48,10 +38,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 :
@@ -219,13 +205,32 @@ static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
        return 0;
 }
 
-static void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
+/**
+ * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo
+ * @idx: Index of memblk to remove
+ * @mi: numa_meminfo to remove memblk from
+ *
+ * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and
+ * decrementing @mi->nr_blks.
+ */
+void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
 {
        mi->nr_blks--;
        memmove(&mi->blk[idx], &mi->blk[idx + 1],
                (mi->nr_blks - idx) * sizeof(mi->blk[0]));
 }
 
+/**
+ * numa_add_memblk - Add one numa_memblk to numa_meminfo
+ * @nid: NUMA node ID of the new memblk
+ * @start: Start address of the new memblk
+ * @end: End address of the new memblk
+ *
+ * Add a new memblk to the default numa_meminfo.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
 int __init numa_add_memblk(int nid, u64 start, u64 end)
 {
        return numa_add_memblk_to(nid, start, end, &numa_meminfo);
@@ -277,7 +282,17 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
        node_set_online(nodeid);
 }
 
-static int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
+/**
+ * numa_cleanup_meminfo - Cleanup a numa_meminfo
+ * @mi: numa_meminfo to clean up
+ *
+ * Sanitize @mi by merging and removing unncessary memblks.  Also check for
+ * conflicts and clear unused memblks.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
 {
        const u64 low = 0;
        const u64 high = (u64)max_pfn << PAGE_SHIFT;
@@ -367,63 +382,85 @@ static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
                        node_set(mi->blk[i].nid, *nodemask);
 }
 
-/*
- * Reset distance table.  The current table is freed.  The next
- * numa_set_distance() call will create a new one.
+/**
+ * numa_reset_distance - Reset NUMA distance table
+ *
+ * The current table is freed.  The next numa_set_distance() call will
+ * create a new one.
  */
-static void __init numa_reset_distance(void)
+void __init numa_reset_distance(void)
 {
-       size_t size;
+       size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]);
 
-       size = numa_distance_cnt * sizeof(numa_distance[0]);
-       memblock_x86_free_range(__pa(numa_distance),
-                               __pa(numa_distance) + size);
-       numa_distance = NULL;
+       /* numa_distance could be 1LU marking allocation failure, test cnt */
+       if (numa_distance_cnt)
+               memblock_x86_free_range(__pa(numa_distance),
+                                       __pa(numa_distance) + size);
        numa_distance_cnt = 0;
+       numa_distance = NULL;   /* enable table creation */
 }
 
-/*
- * Set the distance between node @from to @to to @distance.  If distance
- * table doesn't exist, one which is large enough to accomodate all the
- * currently known nodes will be created.
- */
-void __init numa_set_distance(int from, int to, int distance)
+static int __init numa_alloc_distance(void)
 {
-       if (!numa_distance) {
-               nodemask_t nodes_parsed;
-               size_t size;
-               int i, j, cnt = 0;
-               u64 phys;
-
-               /* size the new table and allocate it */
-               nodes_parsed = numa_nodes_parsed;
-               numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
-
-               for_each_node_mask(i, nodes_parsed)
-                       cnt = i;
-               size = ++cnt * sizeof(numa_distance[0]);
-
-               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 distance table!\n");
-                       /* don't retry until explicitly reset */
-                       numa_distance = (void *)1LU;
-                       return;
-               }
-               memblock_x86_reserve_range(phys, phys + size, "NUMA DIST");
+       nodemask_t nodes_parsed;
+       size_t size;
+       int i, j, cnt = 0;
+       u64 phys;
+
+       /* size the new table and allocate it */
+       nodes_parsed = numa_nodes_parsed;
+       numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
+
+       for_each_node_mask(i, nodes_parsed)
+               cnt = i;
+       cnt++;
+       size = cnt * cnt * sizeof(numa_distance[0]);
+
+       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 distance table!\n");
+               /* don't retry until explicitly reset */
+               numa_distance = (void *)1LU;
+               return -ENOMEM;
+       }
+       memblock_x86_reserve_range(phys, phys + size, "NUMA DIST");
 
-               numa_distance = __va(phys);
-               numa_distance_cnt = cnt;
+       numa_distance = __va(phys);
+       numa_distance_cnt = cnt;
 
-               /* fill with the default distances */
-               for (i = 0; i < cnt; i++)
-                       for (j = 0; j < cnt; j++)
-                               numa_distance[i * cnt + j] = i == j ?
-                                       LOCAL_DISTANCE : REMOTE_DISTANCE;
-               printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt);
-       }
+       /* fill with the default distances */
+       for (i = 0; i < cnt; i++)
+               for (j = 0; j < cnt; j++)
+                       numa_distance[i * cnt + j] = i == j ?
+                               LOCAL_DISTANCE : REMOTE_DISTANCE;
+       printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt);
+
+       return 0;
+}
+
+/**
+ * numa_set_distance - Set NUMA distance from one NUMA to another
+ * @from: the 'from' node to set distance
+ * @to: the 'to'  node to set distance
+ * @distance: NUMA distance
+ *
+ * Set the distance from node @from to @to to @distance.  If distance table
+ * doesn't exist, one which is large enough to accommodate all the currently
+ * known nodes will be created.
+ *
+ * If such table cannot be allocated, a warning is printed and further
+ * calls are ignored until the distance table is reset with
+ * numa_reset_distance().
+ *
+ * If @from or @to is higher than the highest known node at the time of
+ * table creation or @distance doesn't make sense, the call is ignored.
+ * This is to allow simplification of specific NUMA config implementations.
+ */
+void __init numa_set_distance(int from, int to, int distance)
+{
+       if (!numa_distance && numa_alloc_distance() < 0)
+               return;
 
        if (from >= numa_distance_cnt || to >= numa_distance_cnt) {
                printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n",
@@ -443,10 +480,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];
@@ -486,7 +519,7 @@ static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
 
 static int __init numa_register_memblks(struct numa_meminfo *mi)
 {
-       int i, j, nid;
+       int i, nid;
 
        /* Account for nodes with cpus and no memory */
        node_possible_map = numa_nodes_parsed;
@@ -510,471 +543,105 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)
        if (!numa_meminfo_cover_memory(mi))
                return -EINVAL;
 
-       init_memory_mapping_high();
-
-       /*
-        * Finally register nodes.  Do it twice in case setup_node_bootmem
-        * missed one due to missing bootmem.
-        */
-       for (i = 0; i < 2; i++) {
-               for_each_node_mask(nid, node_possible_map) {
-                       u64 start = (u64)max_pfn << PAGE_SHIFT;
-                       u64 end = 0;
+       /* Finally register nodes. */
+       for_each_node_mask(nid, node_possible_map) {
+               u64 start = (u64)max_pfn << PAGE_SHIFT;
+               u64 end = 0;
 
-                       if (node_online(nid))
+               for (i = 0; i < mi->nr_blks; i++) {
+                       if (nid != mi->blk[i].nid)
                                continue;
-
-                       for (j = 0; j < mi->nr_blks; j++) {
-                               if (nid != mi->blk[j].nid)
-                                       continue;
-                               start = min(mi->blk[j].start, start);
-                               end = max(mi->blk[j].end, end);
-                       }
-
-                       if (start < end)
-                               setup_node_bootmem(nid, start, end);
-               }
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_NUMA_EMU
-/* Numa emulation */
-static int emu_nid_to_phys[MAX_NUMNODES] __cpuinitdata;
-static char *emu_cmdline __initdata;
-
-void __init numa_emu_cmdline(char *str)
-{
-       emu_cmdline = str;
-}
-
-static int __init emu_find_memblk_by_nid(int nid, const struct numa_meminfo *mi)
-{
-       int i;
-
-       for (i = 0; i < mi->nr_blks; i++)
-               if (mi->blk[i].nid == nid)
-                       return i;
-       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);
+                       start = min(mi->blk[i].start, start);
+                       end = max(mi->blk[i].end, 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.
- */
-static int __init emu_setup_memblk(struct numa_meminfo *ei,
-                                  struct numa_meminfo *pi,
-                                  int nid, int phys_blk, u64 size)
-{
-       struct numa_memblk *eb = &ei->blk[ei->nr_blks];
-       struct numa_memblk *pb = &pi->blk[phys_blk];
-
-       if (ei->nr_blks >= NR_NODE_MEMBLKS) {
-               pr_err("NUMA: Too many emulated memblks, failing emulation\n");
-               return -EINVAL;
-       }
-
-       ei->nr_blks++;
-       eb->start = pb->start;
-       eb->end = pb->start + size;
-       eb->nid = nid;
-
-       if (emu_nid_to_phys[nid] == NUMA_NO_NODE)
-               emu_nid_to_phys[nid] = pb->nid;
-
-       pb->start += size;
-       if (pb->start >= pb->end) {
-               WARN_ON_ONCE(pb->start > pb->end);
-               numa_remove_memblk_from(phys_blk, pi);
-       }
-
-       printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", nid,
-              eb->start, eb->end, (eb->end - eb->start) >> 20);
-       return 0;
-}
 
-/*
- * Sets up nr_nodes fake nodes interleaved over physical nodes ranging from addr
- * to max_addr.  The return value is the number of nodes allocated.
- */
-static int __init split_nodes_interleave(struct numa_meminfo *ei,
-                                        struct numa_meminfo *pi,
-                                        u64 addr, u64 max_addr, int nr_nodes)
-{
-       nodemask_t physnode_mask = NODE_MASK_NONE;
-       u64 size;
-       int big;
-       int nid = 0;
-       int i, ret;
-
-       if (nr_nodes <= 0)
-               return -1;
-       if (nr_nodes > MAX_NUMNODES) {
-               pr_info("numa=fake=%d too large, reducing to %d\n",
-                       nr_nodes, MAX_NUMNODES);
-               nr_nodes = MAX_NUMNODES;
+               if (start < end)
+                       setup_node_bootmem(nid, start, end);
        }
 
-       size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
-       /*
-        * Calculate the number of big nodes that can be allocated as a result
-        * of consolidating the remainder.
-        */
-       big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * nr_nodes) /
-               FAKE_NODE_MIN_SIZE;
-
-       size &= FAKE_NODE_MIN_HASH_MASK;
-       if (!size) {
-               pr_err("Not enough memory for each node.  "
-                       "NUMA emulation disabled.\n");
-               return -1;
-       }
-
-       for (i = 0; i < pi->nr_blks; i++)
-               node_set(pi->blk[i].nid, physnode_mask);
-
-       /*
-        * Continue to fill physical nodes with fake nodes until there is no
-        * memory left on any of them.
-        */
-       while (nodes_weight(physnode_mask)) {
-               for_each_node_mask(i, physnode_mask) {
-                       u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
-                       u64 start, limit, end;
-                       int phys_blk;
-
-                       phys_blk = emu_find_memblk_by_nid(i, pi);
-                       if (phys_blk < 0) {
-                               node_clear(i, physnode_mask);
-                               continue;
-                       }
-                       start = pi->blk[phys_blk].start;
-                       limit = pi->blk[phys_blk].end;
-                       end = start + size;
-
-                       if (nid < big)
-                               end += FAKE_NODE_MIN_SIZE;
-
-                       /*
-                        * Continue to add memory to this fake node if its
-                        * non-reserved memory is less than the per-node size.
-                        */
-                       while (end - start -
-                              memblock_x86_hole_size(start, end) < size) {
-                               end += FAKE_NODE_MIN_SIZE;
-                               if (end > limit) {
-                                       end = limit;
-                                       break;
-                               }
-                       }
-
-                       /*
-                        * If there won't be at least FAKE_NODE_MIN_SIZE of
-                        * non-reserved memory in ZONE_DMA32 for the next node,
-                        * this one must extend to the boundary.
-                        */
-                       if (end < dma32_end && dma32_end - end -
-                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
-                               end = dma32_end;
-
-                       /*
-                        * If there won't be enough non-reserved memory for the
-                        * next node, this one must extend to the end of the
-                        * physical node.
-                        */
-                       if (limit - end -
-                           memblock_x86_hole_size(end, limit) < size)
-                               end = limit;
-
-                       ret = emu_setup_memblk(ei, pi, nid++ % nr_nodes,
-                                              phys_blk,
-                                              min(end, limit) - start);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
        return 0;
 }
 
-/*
- * Returns the end address of a node so that there is at least `size' amount of
- * non-reserved memory or `max_addr' is reached.
- */
-static u64 __init find_end_of_node(u64 start, u64 max_addr, u64 size)
-{
-       u64 end = start + size;
-
-       while (end - start - memblock_x86_hole_size(start, end) < size) {
-               end += FAKE_NODE_MIN_SIZE;
-               if (end > max_addr) {
-                       end = max_addr;
-                       break;
-               }
-       }
-       return end;
-}
-
-/*
- * Sets up fake nodes of `size' interleaved over physical nodes ranging from
- * `addr' to `max_addr'.  The return value is the number of nodes allocated.
+/**
+ * dummy_numma_init - Fallback dummy NUMA init
+ *
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
  */
-static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
-                                             struct numa_meminfo *pi,
-                                             u64 addr, u64 max_addr, u64 size)
+static int __init dummy_numa_init(void)
 {
-       nodemask_t physnode_mask = NODE_MASK_NONE;
-       u64 min_size;
-       int nid = 0;
-       int i, ret;
-
-       if (!size)
-               return -1;
-       /*
-        * The limit on emulated nodes is MAX_NUMNODES, so the size per node is
-        * increased accordingly if the requested size is too small.  This
-        * creates a uniform distribution of node sizes across the entire
-        * machine (but not necessarily over physical nodes).
-        */
-       min_size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) /
-                                               MAX_NUMNODES;
-       min_size = max(min_size, FAKE_NODE_MIN_SIZE);
-       if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size)
-               min_size = (min_size + FAKE_NODE_MIN_SIZE) &
-                                               FAKE_NODE_MIN_HASH_MASK;
-       if (size < min_size) {
-               pr_err("Fake node size %LuMB too small, increasing to %LuMB\n",
-                       size >> 20, min_size >> 20);
-               size = min_size;
-       }
-       size &= FAKE_NODE_MIN_HASH_MASK;
-
-       for (i = 0; i < pi->nr_blks; i++)
-               node_set(pi->blk[i].nid, physnode_mask);
-
-       /*
-        * Fill physical nodes with fake nodes of size until there is no memory
-        * left on any of them.
-        */
-       while (nodes_weight(physnode_mask)) {
-               for_each_node_mask(i, physnode_mask) {
-                       u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT;
-                       u64 start, limit, end;
-                       int phys_blk;
-
-                       phys_blk = emu_find_memblk_by_nid(i, pi);
-                       if (phys_blk < 0) {
-                               node_clear(i, physnode_mask);
-                               continue;
-                       }
-                       start = pi->blk[phys_blk].start;
-                       limit = pi->blk[phys_blk].end;
+       printk(KERN_INFO "%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");
+       printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
+              0LU, max_pfn << PAGE_SHIFT);
 
-                       end = find_end_of_node(start, limit, size);
-                       /*
-                        * If there won't be at least FAKE_NODE_MIN_SIZE of
-                        * non-reserved memory in ZONE_DMA32 for the next node,
-                        * this one must extend to the boundary.
-                        */
-                       if (end < dma32_end && dma32_end - end -
-                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
-                               end = dma32_end;
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT);
 
-                       /*
-                        * If there won't be enough non-reserved memory for the
-                        * next node, this one must extend to the end of the
-                        * physical node.
-                        */
-                       if (limit - end -
-                           memblock_x86_hole_size(end, limit) < size)
-                               end = limit;
-
-                       ret = emu_setup_memblk(ei, pi, nid++ % MAX_NUMNODES,
-                                              phys_blk,
-                                              min(end, limit) - start);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
        return 0;
 }
 
-/*
- * 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 int __init numa_init(int (*init_func)(void))
 {
-       static struct numa_meminfo ei __initdata;
-       static struct numa_meminfo pi __initdata;
-       const u64 max_addr = max_pfn << PAGE_SHIFT;
-       int i, ret;
+       int i;
+       int ret;
 
-       memset(&ei, 0, sizeof(ei));
-       pi = numa_meminfo;
+       for (i = 0; i < MAX_LOCAL_APIC; i++)
+               set_apicid_to_node(i, NUMA_NO_NODE);
 
-       for (i = 0; i < MAX_NUMNODES; i++)
-               emu_nid_to_phys[i] = NUMA_NO_NODE;
-
-       /*
-        * If the numa=fake command-line contains a 'M' or 'G', it represents
-        * the fixed node size.  Otherwise, if it is just a single number N,
-        * split the system RAM into N fake nodes.
-        */
-       if (strchr(emu_cmdline, 'M') || strchr(emu_cmdline, 'G')) {
-               u64 size;
-
-               size = memparse(emu_cmdline, &emu_cmdline);
-               ret = split_nodes_size_interleave(&ei, &pi, 0, max_addr, size);
-       } else {
-               unsigned long n;
-
-               n = simple_strtoul(emu_cmdline, NULL, 0);
-               ret = split_nodes_interleave(&ei, &pi, 0, max_addr, n);
-       }
+       nodes_clear(numa_nodes_parsed);
+       nodes_clear(node_possible_map);
+       nodes_clear(node_online_map);
+       memset(&numa_meminfo, 0, sizeof(numa_meminfo));
+       remove_all_active_ranges();
+       numa_reset_distance();
 
+       ret = init_func();
        if (ret < 0)
-               return false;
-
-       if (numa_cleanup_meminfo(&ei) < 0) {
-               pr_warning("NUMA: Warning: constructed meminfo invalid, disabling emulation\n");
-               return false;
-       }
-
-       /* commit */
-       numa_meminfo = ei;
-
-       /* make sure all emulated nodes are mapped to a physical node */
-       for (i = 0; i < ARRAY_SIZE(emu_nid_to_phys); i++)
-               if (emu_nid_to_phys[i] == NUMA_NO_NODE)
-                       emu_nid_to_phys[i] = 0;
+               return ret;
+       ret = numa_cleanup_meminfo(&numa_meminfo);
+       if (ret < 0)
+               return ret;
 
-       fake_physnodes(acpi, amd, &ei);
-       numa_emu_dist = true;
-       return true;
-}
-#endif /* CONFIG_NUMA_EMU */
+       numa_emulation(&numa_meminfo, numa_distance_cnt);
 
-static int dummy_numa_init(void)
-{
-       printk(KERN_INFO "%s\n",
-              numa_off ? "NUMA turned off" : "No NUMA configuration found");
-       printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
-              0LU, max_pfn << PAGE_SHIFT);
+       ret = numa_register_memblks(&numa_meminfo);
+       if (ret < 0)
+               return ret;
 
-       node_set(0, numa_nodes_parsed);
-       numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT);
+       for (i = 0; i < nr_cpu_ids; i++) {
+               int nid = early_cpu_to_node(i);
 
+               if (nid == NUMA_NO_NODE)
+                       continue;
+               if (!node_online(nid))
+                       numa_clear_node(i);
+       }
+       numa_init_array();
        return 0;
 }
 
 void __init initmem_init(void)
 {
-       int (*numa_init[])(void) = { [2] = dummy_numa_init };
-       int i, j;
+       int ret;
 
        if (!numa_off) {
 #ifdef CONFIG_ACPI_NUMA
-               numa_init[0] = x86_acpi_numa_init;
+               ret = numa_init(x86_acpi_numa_init);
+               if (!ret)
+                       return;
 #endif
 #ifdef CONFIG_AMD_NUMA
-               numa_init[1] = amd_numa_init;
+               ret = numa_init(amd_numa_init);
+               if (!ret)
+                       return;
 #endif
        }
 
-       for (i = 0; i < ARRAY_SIZE(numa_init); i++) {
-               if (!numa_init[i])
-                       continue;
-
-               for (j = 0; j < MAX_LOCAL_APIC; j++)
-                       set_apicid_to_node(j, NUMA_NO_NODE);
-
-               nodes_clear(numa_nodes_parsed);
-               nodes_clear(node_possible_map);
-               nodes_clear(node_online_map);
-               memset(&numa_meminfo, 0, sizeof(numa_meminfo));
-               remove_all_active_ranges();
-               numa_reset_distance();
-
-               if (numa_init[i]() < 0)
-                       continue;
-
-               if (numa_cleanup_meminfo(&numa_meminfo) < 0)
-                       continue;
-#ifdef CONFIG_NUMA_EMU
-               /*
-                * 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))
-                       for (j = 0; j < ARRAY_SIZE(emu_nid_to_phys); j++)
-                               emu_nid_to_phys[j] = j;
-#endif
-               if (numa_register_memblks(&numa_meminfo) < 0)
-                       continue;
-
-               for (j = 0; j < nr_cpu_ids; j++) {
-                       int nid = early_cpu_to_node(j);
-
-                       if (nid == NUMA_NO_NODE)
-                               continue;
-                       if (!node_online(nid))
-                               numa_clear_node(j);
-               }
-               numa_init_array();
-               return;
-       }
-       BUG();
+       numa_init(dummy_numa_init);
 }
 
 unsigned long __init numa_free_all_bootmem(void)
@@ -998,83 +665,3 @@ int __cpuinit numa_cpu_node(int cpu)
                return __apicid_to_node[apicid];
        return NUMA_NO_NODE;
 }
-
-/*
- * UGLINESS AHEAD: Currently, CONFIG_NUMA_EMU is 64bit only and makes use
- * of 64bit specific data structures.  The distinction is artificial and
- * should be removed.  numa_{add|remove}_cpu() are implemented in numa.c
- * for both 32 and 64bit when CONFIG_NUMA_EMU is disabled but here when
- * enabled.
- *
- * NUMA emulation is planned to be made generic and the following and other
- * related code should be moved to numa.c.
- */
-#ifdef CONFIG_NUMA_EMU
-# ifndef CONFIG_DEBUG_PER_CPU_MAPS
-void __cpuinit numa_add_cpu(int cpu)
-{
-       int physnid, nid;
-
-       nid = numa_cpu_node(cpu);
-       if (nid == NUMA_NO_NODE)
-               nid = early_cpu_to_node(cpu);
-       BUG_ON(nid == NUMA_NO_NODE || !node_online(nid));
-
-       physnid = emu_nid_to_phys[nid];
-
-       /*
-        * Map the cpu to each emulated node that is allocated on the physical
-        * node of the cpu's apic id.
-        */
-       for_each_online_node(nid)
-               if (emu_nid_to_phys[nid] == physnid)
-                       cpumask_set_cpu(cpu, node_to_cpumask_map[nid]);
-}
-
-void __cpuinit numa_remove_cpu(int cpu)
-{
-       int i;
-
-       for_each_online_node(i)
-               cpumask_clear_cpu(cpu, node_to_cpumask_map[i]);
-}
-# else /* !CONFIG_DEBUG_PER_CPU_MAPS */
-static void __cpuinit numa_set_cpumask(int cpu, int enable)
-{
-       struct cpumask *mask;
-       int nid, physnid, i;
-
-       nid = early_cpu_to_node(cpu);
-       if (nid == NUMA_NO_NODE) {
-               /* early_cpu_to_node() already emits a warning and trace */
-               return;
-       }
-
-       physnid = emu_nid_to_phys[nid];
-
-       for_each_online_node(i) {
-               if (emu_nid_to_phys[nid] != physnid)
-                       continue;
-
-               mask = debug_cpumask_set_cpu(cpu, enable);
-               if (!mask)
-                       return;
-
-               if (enable)
-                       cpumask_set_cpu(cpu, mask);
-               else
-                       cpumask_clear_cpu(cpu, mask);
-       }
-}
-
-void __cpuinit numa_add_cpu(int cpu)
-{
-       numa_set_cpumask(cpu, 1);
-}
-
-void __cpuinit numa_remove_cpu(int cpu)
-{
-       numa_set_cpumask(cpu, 0);
-}
-# endif        /* !CONFIG_DEBUG_PER_CPU_MAPS */
-#endif /* CONFIG_NUMA_EMU */