arm: mm: introduce special ptes for LPAE
authorSteve Capper <steve.capper@linaro.org>
Thu, 9 Oct 2014 22:29:16 +0000 (15:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 10 Oct 2014 02:26:00 +0000 (22:26 -0400)
We need a mechanism to tag ptes as being special, this indicates that no
attempt should be made to access the underlying struct page * associated
with the pte.  This is used by the fast_gup when operating on ptes as it
has no means to access VMAs (that also contain this information)
locklessly.

The L_PTE_SPECIAL bit is already allocated for LPAE, this patch modifies
pte_special and pte_mkspecial to make use of it, and defines
__HAVE_ARCH_PTE_SPECIAL.

This patch also excludes special ptes from the icache/dcache sync logic.

Signed-off-by: Steve Capper <steve.capper@linaro.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dann Frazier <dann.frazier@canonical.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/arm/include/asm/pgtable-2level.h
arch/arm/include/asm/pgtable-3level.h
arch/arm/include/asm/pgtable.h

index 219ac88a954243b3e3acaebcebd9871ea49825e4..f0279411847d72e2f73ffd430a9a5d53d9968514 100644 (file)
@@ -182,6 +182,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 #define pmd_addr_end(addr,end) (end)
 
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
+#define pte_special(pte)       (0)
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 
 /*
  * We don't have huge page support for short descriptors, for the moment
index 06e0bc0f8b00b2c7f9fe9f6dac97c81b00b803bb..16122d4d708199029697ea007840fe747277ff2f 100644 (file)
@@ -213,6 +213,13 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 #define pmd_isclear(pmd, val)  (!(pmd_val(pmd) & (val)))
 
 #define pmd_young(pmd)         (pmd_isset((pmd), PMD_SECT_AF))
+#define pte_special(pte)       (pte_isset((pte), L_PTE_SPECIAL))
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+       pte_val(pte) |= L_PTE_SPECIAL;
+       return pte;
+}
+#define        __HAVE_ARCH_PTE_SPECIAL
 
 #define __HAVE_ARCH_PMD_WRITE
 #define pmd_write(pmd)         (pmd_isclear((pmd), L_PMD_SECT_RDONLY))
index 01baef07cd0ca64a16f8b84c52c56a88c7ef6989..90aa4583b3086812e7bbea226f9092c0cc422cd7 100644 (file)
@@ -226,7 +226,6 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 #define pte_dirty(pte)         (pte_isset((pte), L_PTE_DIRTY))
 #define pte_young(pte)         (pte_isset((pte), L_PTE_YOUNG))
 #define pte_exec(pte)          (pte_isclear((pte), L_PTE_XN))
-#define pte_special(pte)       (0)
 
 #define pte_valid_user(pte)    \
        (pte_valid(pte) && pte_isset((pte), L_PTE_USER) && pte_young(pte))
@@ -245,7 +244,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
        unsigned long ext = 0;
 
        if (addr < TASK_SIZE && pte_valid_user(pteval)) {
-               __sync_icache_dcache(pteval);
+               if (!pte_special(pteval))
+                       __sync_icache_dcache(pteval);
                ext |= PTE_EXT_NG;
        }
 
@@ -264,8 +264,6 @@ PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
 PTE_BIT_FUNC(mkexec,   &= ~L_PTE_XN);
 PTE_BIT_FUNC(mknexec,   |= L_PTE_XN);
 
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
-
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = L_PTE_XN | L_PTE_RDONLY | L_PTE_USER |