Merge branch 'akpm' (patches from Andrew)
[cascardo/linux.git] / arch / mips / include / asm / pgtable.h
index 9a4fe01..a6b611f 100644 (file)
 struct mm_struct;
 struct vm_area_struct;
 
-#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT)
-#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_READ | \
+#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_NO_READ | \
+                                _CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \
                                 _page_cachable_default)
-#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_NO_EXEC | \
+#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_NO_EXEC | \
                                 _page_cachable_default)
-#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_READ | \
+#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | \
                                 _page_cachable_default)
 #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
                                 _PAGE_GLOBAL | _page_cachable_default)
 #define PAGE_KERNEL_NC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
                                 _PAGE_GLOBAL | _CACHE_CACHABLE_NONCOHERENT)
-#define PAGE_USERIO    __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+#define PAGE_USERIO    __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \
                                 _page_cachable_default)
 #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \
                        __WRITEABLE | _PAGE_GLOBAL | _CACHE_UNCACHED)
@@ -127,10 +128,19 @@ do {                                                                      \
        }                                                               \
 } while(0)
 
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pteval);
+
 #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
 
-#define pte_none(pte)          (!(((pte).pte_high) & ~_PAGE_GLOBAL))
+#ifdef CONFIG_XPA
+# define pte_none(pte)         (!(((pte).pte_high) & ~_PAGE_GLOBAL))
+#else
+# define pte_none(pte)         (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL))
+#endif
+
 #define pte_present(pte)       ((pte).pte_low & _PAGE_PRESENT)
+#define pte_no_exec(pte)       ((pte).pte_low & _PAGE_NO_EXEC)
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
@@ -138,17 +148,23 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
        smp_wmb();
        ptep->pte_low = pte.pte_low;
 
+#ifdef CONFIG_XPA
        if (pte.pte_high & _PAGE_GLOBAL) {
+#else
+       if (pte.pte_low & _PAGE_GLOBAL) {
+#endif
                pte_t *buddy = ptep_buddy(ptep);
                /*
                 * Make sure the buddy is global too (if it's !none,
                 * it better already be global)
                 */
-               if (pte_none(*buddy))
+               if (pte_none(*buddy)) {
+                       if (!config_enabled(CONFIG_XPA))
+                               buddy->pte_low |= _PAGE_GLOBAL;
                        buddy->pte_high |= _PAGE_GLOBAL;
+               }
        }
 }
-#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
@@ -156,8 +172,13 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
 
        htw_stop();
        /* Preserve global status for the pair */
-       if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL)
-               null.pte_high = _PAGE_GLOBAL;
+       if (config_enabled(CONFIG_XPA)) {
+               if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL)
+                       null.pte_high = _PAGE_GLOBAL;
+       } else {
+               if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL)
+                       null.pte_low = null.pte_high = _PAGE_GLOBAL;
+       }
 
        set_pte_at(mm, addr, ptep, null);
        htw_start();
@@ -166,6 +187,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
 
 #define pte_none(pte)          (!(pte_val(pte) & ~_PAGE_GLOBAL))
 #define pte_present(pte)       (pte_val(pte) & _PAGE_PRESENT)
+#define pte_no_exec(pte)       (pte_val(pte) & _PAGE_NO_EXEC)
 
 /*
  * Certain architectures need to do special things when pte's
@@ -187,30 +209,42 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
                 * For SMP, multiple CPUs can race, so we need to do
                 * this atomically.
                 */
-#ifdef CONFIG_64BIT
-#define LL_INSN "lld"
-#define SC_INSN "scd"
-#else /* CONFIG_32BIT */
-#define LL_INSN "ll"
-#define SC_INSN "sc"
-#endif
                unsigned long page_global = _PAGE_GLOBAL;
                unsigned long tmp;
 
