Merge commit 'v2.6.36-rc3' into x86/memblock
[linux-3.10.git] / arch / powerpc / mm / init_64.c
index 82ac61d..6374b21 100644 (file)
@@ -40,7 +40,9 @@
 #include <linux/nodemask.h>
 #include <linux/module.h>
 #include <linux/poison.h>
-#include <linux/lmb.h>
+#include <linux/memblock.h>
+#include <linux/hugetlb.h>
+#include <linux/slab.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
@@ -77,7 +79,9 @@
 #endif /* CONFIG_PPC_STD_MMU_64 */
 
 phys_addr_t memstart_addr = ~0;
+EXPORT_SYMBOL_GPL(memstart_addr);
 phys_addr_t kernstart_addr;
+EXPORT_SYMBOL_GPL(kernstart_addr);
 
 void free_initmem(void)
 {
@@ -136,8 +140,13 @@ void pgtable_cache_add(unsigned shift, void (*ctor)(void *))
 
        /* When batching pgtable pointers for RCU freeing, we store
         * the index size in the low bits.  Table alignment must be
-        * big enough to fit it */
-       unsigned long minalign = MAX_PGTABLE_INDEX_SIZE + 1;
+        * big enough to fit it.
+        *
+        * Likewise, hugeapge pagetable pointers contain a (different)
+        * shift value in the low bits.  All tables must be aligned so
+        * as to leave enough 0 bits in the address to contain it. */
+       unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1,
+                                    HUGEPD_SHIFT_MASK + 1);
        struct kmem_cache *new;
 
        /* It would be nice if this was a BUILD_BUG_ON(), but at the
@@ -245,6 +254,47 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
 }
 #endif /* CONFIG_PPC_BOOK3E */
 
+struct vmemmap_backing *vmemmap_list;
+
+static __meminit struct vmemmap_backing * vmemmap_list_alloc(int node)
+{
+       static struct vmemmap_backing *next;
+       static int num_left;
+
+       /* allocate a page when required and hand out chunks */
+       if (!next || !num_left) {
+               next = vmemmap_alloc_block(PAGE_SIZE, node);
+               if (unlikely(!next)) {
+                       WARN_ON(1);
+                       return NULL;
+               }
+               num_left = PAGE_SIZE / sizeof(struct vmemmap_backing);
+       }
+
+       num_left--;
+
+       return next++;
+}
+
+static __meminit void vmemmap_list_populate(unsigned long phys,
+                                           unsigned long start,
+                                           int node)
+{
+       struct vmemmap_backing *vmem_back;
+
+       vmem_back = vmemmap_list_alloc(node);
+       if (unlikely(!vmem_back)) {
+               WARN_ON(1);
+               return;
+       }
+
+       vmem_back->phys = phys;
+       vmem_back->virt_addr = start;
+       vmem_back->list = vmemmap_list;
+
+       vmemmap_list = vmem_back;
+}
+
 int __meminit vmemmap_populate(struct page *start_page,
                               unsigned long nr_pages, int node)
 {
@@ -269,6 +319,8 @@ int __meminit vmemmap_populate(struct page *start_page,
                if (!p)
                        return -ENOMEM;
 
+               vmemmap_list_populate(__pa(p), start, node);
+
                pr_debug("      * %016lx..%016lx allocated at %p\n",
                         start, start + page_size, p);
 
@@ -278,3 +330,4 @@ int __meminit vmemmap_populate(struct page *start_page,
        return 0;
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
+