include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / powerpc / mm / init_64.c
index ce974c8..d7fa50b 100644 (file)
@@ -5,7 +5,6 @@
  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
  *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
  *    Copyright (C) 1996 Paul Mackerras
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
  *
  *  Derived from "arch/i386/mm/init.c"
  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
@@ -20,7 +19,8 @@
  *
  */
 
-#include <linux/config.h>
+#undef DEBUG
+
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/idr.h>
 #include <linux/nodemask.h>
 #include <linux/module.h>
+#include <linux/poison.h>
+#include <linux/lmb.h>
+#include <linux/hugetlb.h>
+#include <linux/slab.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/prom.h>
-#include <asm/lmb.h>
 #include <asm/rtas.h>
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/iommu.h>
 #include <asm/abs_addr.h>
 #include <asm/vdso.h>
-#include <asm/imalloc.h>
 
+#include "mmu_decl.h"
+
+#ifdef CONFIG_PPC_STD_MMU_64
 #if PGTABLE_RANGE > USER_VSID_RANGE
 #warning Limited user VSID range means pagetable space is wasted
 #endif
 #if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
 #warning TASK_SIZE is smaller than it needs to be.
 #endif
+#endif /* CONFIG_PPC_STD_MMU_64 */
 
-unsigned long klimit = (unsigned long)_end;
-
-/* max amount of RAM to use */
-unsigned long __max_memory;
-
-/* info on what we think the IO hole is */
-unsigned long  io_hole_start;
-unsigned long  io_hole_size;
-
-/*
- * Do very early mm setup.
- */
-void __init mm_init_ppc64(void)
-{
-#ifndef CONFIG_PPC_ISERIES
-       unsigned long i;
-#endif
-
-       ppc64_boot_msg(0x100, "MM Init");
-
-       /* This is the story of the IO hole... please, keep seated,
-        * unfortunately, we are out of oxygen masks at the moment.
-        * So we need some rough way to tell where your big IO hole
-        * is. On pmac, it's between 2G and 4G, on POWER3, it's around
-        * that area as well, on POWER4 we don't have one, etc...
-        * We need that as a "hint" when sizing the TCE table on POWER3
-        * So far, the simplest way that seem work well enough for us it
-        * to just assume that the first discontinuity in our physical
-        * RAM layout is the IO hole. That may not be correct in the future
-        * (and isn't on iSeries but then we don't care ;)
-        */
-
-#ifndef CONFIG_PPC_ISERIES
-       for (i = 1; i < lmb.memory.cnt; i++) {
-               unsigned long base, prevbase, prevsize;
-
-               prevbase = lmb.memory.region[i-1].base;
-               prevsize = lmb.memory.region[i-1].size;
-               base = lmb.memory.region[i].base;
-               if (base > (prevbase + prevsize)) {
-                       io_hole_start = prevbase + prevsize;
-                       io_hole_size = base  - (prevbase + prevsize);
-                       break;
-               }
-       }
-#endif /* CONFIG_PPC_ISERIES */
-       if (io_hole_start)
-               printk("IO Hole assumed to be %lx -> %lx\n",
-                      io_hole_start, io_hole_start + io_hole_size - 1);
-
-       ppc64_boot_msg(0x100, "MM Init Done");
-}
+phys_addr_t memstart_addr = ~0;
+phys_addr_t kernstart_addr;
 
 void free_initmem(void)
 {
@@ -131,9 +87,9 @@ void free_initmem(void)
 
        addr = (unsigned long)__init_begin;
        for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
-               memset((void *)addr, 0xcc, PAGE_SIZE);
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                ClearPageReserved(virt_to_page(addr));
-               set_page_count(virt_to_page(addr), 1);
+               init_page_count(virt_to_page(addr));
                free_page(addr);
                totalram_pages++;
        }
@@ -148,79 +104,184 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
-               set_page_count(virt_to_page(start), 1);
+               init_page_count(virt_to_page(start));
                free_page(start);
                totalram_pages++;
        }
 }
 #endif
 
