summaryrefslogtreecommitdiff
path: root/arch/arc/mm/tlb.c
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-05-09 20:24:51 +0400
committerVineet Gupta <vgupta@synopsys.com>2013-05-09 20:29:46 +0400
commit4102b53392d6397d80b6e09b516517efacf7ea77 (patch)
treeb79aa87af1b3a1ff39b4a00b889cb806dfe32ae7 /arch/arc/mm/tlb.c
parent6ec18a81b22ab2b40df8424f2b5fc6be20ccad87 (diff)
downloadlinux-4102b53392d6397d80b6e09b516517efacf7ea77.tar.xz
ARC: [mm] Aliasing VIPT dcache support 2/4
This is the meat of the series which prevents any dcache alias creation by always keeping the U and K mapping of a page congruent. If a mapping already exists, and other tries to access the page, prev one is flushed to physical page (wback+inv) Essentially flush_dcache_page()/copy_user_highpage() create K-mapping of a page, but try to defer flushing, unless U-mapping exist. When page is actually mapped to userspace, update_mmu_cache() flushes the K-mapping (in certain cases this can be optimised out) Additonally flush_cache_mm(), flush_cache_range(), flush_cache_page() handle the puring of stale userspace mappings on exit/munmap... flush_anon_page() handles the existing U-mapping for anon page before kernel reads it via the GUP path. Note that while not complete, this is enough to boot a simple dynamically linked Busybox based rootfs Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Diffstat (limited to 'arch/arc/mm/tlb.c')
-rw-r--r--arch/arc/mm/tlb.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
index 5810c7a92b77..066145b5f348 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -421,25 +421,40 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
/*
* Called at the end of pagefault, for a userspace mapped page
* -pre-install the corresponding TLB entry into MMU
- * -Finalize the delayed D-cache flush (wback+inv kernel mapping)
+ * -Finalize the delayed D-cache flush of kernel mapping of page due to
+ * flush_dcache_page(), copy_user_page()
+ *
+ * Note that flush (when done) involves both WBACK - so physical page is
+ * in sync as well as INV - so any non-congruent aliases don't remain
*/
void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
pte_t *ptep)
{
unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
+ unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
create_tlb(vma, vaddr, ptep);
- /* icache doesn't snoop dcache, thus needs to be made coherent here */
- if (vma->vm_flags & VM_EXEC) {
+ /*
+ * Exec page : Independent of aliasing/page-color considerations,
+ * since icache doesn't snoop dcache on ARC, any dirty
+ * K-mapping of a code page needs to be wback+inv so that
+ * icache fetch by userspace sees code correctly.
+ * !EXEC page: If K-mapping is NOT congruent to U-mapping, flush it
+ * so userspace sees the right data.
+ * (Avoids the flush for Non-exec + congruent mapping case)
+ */
+ if (vma->vm_flags & VM_EXEC || addr_not_cache_congruent(paddr, vaddr)) {
struct page *page = pfn_to_page(pte_pfn(*ptep));
- /* if page was dcache dirty, flush now */
int dirty = test_and_clear_bit(PG_arch_1, &page->flags);
if (dirty) {
- unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
+ /* wback + inv dcache lines */
__flush_dcache_page(paddr, paddr);
- __inv_icache_page(paddr, vaddr);
+
+ /* invalidate any existing icache lines */
+ if (vma->vm_flags & VM_EXEC)
+ __inv_icache_page(paddr, vaddr);
}
}
}