aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-04-11 09:06:35 -0400
committerVineet Gupta <vgupta@synopsys.com>2013-05-07 09:38:12 -0400
commit24603fdd19d978fcc0d089d92370ee1aa3a71e84 (patch)
tree8871ebc44c1b569dce1a394eb290f2912066cc52
parent8d56bec2f2945b7e500b413d1bdc24e7dca12877 (diff)
ARC: [mm] optimise icache flush for user mappings
ARC icache doesn't snoop dcache thus executable pages need to be made coherent before mapping into userspace in flush_icache_page(). However ARC700 CDU (hardware cache flush module) requires both vaddr (index in cache) as well as paddr (tag match) to correctly identify a line in the VIPT cache. A typical ARC700 SoC has aliasing icache, thus the paddr only based flush_icache_page() API couldn't be implemented efficiently. It had to loop thru all possible alias indexes and perform the invalidate operation (ofcourse the cache op would only succeed at the index(es) where tag matches - typically only 1, but the cost of visiting all the cache-bins needs to paid nevertheless). Turns out however that the vaddr (along with paddr) is available in update_mmu_cache() hence better suits ARC icache flush semantics. With both vaddr+paddr, exactly one flush operation per line is done. Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
-rw-r--r--arch/arc/include/asm/cacheflush.h10
-rw-r--r--arch/arc/mm/cache_arc700.c14
-rw-r--r--arch/arc/mm/tlb.c12
3 files changed, 21 insertions, 15 deletions
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h
index 97ee96f26505..46f13e7314dc 100644
--- a/arch/arc/include/asm/cacheflush.h
+++ b/arch/arc/include/asm/cacheflush.h
@@ -20,12 +20,20 @@
20 20
21#include <linux/mm.h> 21#include <linux/mm.h>
22 22
23/*
24 * Semantically we need this because icache doesn't snoop dcache/dma.
25 * However ARC Cache flush requires paddr as well as vaddr, latter not available
26 * in the flush_icache_page() API. So we no-op it but do the equivalent work
27 * in update_mmu_cache()
28 */
29#define flush_icache_page(vma, page)
30
23void flush_cache_all(void); 31void flush_cache_all(void);
24 32
25void flush_icache_range(unsigned long start, unsigned long end); 33void flush_icache_range(unsigned long start, unsigned long end);
26void flush_icache_page(struct vm_area_struct *vma, struct page *page);
27void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr, 34void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr,
28 int len); 35 int len);
36void __inv_icache_page(unsigned long paddr, unsigned long vaddr);
29 37
30#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 38#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
31 39
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c
index c02aac649e84..a65c13942766 100644
--- a/arch/arc/mm/cache_arc700.c
+++ b/arch/arc/mm/cache_arc700.c
@@ -716,18 +716,10 @@ void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr,
716 __dc_line_op(paddr, len, OP_FLUSH); 716 __dc_line_op(paddr, len, OP_FLUSH);
717} 717}
718 718
719/* 719/* wrapper to compile time eliminate alignment checks in flush loop */
720 * XXX: This also needs to be optim using pg_arch_1 720void __inv_icache_page(unsigned long paddr, unsigned long vaddr)
721 * This is called when a page-cache page is about to be mapped into a
722 * user process' address space. It offers an opportunity for a
723 * port to ensure d-cache/i-cache coherency if necessary.
724 */
725void flush_icache_page(struct vm_area_struct *vma, struct page *page)
726{ 721{
727 if (!(vma->vm_flags & VM_EXEC)) 722 __ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE);
728 return;
729
730 __ic_line_inv((unsigned long)page_address(page), PAGE_SIZE);
731} 723}
732 724
733void flush_icache_all(void) 725void flush_icache_all(void)
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
index c03364af9363..086be526072a 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -422,12 +422,18 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
422 * when a new PTE is entered in Page Tables or an existing one 422 * when a new PTE is entered in Page Tables or an existing one
423 * is modified. We aggresively pre-install a TLB entry 423 * is modified. We aggresively pre-install a TLB entry
424 */ 424 */
425 425void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
426void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddress,
427 pte_t *ptep) 426 pte_t *ptep)
428{ 427{
428 unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
429
430 create_tlb(vma, vaddr, ptep);
429 431
430 create_tlb(vma, vaddress, ptep); 432 /* icache doesn't snoop dcache, thus needs to be made coherent here */
433 if (vma->vm_flags & VM_EXEC) {
434 unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
435 __inv_icache_page(paddr, vaddr);
436 }
431} 437}
432 438
433/* Read the Cache Build Confuration Registers, Decode them and save into 439/* Read the Cache Build Confuration Registers, Decode them and save into