-               __asm__ __volatile__ (
-                       "       .set    push\n"
-                       "       .set    noreorder\n"
-                       "1:     " LL_INSN "     %[tmp], %[buddy]\n"
-                       "       bnez    %[tmp], 2f\n"
-                       "        or     %[tmp], %[tmp], %[global]\n"
-                       "       " SC_INSN "     %[tmp], %[buddy]\n"
-                       "       beqz    %[tmp], 1b\n"
-                       "        nop\n"
-                       "2:\n"
-                       "       .set pop"
-                       : [buddy] "+m" (buddy->pte),
-                         [tmp] "=&r" (tmp)
+               if (kernel_uses_llsc && R10000_LLSC_WAR) {
+                       __asm__ __volatile__ (
+                       "       .set    arch=r4000                      \n"
+                       "       .set    push                            \n"
+                       "       .set    noreorder                       \n"
+                       "1:"    __LL    "%[tmp], %[buddy]               \n"
+                       "       bnez    %[tmp], 2f                      \n"
+                       "        or     %[tmp], %[tmp], %[global]       \n"
+                               __SC    "%[tmp], %[buddy]               \n"
+                       "       beqzl   %[tmp], 1b                      \n"
+                       "       nop                                     \n"
+                       "2:                                             \n"
+                       "       .set    pop                             \n"
+                       "       .set    mips0                           \n"
+                       : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
+                       : [global] "r" (page_global));
+               } else if (kernel_uses_llsc) {
+                       __asm__ __volatile__ (
+                       "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
+                       "       .set    push                            \n"
+                       "       .set    noreorder                       \n"
+                       "1:"    __LL    "%[tmp], %[buddy]               \n"
+                       "       bnez    %[tmp], 2f                      \n"
+                       "        or     %[tmp], %[tmp], %[global]       \n"
+                               __SC    "%[tmp], %[buddy]               \n"
+                       "       beqz    %[tmp], 1b                      \n"
+                       "       nop                                     \n"
+                       "2:                                             \n"
+                       "       .set    pop                             \n"
+                       "       .set    mips0                           \n"
+                       : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
                        : [global] "r" (page_global));
+               }
 #else /* !CONFIG_SMP */
                if (pte_none(*buddy))
                        pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
@@ -218,7 +252,6 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
        }
 #endif
 }
