diff options
Diffstat (limited to 'arch/arm/mm/flush.c')
| -rw-r--r-- | arch/arm/mm/flush.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index c6de48d89503..4085ed983e46 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
| @@ -13,6 +13,29 @@ | |||
| 13 | 13 | ||
| 14 | #include <asm/cacheflush.h> | 14 | #include <asm/cacheflush.h> |
| 15 | #include <asm/system.h> | 15 | #include <asm/system.h> |
| 16 | #include <asm/tlbflush.h> | ||
| 17 | |||
| 18 | #ifdef CONFIG_CPU_CACHE_VIPT | ||
| 19 | #define ALIAS_FLUSH_START 0xffff4000 | ||
| 20 | |||
| 21 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | ||
| 22 | |||
| 23 | static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) | ||
| 24 | { | ||
| 25 | unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); | ||
| 26 | |||
| 27 | set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL)); | ||
| 28 | flush_tlb_kernel_page(to); | ||
| 29 | |||
| 30 | asm( "mcrr p15, 0, %1, %0, c14\n" | ||
| 31 | " mcrr p15, 0, %1, %0, c5\n" | ||
| 32 | : | ||
| 33 | : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES) | ||
| 34 | : "cc"); | ||
| 35 | } | ||
| 36 | #else | ||
| 37 | #define flush_pfn_alias(pfn,vaddr) do { } while (0) | ||
| 38 | #endif | ||
| 16 | 39 | ||
| 17 | static void __flush_dcache_page(struct address_space *mapping, struct page *page) | 40 | static void __flush_dcache_page(struct address_space *mapping, struct page *page) |
| 18 | { | 41 | { |
| @@ -37,6 +60,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page | |||
| 37 | return; | 60 | return; |
| 38 | 61 | ||
| 39 | /* | 62 | /* |
| 63 | * This is a page cache page. If we have a VIPT cache, we | ||
| 64 | * only need to do one flush - which would be at the relevant | ||
| 65 | * userspace colour, which is congruent with page->index. | ||
| 66 | */ | ||
| 67 | if (cache_is_vipt()) { | ||
| 68 | if (cache_is_vipt_aliasing()) | ||
| 69 | flush_pfn_alias(page_to_pfn(page), | ||
| 70 | page->index << PAGE_CACHE_SHIFT); | ||
| 71 | return; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* | ||
| 40 | * There are possible user space mappings of this page: | 75 | * There are possible user space mappings of this page: |
| 41 | * - VIVT cache: we need to also write back and invalidate all user | 76 | * - VIVT cache: we need to also write back and invalidate all user |
| 42 | * data in the current VM view associated with this page. | 77 | * data in the current VM view associated with this page. |
| @@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page | |||
| 57 | continue; | 92 | continue; |
| 58 | offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; | 93 | offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; |
| 59 | flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page)); | 94 | flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page)); |
| 60 | if (cache_is_vipt()) | ||
| 61 | break; | ||
| 62 | } | 95 | } |
| 63 | flush_dcache_mmap_unlock(mapping); | 96 | flush_dcache_mmap_unlock(mapping); |
| 64 | } | 97 | } |
