diff options
author | Steve Capper <steve.capper@linaro.org> | 2014-10-09 18:29:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 22:26:00 -0400 |
commit | bd951303be5b4df578c7f30ef78839f1a9d6658c (patch) | |
tree | 573157dd8efc4de9a26b5e10f857840f8fcab02e | |
parent | 2667f50e8b81457fcb4a3dbe6aff3e81ea009e13 (diff) |
arm: mm: introduce special ptes for LPAE
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>
-rw-r--r-- | arch/arm/include/asm/pgtable-2level.h | 2 | ||||
-rw-r--r-- | arch/arm/include/asm/pgtable-3level.h | 7 | ||||
-rw-r--r-- | arch/arm/include/asm/pgtable.h | 6 |
3 files changed, 11 insertions, 4 deletions
diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index 219ac88a9542..f0279411847d 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h | |||
@@ -182,6 +182,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | |||
182 | #define pmd_addr_end(addr,end) (end) | 182 | #define pmd_addr_end(addr,end) (end) |
183 | 183 | ||
184 | #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) | 184 | #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) |
185 | #define pte_special(pte) (0) | ||
186 | static inline pte_t pte_mkspecial(pte_t pte) { return pte; } | ||
185 | 187 | ||
186 | /* | 188 | /* |
187 | * We don't have huge page support for short descriptors, for the moment | 189 | * We don't have huge page support for short descriptors, for the moment |
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index 06e0bc0f8b00..16122d4d7081 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h | |||
@@ -213,6 +213,13 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | |||
213 | #define pmd_isclear(pmd, val) (!(pmd_val(pmd) & (val))) | 213 | #define pmd_isclear(pmd, val) (!(pmd_val(pmd) & (val))) |
214 | 214 | ||
215 | #define pmd_young(pmd) (pmd_isset((pmd), PMD_SECT_AF)) | 215 | #define pmd_young(pmd) (pmd_isset((pmd), PMD_SECT_AF)) |
216 | #define pte_special(pte) (pte_isset((pte), L_PTE_SPECIAL)) | ||
217 | static inline pte_t pte_mkspecial(pte_t pte) | ||
218 | { | ||
219 | pte_val(pte) |= L_PTE_SPECIAL; | ||
220 | return pte; | ||
221 | } | ||
222 | #define __HAVE_ARCH_PTE_SPECIAL | ||
216 | 223 | ||
217 | #define __HAVE_ARCH_PMD_WRITE | 224 | #define __HAVE_ARCH_PMD_WRITE |
218 | #define pmd_write(pmd) (pmd_isclear((pmd), L_PMD_SECT_RDONLY)) | 225 | #define pmd_write(pmd) (pmd_isclear((pmd), L_PMD_SECT_RDONLY)) |
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 01baef07cd0c..90aa4583b308 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h | |||
@@ -226,7 +226,6 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) | |||
226 | #define pte_dirty(pte) (pte_isset((pte), L_PTE_DIRTY)) | 226 | #define pte_dirty(pte) (pte_isset((pte), L_PTE_DIRTY)) |
227 | #define pte_young(pte) (pte_isset((pte), L_PTE_YOUNG)) | 227 | #define pte_young(pte) (pte_isset((pte), L_PTE_YOUNG)) |
228 | #define pte_exec(pte) (pte_isclear((pte), L_PTE_XN)) | 228 | #define pte_exec(pte) (pte_isclear((pte), L_PTE_XN)) |
229 | #define pte_special(pte) (0) | ||
230 | 229 | ||
231 | #define pte_valid_user(pte) \ | 230 | #define pte_valid_user(pte) \ |
232 | (pte_valid(pte) && pte_isset((pte), L_PTE_USER) && pte_young(pte)) | 231 | (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, | |||
245 | unsigned long ext = 0; | 244 | unsigned long ext = 0; |
246 | 245 | ||
247 | if (addr < TASK_SIZE && pte_valid_user(pteval)) { | 246 | if (addr < TASK_SIZE && pte_valid_user(pteval)) { |
248 | __sync_icache_dcache(pteval); | 247 | if (!pte_special(pteval)) |
248 | __sync_icache_dcache(pteval); | ||
249 | ext |= PTE_EXT_NG; | 249 | ext |= PTE_EXT_NG; |
250 | } | 250 | } |
251 | 251 | ||
@@ -264,8 +264,6 @@ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG); | |||
264 | PTE_BIT_FUNC(mkexec, &= ~L_PTE_XN); | 264 | PTE_BIT_FUNC(mkexec, &= ~L_PTE_XN); |
265 | PTE_BIT_FUNC(mknexec, |= L_PTE_XN); | 265 | PTE_BIT_FUNC(mknexec, |= L_PTE_XN); |
266 | 266 | ||
267 | static inline pte_t pte_mkspecial(pte_t pte) { return pte; } | ||
268 | |||
269 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | 267 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) |
270 | { | 268 | { |
271 | const pteval_t mask = L_PTE_XN | L_PTE_RDONLY | L_PTE_USER | | 269 | const pteval_t mask = L_PTE_XN | L_PTE_RDONLY | L_PTE_USER | |