diff options
| -rw-r--r-- | arch/arm/include/asm/pgtable.h | 26 | ||||
| -rw-r--r-- | arch/arm/include/asm/tlbflush.h | 10 | ||||
| -rw-r--r-- | arch/arm/mm/fault-armv.c | 4 | ||||
| -rw-r--r-- | arch/arm/mm/flush.c | 30 |
4 files changed, 64 insertions, 6 deletions
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index ab68cf1ef80f..42e694f1d58e 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h | |||
| @@ -278,9 +278,24 @@ extern struct page *empty_zero_page; | |||
| 278 | 278 | ||
| 279 | #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) | 279 | #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) |
| 280 | 280 | ||
| 281 | #define set_pte_at(mm,addr,ptep,pteval) do { \ | 281 | #if __LINUX_ARM_ARCH__ < 6 |
| 282 | set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ | 282 | static inline void __sync_icache_dcache(pte_t pteval) |
| 283 | } while (0) | 283 | { |
| 284 | } | ||
| 285 | #else | ||
| 286 | extern void __sync_icache_dcache(pte_t pteval); | ||
| 287 | #endif | ||
| 288 | |||
| 289 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
| 290 | pte_t *ptep, pte_t pteval) | ||
| 291 | { | ||
| 292 | if (addr >= TASK_SIZE) | ||
| 293 | set_pte_ext(ptep, pteval, 0); | ||
| 294 | else { | ||
| 295 | __sync_icache_dcache(pteval); | ||
| 296 | set_pte_ext(ptep, pteval, PTE_EXT_NG); | ||
| 297 | } | ||
| 298 | } | ||
| 284 | 299 | ||
| 285 | /* | 300 | /* |
| 286 | * The following only work if pte_present() is true. | 301 | * The following only work if pte_present() is true. |
| @@ -290,8 +305,13 @@ extern struct page *empty_zero_page; | |||
| 290 | #define pte_write(pte) (pte_val(pte) & L_PTE_WRITE) | 305 | #define pte_write(pte) (pte_val(pte) & L_PTE_WRITE) |
| 291 | #define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY) | 306 | #define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY) |
| 292 | #define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) | 307 | #define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) |
| 308 | #define pte_exec(pte) (pte_val(pte) & L_PTE_EXEC) | ||
| 293 | #define pte_special(pte) (0) | 309 | #define pte_special(pte) (0) |
| 294 | 310 | ||
| 311 | #define pte_present_user(pte) \ | ||
| 312 | ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \ | ||
| 313 | (L_PTE_PRESENT | L_PTE_USER)) | ||
| 314 | |||
| 295 | #define PTE_BIT_FUNC(fn,op) \ | 315 | #define PTE_BIT_FUNC(fn,op) \ |
| 296 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } | 316 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } |
| 297 | 317 | ||
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 9ad329ad7458..989c9e57d92b 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h | |||
| @@ -562,10 +562,18 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); | |||
| 562 | /* | 562 | /* |
| 563 | * If PG_dcache_clean is not set for the page, we need to ensure that any | 563 | * If PG_dcache_clean is not set for the page, we need to ensure that any |
| 564 | * cache entries for the kernels virtual memory range are written | 564 | * cache entries for the kernels virtual memory range are written |
| 565 | * back to the page. | 565 | * back to the page. On ARMv6 and later, the cache coherency is handled via |
| 566 | * the set_pte_at() function. | ||
| 566 | */ | 567 | */ |
| 568 | #if __LINUX_ARM_ARCH__ < 6 | ||
| 567 | extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, | 569 | extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, |
| 568 | pte_t *ptep); | 570 | pte_t *ptep); |
| 571 | #else | ||
| 572 | static inline void update_mmu_cache(struct vm_area_struct *vma, | ||
| 573 | unsigned long addr, pte_t *ptep) | ||
| 574 | { | ||
| 575 | } | ||
| 576 | #endif | ||
| 569 | 577 | ||
| 570 | #endif | 578 | #endif |
| 571 | 579 | ||
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 58846cbd0e0b..8440d952ba6d 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; | 29 | static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; |
| 30 | 30 | ||
| 31 | #if __LINUX_ARM_ARCH__ < 6 | ||
| 31 | /* | 32 | /* |
| 32 | * We take the easy way out of this problem - we make the | 33 | * We take the easy way out of this problem - we make the |
| 33 | * PTE uncacheable. However, we leave the write buffer on. | 34 | * PTE uncacheable. However, we leave the write buffer on. |
| @@ -168,10 +169,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, | |||
| 168 | return; | 169 | return; |
| 169 | 170 | ||
| 170 | mapping = page_mapping(page); | 171 | mapping = page_mapping(page); |
| 171 | #ifndef CONFIG_SMP | ||
| 172 | if (!test_and_set_bit(PG_dcache_clean, &page->flags)) | 172 | if (!test_and_set_bit(PG_dcache_clean, &page->flags)) |
| 173 | __flush_dcache_page(mapping, page); | 173 | __flush_dcache_page(mapping, page); |
| 174 | #endif | ||
| 175 | if (mapping) { | 174 | if (mapping) { |
| 176 | if (cache_is_vivt()) | 175 | if (cache_is_vivt()) |
| 177 | make_coherent(mapping, vma, addr, ptep, pfn); | 176 | make_coherent(mapping, vma, addr, ptep, pfn); |
| @@ -179,6 +178,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, | |||
| 179 | __flush_icache_all(); | 178 | __flush_icache_all(); |
| 180 | } | 179 | } |
| 181 | } | 180 | } |
| 181 | #endif /* __LINUX_ARM_ARCH__ < 6 */ | ||
| 182 | 182 | ||
| 183 | /* | 183 | /* |
| 184 | * Check whether the write buffer has physical address aliasing | 184 | * Check whether the write buffer has physical address aliasing |
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index b4efce9b7985..dd5b0120b92e 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
| @@ -215,6 +215,36 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p | |||
| 215 | flush_dcache_mmap_unlock(mapping); | 215 | flush_dcache_mmap_unlock(mapping); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | #if __LINUX_ARM_ARCH__ >= 6 | ||
| 219 | void __sync_icache_dcache(pte_t pteval) | ||
| 220 | { | ||
| 221 | unsigned long pfn; | ||
| 222 | struct page *page; | ||
| 223 | struct address_space *mapping; | ||
| 224 | |||
| 225 | if (!pte_present_user(pteval)) | ||
| 226 | return; | ||
| 227 | if (cache_is_vipt_nonaliasing() && !pte_exec(pteval)) | ||
| 228 | /* only flush non-aliasing VIPT caches for exec mappings */ | ||
| 229 | return; | ||
| 230 | pfn = pte_pfn(pteval); | ||
| 231 | if (!pfn_valid(pfn)) | ||
| 232 | return; | ||
| 233 | |||
| 234 | page = pfn_to_page(pfn); | ||
| 235 | if (cache_is_vipt_aliasing()) | ||
| 236 | mapping = page_mapping(page); | ||
| 237 | else | ||
| 238 | mapping = NULL; | ||
| 239 | |||
| 240 | if (!test_and_set_bit(PG_dcache_clean, &page->flags)) | ||
| 241 | __flush_dcache_page(mapping, page); | ||
| 242 | /* pte_exec() already checked above for non-aliasing VIPT cache */ | ||
| 243 | if (cache_is_vipt_nonaliasing() || pte_exec(pteval)) | ||
| 244 | __flush_icache_all(); | ||
| 245 | } | ||
| 246 | #endif | ||
| 247 | |||
| 218 | /* | 248 | /* |
| 219 | * Ensure cache coherency between kernel mapping and userspace mapping | 249 | * Ensure cache coherency between kernel mapping and userspace mapping |
| 220 | * of this page. | 250 | * of this page. |
