ARC: [mm] optimise icache flush for user mappings
authorVineet Gupta <vgupta@synopsys.com>
Thu, 11 Apr 2013 13:06:35 +0000 (18:36 +0530)
committerVineet Gupta <vgupta@synopsys.com>
Tue, 7 May 2013 13:38:12 +0000 (19:08 +0530)
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>
arch/arc/include/asm/cacheflush.h
arch/arc/mm/cache_arc700.c
arch/arc/mm/tlb.c

index 97ee96f265055b012cd763f0daf293e61e2c754d..46f13e7314dc1d1590590623a0746b7e094e8bb1 100644 (file)
 
 #include <linux/mm.h>
 
+/*
+ * Semantically we need this because icache doesn't snoop dcache/dma.
+ * However ARC Cache flush requires paddr as well as vaddr, latter not available
+ * in the flush_icache_page() API. So we no-op it but do the equivalent work
+ * in update_mmu_cache()
+ */
+#define flush_icache_page(vma, page)
+
 void flush_cache_all(void);
 
 void flush_icache_range(unsigned long start, unsigned long end);
-void flush_icache_page(struct vm_area_struct *vma, struct page *page);
 void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr,
                                     int len);
+void __inv_icache_page(unsigned long paddr, unsigned long vaddr);
 
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 
index c02aac649e84450685e2e2e494f9f963e5052d28..a65c13942766ee2564548827b2deae6ae656753a 100644 (file)
@@ -716,18 +716,10 @@ void flush_icache_range_vaddr(unsigned long paddr, unsigned long u_vaddr,
        __dc_line_op(paddr, len, OP_FLUSH);
 }
 
-/*
- * XXX: This also needs to be optim using pg_arch_1
- * This is called when a page-cache page is about to be mapped into a
- * user process' address space.  It offers an opportunity for a
- * port to ensure d-cache/i-cache coherency if necessary.
- */
-void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+/* wrapper to compile time eliminate alignment checks in flush loop */
+void __inv_icache_page(unsigned long paddr, unsigned long vaddr)
 {
-       if (!(vma->vm_flags & VM_EXEC))
-               return;
-
-       __ic_line_inv((unsigned long)page_address(page), PAGE_SIZE);
+       __ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE);
 }
 
 void flush_icache_all(void)
index c03364af9363174e3185834293198d1e3780c51b..086be526072a66e89463759d9218922e19bc5b87 100644 (file)
@@ -422,12 +422,18 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
  * when a new PTE is entered in Page Tables or an existing one
  * is modified. We aggresively pre-install a TLB entry
  */
-
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddress,
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
                      pte_t *ptep)
 {
+       unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
+
+       create_tlb(vma, vaddr, ptep);
 
-       create_tlb(vma, vaddress, ptep);
+       /* icache doesn't snoop dcache, thus needs to be made coherent here */
+       if (vma->vm_flags & VM_EXEC) {
+               unsigned long paddr =  pte_val(*ptep) & PAGE_MASK;
+               __inv_icache_page(paddr, vaddr);
+       }
 }
 
 /* Read the Cache Build Confuration Registers, Decode them and save into