From: Andi Kleen <ak@suse.de>

ppc64		works with 3 levels (thanks to dwmw2) 

Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ppc64/kernel/eeh.c     |    2 +-
 25-akpm/arch/ppc64/kernel/process.c |    2 +-
 25-akpm/arch/ppc64/mm/hash_utils.c  |    2 +-
 25-akpm/arch/ppc64/mm/hugetlbpage.c |    2 +-
 25-akpm/arch/ppc64/mm/init.c        |    7 ++++++-
 25-akpm/include/asm-ppc64/page.h    |    2 ++
 25-akpm/include/asm-ppc64/pgalloc.h |    8 ++------
 25-akpm/include/asm-ppc64/pgtable.h |   10 ++++------
 8 files changed, 18 insertions(+), 17 deletions(-)

diff -puN arch/ppc64/kernel/eeh.c~4level-architecture-changes-for-ppc64 arch/ppc64/kernel/eeh.c
--- 25/arch/ppc64/kernel/eeh.c~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.568110824 -0800
+++ 25-akpm/arch/ppc64/kernel/eeh.c	2004-11-15 20:00:50.581108848 -0800
@@ -482,7 +482,7 @@ static inline unsigned long eeh_token_to
 	pte_t *ptep;
 	unsigned long pa;
 
-	ptep = find_linux_pte(ioremap_mm.pgd, token);
+	ptep = find_linux_pte((pgd_t *)ioremap_mm.pml4, token);
 	if (!ptep)
 		return token;
 	pa = pte_pfn(*ptep) << PAGE_SHIFT;
