--- v5
+++ v1
@@ -1,107 +1,205 @@
-This patch move pgtable_t into platform headers.
-
-It gets rid of the CONFIG_PPC_64K_PAGES case for PPC64
-as nohash/64 doesn't support CONFIG_PPC_64K_PAGES.
+DO NOT APPLY THAT ONE, IT BUGS. But comments are welcome.
+
+
+In 16k pages mode, the 8xx still need only 4k for the page table.
+
+This patch makes use of the pte_fragment functions in order
+to avoid wasting memory space
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
- arch/powerpc/include/asm/book3s/32/mmu-hash.h | 2 ++
- arch/powerpc/include/asm/book3s/64/mmu.h | 9 +++++++++
- arch/powerpc/include/asm/nohash/32/mmu.h | 4 ++++
- arch/powerpc/include/asm/nohash/64/mmu.h | 4 ++++
- arch/powerpc/include/asm/page.h | 14 --------------
- 5 files changed, 19 insertions(+), 14 deletions(-)
-
-diff --git a/arch/powerpc/include/asm/book3s/32/mmu-hash.h b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
-index e38c91388c40..5bd26c218b94 100644
---- a/arch/powerpc/include/asm/book3s/32/mmu-hash.h
-+++ b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
-@@ -42,6 +42,8 @@ struct ppc_bat {
- u32 batu;
- u32 batl;
- };
-+
-+typedef struct page *pgtable_t;
- #endif /* !__ASSEMBLY__ */
-
- /*
-diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
-index 9c8c669a6b6a..488e7ed07e96 100644
---- a/arch/powerpc/include/asm/book3s/64/mmu.h
-+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
-@@ -2,6 +2,8 @@
- #ifndef _ASM_POWERPC_BOOK3S_64_MMU_H_
- #define _ASM_POWERPC_BOOK3S_64_MMU_H_
-
-+#include <asm/page.h>
-+
- #ifndef __ASSEMBLY__
- /*
- * Page size definition
-@@ -24,6 +26,13 @@ struct mmu_psize_def {
- };
- extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
-
-+/*
-+ * For BOOK3s 64 with 4k and 64K linux page size
-+ * we want to use pointers, because the page table
-+ * actually store pfn
-+ */
-+typedef pte_t *pgtable_t;
-+
- #endif /* __ASSEMBLY__ */
-
- /* 64-bit classic hash table MMU */
-diff --git a/arch/powerpc/include/asm/nohash/32/mmu.h b/arch/powerpc/include/asm/nohash/32/mmu.h
-index af0e8b54876a..f61f933a4cd8 100644
---- a/arch/powerpc/include/asm/nohash/32/mmu.h
-+++ b/arch/powerpc/include/asm/nohash/32/mmu.h
-@@ -16,4 +16,8 @@
- #include <asm/nohash/32/mmu-8xx.h>
+ arch/powerpc/include/asm/mmu-8xx.h | 4 ++++
+ arch/powerpc/include/asm/nohash/32/pgalloc.h | 29 +++++++++++++++++++++++++++-
+ arch/powerpc/include/asm/nohash/32/pgtable.h | 5 ++++-
+ arch/powerpc/mm/mmu_context_nohash.c | 4 ++++
+ arch/powerpc/mm/pgtable.c | 10 +++++++++-
+ arch/powerpc/mm/pgtable_32.c | 12 ++++++++++++
+ arch/powerpc/platforms/Kconfig.cputype | 1 +
+ 7 files changed, 62 insertions(+), 3 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/mmu-8xx.h b/arch/powerpc/include/asm/mmu-8xx.h
+index 193f53116c7a..4f4cb754afd8 100644
+--- a/arch/powerpc/include/asm/mmu-8xx.h
++++ b/arch/powerpc/include/asm/mmu-8xx.h
+@@ -190,6 +190,10 @@ typedef struct {
+ struct slice_mask mask_8m;
+ # endif
#endif
-
-+#ifndef __ASSEMBLY__
-+typedef struct page *pgtable_t;
-+#endif
-+
- #endif /* _ASM_POWERPC_NOHASH_32_MMU_H_ */
-diff --git a/arch/powerpc/include/asm/nohash/64/mmu.h b/arch/powerpc/include/asm/nohash/64/mmu.h
-index 87871d027b75..e6585480dfc4 100644
---- a/arch/powerpc/include/asm/nohash/64/mmu.h
-+++ b/arch/powerpc/include/asm/nohash/64/mmu.h
-@@ -5,4 +5,8 @@
- /* Freescale Book-E software loaded TLB or Book-3e (ISA 2.06+) MMU */
- #include <asm/nohash/mmu-book3e.h>
-
-+#ifndef __ASSEMBLY__
-+typedef struct page *pgtable_t;
-+#endif
-+
- #endif /* _ASM_POWERPC_NOHASH_64_MMU_H_ */
-diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
-index f6a1265face2..ddfb4b965e5b 100644
---- a/arch/powerpc/include/asm/page.h
-+++ b/arch/powerpc/include/asm/page.h
-@@ -335,20 +335,6 @@ void arch_free_page(struct page *page, int order);
++#ifdef CONFIG_NEED_PTE_FRAG
++ /* for 4K PTE fragment support */
++ void *pte_frag;
++#endif
+ } mm_context_t;
+
+ #define PHYS_IMMR_BASE (mfspr(SPRN_IMMR) & 0xfff80000)
+diff --git a/arch/powerpc/include/asm/nohash/32/pgalloc.h b/arch/powerpc/include/asm/nohash/32/pgalloc.h
+index 1c6461e7c6aa..1e3b8f580499 100644
+--- a/arch/powerpc/include/asm/nohash/32/pgalloc.h
++++ b/arch/powerpc/include/asm/nohash/32/pgalloc.h
+@@ -93,6 +93,32 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmdp,
+ ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel_g(pmd, address))? \
+ NULL: pte_offset_kernel(pmd, address))
+
++#ifdef CONFIG_NEED_PTE_FRAG
++extern pte_t *pte_fragment_alloc(struct mm_struct *, unsigned long, int);
++extern void pte_fragment_free(unsigned long *, int);
++
++static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
++ unsigned long address)
++{
++ return (pte_t *)pte_fragment_alloc(mm, address, 1);
++}
++
++static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
++ unsigned long address)
++{
++ return (pgtable_t)pte_fragment_alloc(mm, address, 0);
++}
++
++static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
++{
++ pte_fragment_free((unsigned long *)pte, 1);
++}
++
++static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
++{
++ pte_fragment_free((unsigned long *)ptepage, 0);
++}
++#else
+ extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
+ extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr);
+
+@@ -106,11 +132,12 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
+ pgtable_page_dtor(ptepage);
+ __free_page(ptepage);
+ }
++#endif
+
+ static inline void pgtable_free(void *table, unsigned index_size)
+ {
+ if (!index_size) {
+- free_page((unsigned long)table);
++ pte_free_kernel(NULL, table);
+ } else {
+ BUG_ON(index_size > MAX_PGTABLE_INDEX_SIZE);
+ kmem_cache_free(PGT_CACHE(index_size), table);
+diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
+index 3efd616bbc80..e2a22c8dc7f6 100644
+--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
++++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
+@@ -20,6 +20,9 @@ extern int icache_44x_need_flush;
+
+ #if defined(CONFIG_PPC_8xx) && defined(CONFIG_PPC_16K_PAGES)
+ #define PTE_INDEX_SIZE (PTE_SHIFT - 2)
++#define PTE_FRAG_NR 4
++#define PTE_FRAG_SIZE_SHIFT 12
++#define PTE_FRAG_SIZE (1UL << PTE_FRAG_SIZE_SHIFT)
+ #else
+ #define PTE_INDEX_SIZE PTE_SHIFT
#endif
-
- struct vm_area_struct;
--#ifdef CONFIG_PPC_BOOK3S_64
--/*
-- * For BOOK3s 64 with 4k and 64K linux page size
-- * we want to use pointers, because the page table
-- * actually store pfn
-- */
--typedef pte_t *pgtable_t;
--#else
--#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC64)
--typedef pte_t *pgtable_t;
--#else
--typedef struct page *pgtable_t;
--#endif
--#endif
-
- #include <asm-generic/memory_model.h>
- #endif /* __ASSEMBLY__ */
+@@ -303,7 +306,7 @@ static inline void __ptep_set_access_flags(struct mm_struct *mm,
+ */
+ #ifndef CONFIG_BOOKE
+ #define pmd_page_vaddr(pmd) \
+- ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++ ((unsigned long) __va(pmd_val(pmd) & ~(PTE_TABLE_SIZE - 1)))
+ #define pmd_page(pmd) \
+ pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
+ #else
+diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
+index e09228a9ad00..8b0ab33673e5 100644
+--- a/arch/powerpc/mm/mmu_context_nohash.c
++++ b/arch/powerpc/mm/mmu_context_nohash.c
+@@ -390,6 +390,9 @@ int init_new_context(struct task_struct *t, struct mm_struct *mm)
+ #endif
+ mm->context.id = MMU_NO_CONTEXT;
+ mm->context.active = 0;
++#ifdef CONFIG_NEED_PTE_FRAG
++ mm->context.pte_frag = NULL;
++#endif
+ return 0;
+ }
+
+@@ -418,6 +421,7 @@ void destroy_context(struct mm_struct *mm)
+ nr_free_contexts++;
+ }
+ raw_spin_unlock_irqrestore(&context_lock, flags);
++ destroy_pagetable_page(mm);
+ }
+
+ #ifdef CONFIG_SMP
+diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
+index 2d34755ed727..96cc5aa73331 100644
+--- a/arch/powerpc/mm/pgtable.c
++++ b/arch/powerpc/mm/pgtable.c
+@@ -23,6 +23,7 @@
+
+ #include <linux/kernel.h>
+ #include <linux/gfp.h>
++#include <linux/memblock.h>
+ #include <linux/mm.h>
+ #include <linux/percpu.h>
+ #include <linux/hardirq.h>
+@@ -320,10 +321,17 @@ static pte_t *__alloc_for_cache(struct mm_struct *mm, int kernel)
+ return (pte_t *)ret;
+ }
+
+-pte_t *pte_fragment_alloc(struct mm_struct *mm, unsigned long vmaddr, int kernel)
++__ref pte_t *pte_fragment_alloc(struct mm_struct *mm, unsigned long vmaddr, int kernel)
+ {
+ pte_t *pte;
+
++ if (kernel && !slab_is_available()) {
++ pte = __va(memblock_alloc(PTE_FRAG_SIZE, PTE_FRAG_SIZE));
++ if (pte)
++ memset(pte, 0, PTE_FRAG_SIZE);
++
++ return pte;
++ }
+ pte = get_from_cache(mm);
+ if (pte)
+ return pte;
+diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
+index 3aa0c78db95d..5c8737cf2945 100644
+--- a/arch/powerpc/mm/pgtable_32.c
++++ b/arch/powerpc/mm/pgtable_32.c
+@@ -40,6 +40,17 @@
+
+ extern char etext[], _stext[], _sinittext[], _einittext[];
+
++#ifdef CONFIG_NEED_PTE_FRAG
++void pte_fragment_free(unsigned long *table, int kernel)
++{
++ struct page *page = virt_to_page(table);
++ if (put_page_testzero(page)) {
++ if (!kernel)
++ pgtable_page_dtor(page);
++ free_unref_page(page);
++ }
++}
++#else
+ __ref pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+ {
+ pte_t *pte;
+@@ -69,6 +80,7 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
+ }
+ return ptepage;
+ }
++#endif
+
+ #ifdef CONFIG_PPC_GUARDED_PAGE_IN_PMD
+ int __pte_alloc_kernel_g(pmd_t *pmd, unsigned long address)
+diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
+index 7172b04c91b5..eff6210ad3c0 100644
+--- a/arch/powerpc/platforms/Kconfig.cputype
++++ b/arch/powerpc/platforms/Kconfig.cputype
+@@ -340,6 +340,7 @@ config PPC_MM_SLICES
+ config NEED_PTE_FRAG
+ bool
+ default y if PPC_BOOK3S_64 && PPC_64K_PAGES
++ default y if PPC_8xx && PPC_16K_PAGES
+ default n
+
+ config PPC_HAVE_PMU_SUPPORT
--
2.13.3