-static struct kcore_list kcore_vmem;
+static void pgd_ctor(void *addr)
+{
+       memset(addr, 0, PGD_TABLE_SIZE);
+}
 
-static int __init setup_kcore(void)
+static void pmd_ctor(void *addr)
 {
-       int i;
+       memset(addr, 0, PMD_TABLE_SIZE);
+}
 
-       for (i=0; i < lmb.memory.cnt; i++) {
-               unsigned long base, size;
-               struct kcore_list *kcore_mem;
+struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE];
+
+/*
+ * Create a kmem_cache() for pagetables.  This is not used for PTE
+ * pages - they're linked to struct page, come from the normal free
+ * pages pool and have a different entry size (see real_pte_t) to
+ * everything else.  Caches created by this function are used for all
+ * the higher level pagetables, and for hugepage pagetables.
+ */
+void pgtable_cache_add(unsigned shift, void (*ctor)(void *))
+{
+       char *name;
+       unsigned long table_size = sizeof(void *) << shift;
+       unsigned long align = table_size;
 
-               base = lmb.memory.region[i].base;
-               size = lmb.memory.region[i].size;
+       /* 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.
+        *
+        * 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;
 
-               /* GFP_ATOMIC to avoid might_sleep warnings during boot */
-               kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC);
-               if (!kcore_mem)
-                       panic("mem_init: kmalloc failed\n");
+       /* It would be nice if this was a BUILD_BUG_ON(), but at the
+        * moment, gcc doesn't seem to recognize is_power_of_2 as a
+        * constant expression, so so much for that. */
+       BUG_ON(!is_power_of_2(minalign));
+       BUG_ON((shift < 1) || (shift > MAX_PGTABLE_INDEX_SIZE));
 
-               kclist_add(kcore_mem, __va(base), size);
-       }
+       if (PGT_CACHE(shift))
+               return; /* Already have a cache of this size */
 
-       kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
+       align = max_t(unsigned long, align, minalign);
+       name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift);
+       new = kmem_cache_create(name, table_size, align, 0, ctor);
+       PGT_CACHE(shift) = new;
 
-       return 0;
+       pr_debug("Allocated pgtable cache for order %d\n", shift);
 }
-module_init(setup_kcore);
 
-static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)
+
+void pgtable_cache_init(void)
 {
-       memset(addr, 0, kmem_cache_size(cache));
+       pgtable_cache_add(PGD_INDEX_SIZE, pgd_ctor);
+       pgtable_cache_add(PMD_INDEX_SIZE, pmd_ctor);
+       if (!PGT_CACHE(PGD_INDEX_SIZE) || !PGT_CACHE(PMD_INDEX_SIZE))
+               panic("Couldn't allocate pgtable caches");
+
+       /* In all current configs, when the PUD index exists it's the
+        * same size as either the pgd or pmd index.  Verify that the
+        * initialization above has also created a PUD cache.  This
+        * will need re-examiniation if we add new possibilities for
+        * the pagetable layout. */
+       BUG_ON(PUD_INDEX_SIZE && !PGT_CACHE(PUD_INDEX_SIZE));
 }
 