-#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
@@ -234,6 +267,22 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
 }
 #endif
 
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pteval)
+{
+       extern void __update_cache(unsigned long address, pte_t pte);
+
+       if (!pte_present(pteval))
+               goto cache_sync_done;
+
+       if (pte_present(*ptep) && (pte_pfn(*ptep) == pte_pfn(pteval)))
+               goto cache_sync_done;
+
+       __update_cache(addr, pteval);
+cache_sync_done:
+       set_pte(ptep, pteval);
+}
+
 /*
  * (pmds are folded into puds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
@@ -270,6 +319,8 @@ static inline int pte_young(pte_t pte)      { return pte.pte_low & _PAGE_ACCESSED; }
 static inline pte_t pte_wrprotect(pte_t pte)
 {
        pte.pte_low  &= ~_PAGE_WRITE;
+       if (!config_enabled(CONFIG_XPA))
+               pte.pte_low &= ~_PAGE_SILENT_WRITE;
        pte.pte_high &= ~_PAGE_SILENT_WRITE;
        return pte;
 }
@@ -277,6 +328,8 @@ static inline pte_t pte_wrprotect(pte_t pte)
 static inline pte_t pte_mkclean(pte_t pte)
 {
        pte.pte_low  &= ~_PAGE_MODIFIED;
+       if (!config_enabled(CONFIG_XPA))
+               pte.pte_low &= ~_PAGE_SILENT_WRITE;
        pte.pte_high &= ~_PAGE_SILENT_WRITE;
        return pte;
 }
@@ -284,6 +337,8 @@ static inline pte_t pte_mkclean(pte_t pte)
 static inline pte_t pte_mkold(pte_t pte)
 {
        pte.pte_low  &= ~_PAGE_ACCESSED;
+       if (!config_enabled(CONFIG_XPA))
+               pte.pte_low &= ~_PAGE_SILENT_READ;
        pte.pte_high &= ~_PAGE_SILENT_READ;
        return pte;
 }
@@ -291,24 +346,33 @@ static inline pte_t pte_mkold(pte_t pte)
 static inline pte_t pte_mkwrite(pte_t pte)
 {
        pte.pte_low |= _PAGE_WRITE;
-       if (pte.pte_low & _PAGE_MODIFIED)
+       if (pte.pte_low & _PAGE_MODIFIED) {
+               if (!config_enabled(CONFIG_XPA))
+                       pte.pte_low |= _PAGE_SILENT_WRITE;
                pte.pte_high |= _PAGE_SILENT_WRITE;
+       }
        return pte;
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
        pte.pte_low |= _PAGE_MODIFIED;
-       if (pte.pte_low & _PAGE_WRITE)
+       if (pte.pte_low & _PAGE_WRITE) {
+               if (!config_enabled(CONFIG_XPA))
+                       pte.pte_low |= _PAGE_SILENT_WRITE;
                pte.pte_high |= _PAGE_SILENT_WRITE;
+       }
        return pte;
 }
 
 static inline pte_t pte_mkyoung(pte_t pte)
 {
        pte.pte_low |= _PAGE_ACCESSED;
-       if (pte.pte_low & _PAGE_READ)
+       if (!(pte.pte_low & _PAGE_NO_READ)) {
+               if (!config_enabled(CONFIG_XPA))
+                       pte.pte_low |= _PAGE_SILENT_READ;
                pte.pte_high |= _PAGE_SILENT_READ;
+       }
        return pte;
 }
 #else
@@ -353,13 +417,8 @@ static inline pte_t pte_mkdirty(pte_t pte)
 static inline pte_t pte_mkyoung(pte_t pte)
 {
        pte_val(pte) |= _PAGE_ACCESSED;
-#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
        if (!(pte_val(pte) & _PAGE_NO_READ))
                pte_val(pte) |= _PAGE_SILENT_READ;
-       else
-#endif
-       if (pte_val(pte) & _PAGE_READ)
-               pte_val(pte) |= _PAGE_SILENT_READ;
        return pte;
 }
 
@@ -411,7 +470,7 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
  */
 #define mk_pte(page, pgprot)   pfn_pte(page_to_pfn(page), (pgprot))
 
-#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
+#if defined(CONFIG_XPA)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        pte.pte_low  &= (_PAGE_MODIFIED | _PAGE_ACCESSED | _PFNX_MASK);
@@ -420,6 +479,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
        pte.pte_high |= pgprot_val(newprot) & ~_PFN_MASK;
        return pte;
 }
+#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+       pte.pte_low  &= _PAGE_CHG_MASK;
+       pte.pte_high &= (_PFN_MASK | _CACHE_MASK);
+       pte.pte_low  |= pgprot_val(newprot);
+       pte.pte_high |= pgprot_val(newprot) & ~(_PFN_MASK | _CACHE_MASK);
+       return pte;
+}
 #else
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
@@ -430,15 +498,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 extern void __update_tlb(struct vm_area_struct *vma, unsigned long address,
        pte_t pte);
-extern void __update_cache(struct vm_area_struct *vma, unsigned long address,
-       pte_t pte);
 
 static inline void update_mmu_cache(struct vm_area_struct *vma,
        unsigned long address, pte_t *ptep)
 {
        pte_t pte = *ptep;
        __update_tlb(vma, address, pte);
-       __update_cache(vma, address, pte);
 }
 
 static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
@@ -468,6 +533,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
+#define has_transparent_hugepage has_transparent_hugepage
 extern int has_transparent_hugepage(void);
 
 static inline int pmd_trans_huge(pmd_t pmd)
@@ -542,13 +608,8 @@ static inline pmd_t pmd_mkyoung(pmd_t pmd)
 {
        pmd_val(pmd) |= _PAGE_ACCESSED;
 
-#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
        if (!(pmd_val(pmd) & _PAGE_NO_READ))
                pmd_val(pmd) |= _PAGE_SILENT_READ;
-       else
-#endif
-       if (pmd_val(pmd) & _PAGE_READ)
-               pmd_val(pmd) |= _PAGE_SILENT_READ;
 
        return pmd;
 }