powerpc/mm: Add support for SPARSEMEM_VMEMMAP on 64-bit Book3E
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 23 Jul 2009 23:15:58 +0000 (23:15 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 20 Aug 2009 00:25:10 +0000 (10:25 +1000)
The base TLB support didn't include support for SPARSEMEM_VMEMMAP, though
we did carve out some virtual space for it, the necessary support code
wasn't there. This implements it by using 16M pages for now, though the
page size could easily be changed at runtime if necessary.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mmu_decl.h
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/tlb_nohash.c

index 6ddbe48d07fac6c0b0065405f33a3bb45b628136..d74580469361569040c37e788e2351ba9a9a859e 100644 (file)
@@ -196,6 +196,7 @@ extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
 #endif
 
 extern int mmu_linear_psize;
+extern int mmu_vmemmap_psize;
 
 #endif /* !__ASSEMBLY__ */
 
index 7254c5a3187c8634e4eba600b6c2a85e6c85cae9..200ec2dfa034adbc971c2992b5f4153cc6eb36cb 100644 (file)
@@ -46,6 +46,7 @@
 /*
  * The vmalloc space starts at the beginning of that region, and
  * occupies half of it on hash CPUs and a quarter of it on Book3E
+ * (we keep a quarter for the virtual memmap)
  */
 #define VMALLOC_START  KERN_VIRT_START
 #ifdef CONFIG_PPC_BOOK3E
@@ -83,7 +84,7 @@
 
 #define VMALLOC_REGION_ID      (REGION_ID(VMALLOC_START))
 #define KERNEL_REGION_ID       (REGION_ID(PAGE_OFFSET))
-#define VMEMMAP_REGION_ID      (0xfUL)
+#define VMEMMAP_REGION_ID      (0xfUL) /* Server only */
 #define USER_REGION_ID         (0UL)
 
 /*
index 68a821add28df21c09c2716cc2cb8ef5c77dc796..31582329cd6778e0f3dc0b058635ab4015c8d6ad 100644 (file)
@@ -205,6 +205,47 @@ static int __meminit vmemmap_populated(unsigned long start, int page_size)
        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)
+{
+       /* 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)
 {
@@ -215,8 +256,11 @@ int __meminit vmemmap_populate(struct page *start_page,
        /* 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) {
-               int mapped;
                void *p;
 
                if (vmemmap_populated(start, page_size))
@@ -226,13 +270,10 @@ int __meminit vmemmap_populate(struct page *start_page,
                if (!p)
                        return -ENOMEM;
 
-               pr_debug("vmemmap %08lx allocated at %p, physical %08lx.\n",
-                       start, p, __pa(p));
+               pr_debug("      * %016lx..%016lx allocated at %p\n",
+                        start, start + page_size, p);
 
-               mapped = htab_bolt_mapping(start, start + page_size, __pa(p),
-                                          pgprot_val(PAGE_KERNEL),
-                                          mmu_vmemmap_psize, mmu_kernel_ssize);
-               BUG_ON(mapped < 0);
+               vmemmap_create_mapping(start, page_size, __pa(p));
        }
 
        return 0;
index 5961c6b739dd7ffb6d900b4d16810570ca87a324..d2e5321d5ea6aba3a4d5827ca6f7fc2d7fe61c6a 100644 (file)
@@ -121,7 +121,12 @@ extern unsigned int rtas_data, rtas_size;
 struct hash_pte;
 extern struct hash_pte *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
-#endif
+
+#endif /* CONFIG_PPC32 */
+
+#ifdef CONFIG_PPC64
+extern int map_kernel_page(unsigned long ea, unsigned long pa, int flags);
+#endif /* CONFIG_PPC64 */
 
 extern unsigned long ioremap_bot;
 extern unsigned long __max_low_memory;
index 93ed1a3c87295548fb346864c7a51b50b0d70ef4..853d5565eed52b88deb8d37b2379d12fe8d6d6bb 100644 (file)
@@ -79,7 +79,7 @@ static void *early_alloc_pgtable(unsigned long size)
  * map_kernel_page adds an entry to the ioremap page table
  * and adds an entry to the HPT, possibly bolting it
  */
-static int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
+int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
 {
        pgd_t *pgdp;
        pud_t *pudp;
index d16100c9416ac3d647c4ec72fada972a0ec411a1..2fbc680c2c7147f8ca2800d383c00a4500cb0b69 100644 (file)
@@ -93,6 +93,7 @@ static inline int mmu_get_tsize(int psize)
 
 int mmu_linear_psize;          /* Page size used for the linear mapping */
 int mmu_pte_psize;             /* Page size used for PTE pages */
+int mmu_vmemmap_psize;         /* Page size used for the virtual mem map */
 int book3e_htw_enabled;                /* Is HW tablewalk enabled ? */
 unsigned long linear_map_top;  /* Top of linear mapping */
 
@@ -356,10 +357,18 @@ static void __early_init_mmu(int boot_cpu)
        unsigned int mas4;
 
        /* XXX This will have to be decided at runtime, but right
-        * now our boot and TLB miss code hard wires it
+        * now our boot and TLB miss code hard wires it. Ideally
+        * we should find out a suitable page size and patch the
+        * TLB miss code (either that or use the PACA to store
+        * the value we want)
         */
        mmu_linear_psize = MMU_PAGE_1G;
 
+       /* XXX This should be decided at runtime based on supported
+        * page sizes in the TLB, but for now let's assume 16M is
+        * always there and a good fit (which it probably is)
+        */
+       mmu_vmemmap_psize = MMU_PAGE_16M;
 
        /* Check if HW tablewalk is present, and if yes, enable it by:
         *