-#ifdef CONFIG_PPC_64K_PAGES
-static const int pgtable_cache_size[2] = {
-       PTE_TABLE_SIZE, PGD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-       "pte_pmd_cache", "pgd_cache",
-};
-#else
-static const int pgtable_cache_size[2] = {
-       PTE_TABLE_SIZE, PMD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-       "pgd_pte_cache", "pud_pmd_cache",
-};
-#endif /* CONFIG_PPC_64K_PAGES */
-
-kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)];
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+/*
+ * Given an address within the vmemmap, determine the pfn of the page that
+ * represents the start of the section it is within.  Note that we have to
+ * do this by hand as the proffered address may not be correctly aligned.
+ * Subtraction of non-aligned pointers produces undefined results.
+ */
+static unsigned long __meminit vmemmap_section_start(unsigned long page)
+{
+       unsigned long offset = page - ((unsigned long)(vmemmap));
 
-void pgtable_cache_init(void)
+       /* Return the pfn of the start of the section. */
+       return (offset / sizeof(struct page)) & PAGE_SECTION_MASK;
+}
+
+/*
+ * Check if this vmemmap page is already initialised.  If any section
+ * which overlaps this vmemmap page is initialised then this page is
+ * initialised already.
+ */
+static int __meminit vmemmap_populated(unsigned long start, int page_size)
+{
+       unsigned long end = start + page_size;
+
+       for (; start < end; start += (PAGES_PER_SECTION * sizeof(struct page)))
+               if (pfn_valid(vmemmap_section_start(start)))
+                       return 1;
+
+       return 0;
+}
+
+/* On hash-based CPUs, the vmemmap is bolted in the hash table.
+ *
+ * On Book3E CPUs, the vmemmap is currently mapped in the top half of
+ * the vmalloc space using normal page tables, though the size of
+ * pages encoded in the PTEs can be different
+ */
+
+#ifdef CONFIG_PPC_BOOK3E
+static void __meminit vmemmap_create_mapping(unsigned long start,
+                                            unsigned long page_size,
+                                            unsigned long phys)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) {
-               int size = pgtable_cache_size[i];
-               const char *name = pgtable_cache_name[i];
-
-               pgtable_cache[i] = kmem_cache_create(name,
-                                                    size, size,
-                                                    SLAB_HWCACHE_ALIGN |
-                                                    SLAB_MUST_HWCACHE_ALIGN,
-                                                    zero_ctor,
-                                                    NULL);
-               if (! pgtable_cache[i])
-                       panic("pgtable_cache_init(): could not create %s!\n",
-                             name);
+       /* Create a PTE encoding without page size */
+       unsigned long i, flags = _PAGE_PRESENT | _PAGE_ACCESSED |
+               _PAGE_KERNEL_RW;
+
+       /* PTEs only contain page size encodings up to 32M */
+       BUG_ON(mmu_psize_defs[mmu_vmemmap_psize].enc > 0xf);
+
+       /* Encode the size in the PTE */
+       flags |= mmu_psize_defs[mmu_vmemmap_psize].enc << 8;
+
+       /* For each PTE for that area, map things. Note that we don't
+        * increment phys because all PTEs are of the large size and
+        * thus must have the low bits clear
+        */
+       for (i = 0; i < page_size; i += PAGE_SIZE)
+               BUG_ON(map_kernel_page(start + i, phys, flags));
+}
+#else /* CONFIG_PPC_BOOK3E */
+static void __meminit vmemmap_create_mapping(unsigned long start,
+                                            unsigned long page_size,
+                                            unsigned long phys)
+{
+       int  mapped = htab_bolt_mapping(start, start + page_size, phys,
+                                       PAGE_KERNEL, mmu_vmemmap_psize,
+                                       mmu_kernel_ssize);
+       BUG_ON(mapped < 0);
+}
+#endif /* CONFIG_PPC_BOOK3E */
+
+int __meminit vmemmap_populate(struct page *start_page,
+                              unsigned long nr_pages, int node)
+{
+       unsigned long start = (unsigned long)start_page;
+       unsigned long end = (unsigned long)(start_page + nr_pages);
+       unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
+
+       /* Align to the page size of the linear mapping. */
+       start = _ALIGN_DOWN(start, page_size);
+
+       pr_debug("vmemmap_populate page %p, %ld pages, node %d\n",
+                start_page, nr_pages, node);
+       pr_debug(" -> map %lx..%lx\n", start, end);
+
+       for (; start < end; start += page_size) {
+               void *p;
+
+               if (vmemmap_populated(start, page_size))
+                       continue;
+
+               p = vmemmap_alloc_block(page_size, node);
+               if (!p)
+                       return -ENOMEM;
+
+               pr_debug("      * %016lx..%016lx allocated at %p\n",
+                        start, start + page_size, p);
+
+               vmemmap_create_mapping(start, page_size, __pa(p));
        }
+
+       return 0;
 }
+#endif /* CONFIG_SPARSEMEM_VMEMMAP */