]> err.no Git - linux-2.6/commitdiff
[PATCH] ARM: Add V6 aliasing cache flush
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Tue, 10 May 2005 16:31:43 +0000 (17:31 +0100)
committerRussell King <rmk@dyn-67.arm.linux.org.uk>
Tue, 10 May 2005 16:31:43 +0000 (17:31 +0100)
Add cache flushing support for aliased V6 caches to
flush_dcache_page.

Signed-off-by: Russell King <rmk@arm.linux.org.uk>
arch/arm/mm/flush.c

index c6de48d895032de8d615ee0f1ae8d8b31e13a716..4085ed983e46e07c3ac62ba31f8b0e605ee2594c 100644 (file)
 
 #include <asm/cacheflush.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_CPU_CACHE_VIPT
+#define ALIAS_FLUSH_START      0xffff4000
+
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
+static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
+{
+       unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
+
+       set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL));
+       flush_tlb_kernel_page(to);
+
+       asm(    "mcrr   p15, 0, %1, %0, c14\n"
+       "       mcrr    p15, 0, %1, %0, c5\n"
+           :
+           : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES)
+           : "cc");
+}
+#else
+#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+#endif
 
 static void __flush_dcache_page(struct address_space *mapping, struct page *page)
 {
@@ -36,6 +59,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
        if (!mapping)
                return;
 
+       /*
+        * This is a page cache page.  If we have a VIPT cache, we
+        * only need to do one flush - which would be at the relevant
+        * userspace colour, which is congruent with page->index.
+        */
+       if (cache_is_vipt()) {
+               if (cache_is_vipt_aliasing())
+                       flush_pfn_alias(page_to_pfn(page),
+                                       page->index << PAGE_CACHE_SHIFT);
+               return;
+       }
+
        /*
         * There are possible user space mappings of this page:
         * - VIVT cache: we need to also write back and invalidate all user
@@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
                        continue;
                offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
                flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page));
-               if (cache_is_vipt())
-                       break;
        }
        flush_dcache_mmap_unlock(mapping);
 }