[ACPI] merge 3549 4320 4485 4588 4980 5483 5651 acpica asus fops pnpacpi branches...
[pandora-kernel.git] / arch / x86_64 / mm / numa.c
index a828a01..6ef9f9a 100644 (file)
@@ -46,13 +46,15 @@ int numa_off __initdata;
  * 0 if memnodmap[] too small (of shift too small)
  * -1 if node overlap or lost ram (shift too big)
  */
-static int __init populate_memnodemap(
-       const struct node *nodes, int numnodes, int shift)
+static int __init
+populate_memnodemap(const struct node *nodes, int numnodes, int shift)
 {
        int i; 
        int res = -1;
        unsigned long addr, end;
 
+       if (shift >= 64)
+               return -1;
        memset(memnodemap, 0xff, sizeof(memnodemap));
        for (i = 0; i < numnodes; i++) {
                addr = nodes[i].start;
@@ -65,7 +67,7 @@ static int __init populate_memnodemap(
                        if (memnodemap[addr >> shift] != 0xff)
                                return -1;
                        memnodemap[addr >> shift] = i;
-                       addr += (1 << shift);
+                       addr += (1UL << shift);
                } while (addr < end);
                res = 1;
        } 
@@ -79,7 +81,7 @@ int __init compute_hash_shift(struct node *nodes, int numnodes)
        while (populate_memnodemap(nodes, numnodes, shift + 1) >= 0)
                shift++;
 
-       printk(KERN_DEBUG "Using %d for the hash shift.\n",
+       printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n",
                shift);
 
        if (populate_memnodemap(nodes, numnodes, shift) != 1) {
@@ -108,7 +110,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
 
        start = round_up(start, ZONE_ALIGN); 
 
-       printk("Bootmem setup node %d %016lx-%016lx\n", nodeid, start, end);
+       printk(KERN_INFO "Bootmem setup node %d %016lx-%016lx\n", nodeid, start, end);
 
        start_pfn = start >> PAGE_SHIFT;
        end_pfn = end >> PAGE_SHIFT;
@@ -154,7 +156,7 @@ void __init setup_node_zones(int nodeid)
        start_pfn = node_start_pfn(nodeid);
        end_pfn = node_end_pfn(nodeid);
 
-       Dprintk(KERN_INFO "setting up node %d %lx-%lx\n",
+       Dprintk(KERN_INFO "Setting up node %d %lx-%lx\n",
                nodeid, start_pfn, end_pfn);
 
        size_zones(zones, holes, start_pfn, end_pfn);
@@ -198,7 +200,7 @@ static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
                while ((x << 1) < sz)
                        x <<= 1;
                if (x < sz/2)
-                       printk("Numa emulation unbalanced. Complain to maintainer\n");
+                       printk(KERN_ERR "Numa emulation unbalanced. Complain to maintainer\n");
                sz = x;
        }
 
@@ -270,7 +272,7 @@ __cpuinit void numa_add_cpu(int cpu)
 
 void __cpuinit numa_set_node(int cpu, int node)
 {
-       cpu_pda[cpu].nodenumber = node;
+       cpu_pda(cpu)->nodenumber = node;
        cpu_to_node[cpu] = node;
 }
 
@@ -328,8 +330,69 @@ __init int numa_setup(char *opt)
        return 1;
 } 
 
+/*
+ * Setup early cpu_to_node.
+ *
+ * Populate cpu_to_node[] only if x86_cpu_to_apicid[],
+ * and apicid_to_node[] tables have valid entries for a CPU.
+ * This means we skip cpu_to_node[] initialisation for NUMA
+ * emulation and faking node case (when running a kernel compiled
+ * for NUMA on a non NUMA box), which is OK as cpu_to_node[]
+ * is already initialized in a round robin manner at numa_init_array,
+ * prior to this call, and this initialization is good enough
+ * for the fake NUMA cases.
+ */
+void __init init_cpu_to_node(void)
+{
+       int i;
+       for (i = 0; i < NR_CPUS; i++) {
+               u8 apicid = x86_cpu_to_apicid[i];
+               if (apicid == BAD_APICID)
+                       continue;
+               if (apicid_to_node[apicid] == NUMA_NO_NODE)
+                       continue;
+               cpu_to_node[i] = apicid_to_node[apicid];
+       }
+}
+
 EXPORT_SYMBOL(cpu_to_node);
 EXPORT_SYMBOL(node_to_cpumask);
 EXPORT_SYMBOL(memnode_shift);
 EXPORT_SYMBOL(memnodemap);
 EXPORT_SYMBOL(node_data);
+
+#ifdef CONFIG_DISCONTIGMEM
+/*
+ * Functions to convert PFNs from/to per node page addresses.
+ * These are out of line because they are quite big.
+ * They could be all tuned by pre caching more state.
+ * Should do that.
+ */
+
+/* Requires pfn_valid(pfn) to be true */
+struct page *pfn_to_page(unsigned long pfn)
+{
+       int nid = phys_to_nid(((unsigned long)(pfn)) << PAGE_SHIFT);
+       return (pfn - node_start_pfn(nid)) + NODE_DATA(nid)->node_mem_map;
+}
+EXPORT_SYMBOL(pfn_to_page);
+
+unsigned long page_to_pfn(struct page *page)
+{
+       return (long)(((page) - page_zone(page)->zone_mem_map) +
+                     page_zone(page)->zone_start_pfn);
+}
+EXPORT_SYMBOL(page_to_pfn);
+
+int pfn_valid(unsigned long pfn)
+{
+       unsigned nid;
+       if (pfn >= num_physpages)
+               return 0;
+       nid = pfn_to_nid(pfn);
+       if (nid == 0xff)
+               return 0;
+       return pfn >= node_start_pfn(nid) && (pfn) < node_end_pfn(nid);
+}
+EXPORT_SYMBOL(pfn_valid);
+#endif