ARM: mm: Transparent huge page support for LPAE systems.
[pandora-kernel.git] / arch / arm / include / asm / pgtable-3level.h
index d1bcd82..54733e5 100644 (file)
 #define L_PTE_SPECIAL          (_AT(pteval_t, 1) << 56)        /* unused */
 #define L_PTE_NONE             (_AT(pteval_t, 1) << 57)        /* PROT_NONE */
 
+#define PMD_SECT_VALID         (_AT(pmdval_t, 1) << 0)
+#define PMD_SECT_DIRTY         (_AT(pmdval_t, 1) << 55)
+#define PMD_SECT_SPLITTING     (_AT(pmdval_t, 1) << 56)
+#define PMD_SECT_NONE          (_AT(pmdval_t, 1) << 57)
+
 /*
  * To be used in assembly code with the upper page attributes.
  */
@@ -196,6 +201,61 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 #define pte_huge(pte)          (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT))
 #define pte_mkhuge(pte)                (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
 
+#define pmd_young(pmd)         (pmd_val(pmd) & PMD_SECT_AF)
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd)         (!(pmd_val(pmd) & PMD_SECT_RDONLY))
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_trans_huge(pmd)    (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
+#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#endif
+
+#define PMD_BIT_FUNC(fn,op) \
+static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+
+PMD_BIT_FUNC(wrprotect,        |= PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkold,    &= ~PMD_SECT_AF);
+PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
+PMD_BIT_FUNC(mkwrite,   &= ~PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkdirty,   |= PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkyoung,   |= PMD_SECT_AF);
+
+#define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
+
+#define pmd_pfn(pmd)           (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+#define pfn_pmd(pfn,prot)      (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define mk_pmd(page,prot)      pfn_pmd(page_to_pfn(page),prot)
+
+/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */
+#define pmd_mknotpresent(pmd)  (__pmd(0))
+
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+       const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | PMD_SECT_RDONLY |
+                               PMD_SECT_VALID | PMD_SECT_NONE;
+       pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
+       return pmd;
+}
+
+static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+                             pmd_t *pmdp, pmd_t pmd)
+{
+       BUG_ON(addr >= TASK_SIZE);
+
+       /* create a faulting entry if PROT_NONE protected */
+       if (pmd_val(pmd) & PMD_SECT_NONE)
+               pmd_val(pmd) &= ~PMD_SECT_VALID;
+
+       *pmdp = __pmd(pmd_val(pmd) | PMD_SECT_nG);
+       flush_pmd_entry(pmdp);
+}
+
+static inline int has_transparent_hugepage(void)
+{
+       return 1;
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_PGTABLE_3LEVEL_H */