powerpc/mm: Reduce hugepd size for 8M hugepages on 8xx
[linux-2.6-microblaze.git] / arch / powerpc / include / asm / nohash / 32 / pgtable.h
index b04ba25..ff78bf2 100644 (file)
@@ -110,13 +110,13 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
  */
 #define VMALLOC_OFFSET (0x1000000) /* 16M */
 #ifdef PPC_PIN_SIZE
-#define VMALLOC_START (((_ALIGN((long)high_memory, PPC_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#define VMALLOC_START (((ALIGN((long)high_memory, PPC_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #else
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #endif
 
 #ifdef CONFIG_KASAN_VMALLOC
-#define VMALLOC_END    _ALIGN_DOWN(ioremap_bot, PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
+#define VMALLOC_END    ALIGN_DOWN(ioremap_bot, PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
 #else
 #define VMALLOC_END    ioremap_bot
 #endif
@@ -166,7 +166,7 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
 #ifndef __ASSEMBLY__
 
 #define pte_clear(mm, addr, ptep) \
-       do { pte_update(ptep, ~0, 0); } while (0)
+       do { pte_update(mm, addr, ptep, ~0, 0, 0); } while (0)
 
 #ifndef pte_mkwrite
 static inline pte_t pte_mkwrite(pte_t pte)
@@ -221,13 +221,35 @@ static inline void pmd_clear(pmd_t *pmdp)
  * that an executable user mapping was modified, which is needed
  * to properly flush the virtually tagged instruction cache of
  * those implementations.
+ *
+ * On the 8xx, the page tables are a bit special. For 16k pages, we have
+ * 4 identical entries. For other page sizes, we have a single entry in the
+ * table.
  */
-#ifndef CONFIG_PTE_64BIT
-static inline unsigned long pte_update(pte_t *p,
-                                      unsigned long clr,
-                                      unsigned long set)
+#ifdef CONFIG_PPC_8xx
+static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
+                                    unsigned long clr, unsigned long set, int huge)
 {
-#ifdef PTE_ATOMIC_UPDATES
+       pte_basic_t *entry = &p->pte;
+       pte_basic_t old = pte_val(*p);
+       pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
+       int num, i;
+
+       if (!huge)
+               num = PAGE_SIZE / SZ_4K;
+       else
+               num = 1;
+
+       for (i = 0; i < num; i++, entry++)
+               *entry = new;
+
+       return old;
+}
+#else
+static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
+                                    unsigned long clr, unsigned long set, int huge)
+{
+#if defined(PTE_ATOMIC_UPDATES) && !defined(CONFIG_PTE_64BIT)
        unsigned long old, tmp;
 
        __asm__ __volatile__("\
@@ -241,14 +263,10 @@ static inline unsigned long pte_update(pte_t *p,
        : "r" (p), "r" (clr), "r" (set), "m" (*p)
        : "cc" );
 #else /* PTE_ATOMIC_UPDATES */
-       unsigned long old = pte_val(*p);
-       unsigned long new = (old & ~clr) | set;
+       pte_basic_t old = pte_val(*p);
+       pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
 
-#if defined(CONFIG_PPC_8xx) && defined(CONFIG_PPC_16K_PAGES)
-       p->pte = p->pte1 = p->pte2 = p->pte3 = new;
-#else
        *p = __pte(new);
-#endif
 #endif /* !PTE_ATOMIC_UPDATES */
 
 #ifdef CONFIG_44x
@@ -257,54 +275,24 @@ static inline unsigned long pte_update(pte_t *p,
 #endif
        return old;
 }
-#else /* CONFIG_PTE_64BIT */
-static inline unsigned long long pte_update(pte_t *p,
-                                           unsigned long clr,
-                                           unsigned long set)
-{
-#ifdef PTE_ATOMIC_UPDATES
-       unsigned long long old;
-       unsigned long tmp;
-
-       __asm__ __volatile__("\
-1:     lwarx   %L0,0,%4\n\
-       lwzx    %0,0,%3\n\
-       andc    %1,%L0,%5\n\
-       or      %1,%1,%6\n"
-       PPC405_ERR77(0,%3)
-"      stwcx.  %1,0,%4\n\
-       bne-    1b"
-       : "=&r" (old), "=&r" (tmp), "=m" (*p)
-       : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p)
-       : "cc" );
-#else /* PTE_ATOMIC_UPDATES */
-       unsigned long long old = pte_val(*p);
-       *p = __pte((old & ~(unsigned long long)clr) | set);
-#endif /* !PTE_ATOMIC_UPDATES */
-
-#ifdef CONFIG_44x
-       if ((old & _PAGE_USER) && (old & _PAGE_EXEC))
-               icache_44x_need_flush = 1;
 #endif
-       return old;
-}
-#endif /* CONFIG_PTE_64BIT */
 
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-static inline int __ptep_test_and_clear_young(unsigned int context, unsigned long addr, pte_t *ptep)
+static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
+                                             unsigned long addr, pte_t *ptep)
 {
        unsigned long old;
-       old = pte_update(ptep, _PAGE_ACCESSED, 0);
+       old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
        return (old & _PAGE_ACCESSED) != 0;
 }
 #define ptep_test_and_clear_young(__vma, __addr, __ptep) \
-       __ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
+       __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep)
 
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
                                       pte_t *ptep)
 {
-       return __pte(pte_update(ptep, ~0, 0));
+       return __pte(pte_update(mm, addr, ptep, ~0, 0, 0));
 }
 
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
@@ -314,7 +302,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
        unsigned long clr = ~pte_val(pte_wrprotect(__pte(~0)));
        unsigned long set = pte_val(pte_wrprotect(__pte(0)));
 
-       pte_update(ptep, clr, set);
+       pte_update(mm, addr, ptep, clr, set, 0);
 }
 
 static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
@@ -326,8 +314,9 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
        pte_t pte_clr = pte_mkyoung(pte_mkdirty(pte_mkwrite(pte_mkexec(__pte(~0)))));
        unsigned long set = pte_val(entry) & pte_val(pte_set);
        unsigned long clr = ~pte_val(entry) & ~pte_val(pte_clr);
+       int huge = psize > mmu_virtual_psize ? 1 : 0;
 
-       pte_update(ptep, clr, set);
+       pte_update(vma->vm_mm, address, ptep, clr, set, huge);
 
        flush_tlb_page(vma, address);
 }