diff -puN arch/ppc64/kernel/process.c~4level-architecture-changes-for-ppc64 arch/ppc64/kernel/process.c
--- 25/arch/ppc64/kernel/process.c~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.569110672 -0800
+++ 25-akpm/arch/ppc64/kernel/process.c	2004-11-15 20:00:50.582108696 -0800
@@ -58,7 +58,7 @@ struct task_struct *last_task_used_altiv
 #endif
 
 struct mm_struct ioremap_mm = {
-	.pgd		= ioremap_dir,
+	.pml4		= (pml4_t *)ioremap_dir,
 	.mm_users	= ATOMIC_INIT(2),
 	.mm_count	= ATOMIC_INIT(1),
 	.cpu_vm_mask	= CPU_MASK_ALL,
diff -puN arch/ppc64/mm/hash_utils.c~4level-architecture-changes-for-ppc64 arch/ppc64/mm/hash_utils.c
--- 25/arch/ppc64/mm/hash_utils.c~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.571110368 -0800
+++ 25-akpm/arch/ppc64/mm/hash_utils.c	2004-11-15 20:00:50.583108544 -0800
@@ -315,7 +315,7 @@ int hash_page(unsigned long ea, unsigned
 		break;
 	}
 
-	pgdir = mm->pgd;
+	pgdir = (pgd_t *)mm->pml4;
 
 	if (pgdir == NULL)
 		return 1;
diff -puN arch/ppc64/mm/hugetlbpage.c~4level-architecture-changes-for-ppc64 arch/ppc64/mm/hugetlbpage.c
--- 25/arch/ppc64/mm/hugetlbpage.c~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.572110216 -0800
+++ 25-akpm/arch/ppc64/mm/hugetlbpage.c	2004-11-15 20:00:50.583108544 -0800
@@ -216,7 +216,7 @@ static int prepare_low_seg_for_htlb(stru
 	spin_lock(&mm->page_table_lock);
 	tlb = tlb_gather_mmu(mm, 0);
 	for (addr = start; addr < end; addr += PMD_SIZE) {
-		pgd_t *pgd = pgd_offset(mm, addr);
+		pgd_t *pgd = pml4_pgd_offset(pml4_offset(mm, addr), addr);
 		pmd_t *pmd;
 		struct page *page;
 		pte_t *pte;
diff -puN arch/ppc64/mm/init.c~4level-architecture-changes-for-ppc64 arch/ppc64/mm/init.c
--- 25/arch/ppc64/mm/init.c~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.574109912 -0800
+++ 25-akpm/arch/ppc64/mm/init.c	2004-11-15 20:00:50.584108392 -0800
@@ -849,7 +849,7 @@ void update_mmu_cache(struct vm_area_str
 	if (!pte_young(pte))
 		return;
 
-	pgdir = vma->vm_mm->pgd;
+	pgdir = (pgd_t *)vma->vm_mm->pml4;
 	if (pgdir == NULL)
 		return;
 
@@ -900,3 +900,8 @@ void pgtable_cache_init(void)
 	if (!zero_cache)
 		panic("pgtable_cache_init(): could not create zero_cache!\n");
 }
+
+pgd_t *__pgd_alloc(struct mm_struct *mm, pml4_t *dummy, unsigned long address)
+{
+	return kmem_cache_alloc(zero_cache, GFP_KERNEL);
+}
diff -puN include/asm-ppc64/page.h~4level-architecture-changes-for-ppc64 include/asm-ppc64/page.h
--- 25/include/asm-ppc64/page.h~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.575109760 -0800
+++ 25-akpm/include/asm-ppc64/page.h	2004-11-15 20:00:50.585108240 -0800
@@ -235,5 +235,7 @@ extern int page_is_ram(unsigned long pfn
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+#include <asm-generic/nopml4-page.h>
+
 #endif /* __KERNEL__ */
 #endif /* _PPC64_PAGE_H */
diff -puN include/asm-ppc64/pgalloc.h~4level-architecture-changes-for-ppc64 include/asm-ppc64/pgalloc.h
--- 25/include/asm-ppc64/pgalloc.h~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.577109456 -0800
+++ 25-akpm/include/asm-ppc64/pgalloc.h	2004-11-15 20:00:50.585108240 -0800
@@ -18,12 +18,6 @@ extern kmem_cache_t *zero_cache;
  * 2 of the License, or (at your option) any later version.
  */
 
-static inline pgd_t *
-pgd_alloc(struct mm_struct *mm)
-{
-	return kmem_cache_alloc(zero_cache, GFP_KERNEL);
-}
-
 static inline void
 pgd_free(pgd_t *pgd)
 {
@@ -107,4 +101,6 @@ void __pte_free_tlb(struct mmu_gather *t
 
 #define check_pgt_cache()	do { } while (0)
 
+#include <asm-generic/nopml4-pgalloc.h>
+
 #endif /* _PPC64_PGALLOC_H */
diff -puN include/asm-ppc64/pgtable.h~4level-architecture-changes-for-ppc64 include/asm-ppc64/pgtable.h
--- 25/include/asm-ppc64/pgtable.h~4level-architecture-changes-for-ppc64	2004-11-15 20:00:50.578109304 -0800
+++ 25-akpm/include/asm-ppc64/pgtable.h	2004-11-15 20:00:50.586108088 -0800
@@ -38,7 +38,7 @@
 #define PTRS_PER_PMD	(1 << PMD_INDEX_SIZE)
 #define PTRS_PER_PGD	(1 << PGD_INDEX_SIZE)
 
-#define USER_PTRS_PER_PGD	(1024)
+#define USER_PGDS_IN_LAST_PML4	(1024)
 #define FIRST_USER_PGD_NR	0
 
 #define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
@@ -228,7 +228,7 @@ void hugetlb_mm_free_pgd(struct mm_struc
 /* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
 #define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x7ff)
 
-#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
+#define pgd_index_k(address) pgd_index(address)
 
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(dir,addr) \
@@ -243,10 +243,6 @@ void hugetlb_mm_free_pgd(struct mm_struc
 #define pte_unmap(pte)			do { } while(0)
 #define pte_unmap_nested(pte)		do { } while(0)
 
-/* to find an entry in a kernel page-table-directory */
-/* This now only contains the vmalloc pages */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
 /* to find an entry in the ioremap page-table-directory */
 #define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
 
@@ -558,4 +554,6 @@ static inline pte_t *find_linux_pte(pgd_
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
 
+#include <asm-generic/nopml4-pgtable.h>
+
 #endif /* _PPC64_PGTABLE_H */
_