aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-05-09 12:24:51 -0400
committerVineet Gupta <vgupta@synopsys.com>2013-05-09 12:29:46 -0400
commit4102b53392d6397d80b6e09b516517efacf7ea77 (patch)
treeb79aa87af1b3a1ff39b4a00b889cb806dfe32ae7
parent6ec18a81b22ab2b40df8424f2b5fc6be20ccad87 (diff)
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>
-rw-r--r--arch/arc/Kconfig4
-rw-r--r--arch/arc/include/asm/cacheflush.h53
-rw-r--r--arch/arc/include/asm/page.h16
-rw-r--r--arch/arc/include/asm/tlb.h11
-rw-r--r--arch/arc/mm/cache_arc700.c134
-rw-r--r--arch/arc/mm/tlb.c27
6 files changed, 223 insertions, 22 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 491ae7923b10..5917099470ea 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -182,6 +182,10 @@ config ARC_CACHE_PAGES
182 Note that Global I/D ENABLE + Per Page DISABLE works but corollary 182 Note that Global I/D ENABLE + Per Page DISABLE works but corollary
183 Global DISABLE + Per Page ENABLE won't work 183 Global DISABLE + Per Page ENABLE won't work
184 184
185config ARC_CACHE_VIPT_ALIASING
186 bool "Support VIPT Aliasing D$"
187 default n
188
185endif #ARC_CACHE 189endif #ARC_CACHE
186 190
187config ARC_HAS_ICCM 191config ARC_HAS_ICCM
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h
index ed820bcb745e..d692fbb17254 100644
--- a/arch/arc/include/asm/cacheflush.h
+++ b/arch/arc/include/asm/cacheflush.h
@@ -50,18 +50,55 @@ void dma_cache_wback(unsigned long start, unsigned long sz);
50#define flush_cache_vmap(start, end) flush_cache_all() 50#define flush_cache_vmap(start, end) flush_cache_all()
51#define flush_cache_vunmap(start, end) flush_cache_all() 51#define flush_cache_vunmap(start, end) flush_cache_all()
52 52
53/* 53#define flush_cache_dup_mm(mm) /* called on fork (VIVT only) */
54 * VM callbacks when entire/range of user-space V-P mappings are 54
55 * torn-down/get-invalidated 55#ifndef CONFIG_ARC_CACHE_VIPT_ALIASING
56 * 56
57 * Currently we don't support D$ aliasing configs for our VIPT caches
58 * NOPS for VIPT Cache with non-aliasing D$ configurations only
59 */
60#define flush_cache_dup_mm(mm) /* called on fork */
61#define flush_cache_mm(mm) /* called on munmap/exit */ 57#define flush_cache_mm(mm) /* called on munmap/exit */
62#define flush_cache_range(mm, u_vstart, u_vend) 58#define flush_cache_range(mm, u_vstart, u_vend)
63#define flush_cache_page(vma, u_vaddr, pfn) /* PF handling/COW-break */ 59#define flush_cache_page(vma, u_vaddr, pfn) /* PF handling/COW-break */
64 60
61#else /* VIPT aliasing dcache */
62
63/* To clear out stale userspace mappings */
64void flush_cache_mm(struct mm_struct *mm);
65void flush_cache_range(struct vm_area_struct *vma,
66 unsigned long start,unsigned long end);
67void flush_cache_page(struct vm_area_struct *vma,
68 unsigned long user_addr, unsigned long page);
69
70/*
71 * To make sure that userspace mapping is flushed to memory before
72 * get_user_pages() uses a kernel mapping to access the page
73 */
74#define ARCH_HAS_FLUSH_ANON_PAGE
75void flush_anon_page(struct vm_area_struct *vma,
76 struct page *page, unsigned long u_vaddr);
77
78#endif /* CONFIG_ARC_CACHE_VIPT_ALIASING */
79
80/*
81 * Simple wrapper over config option
82 * Bootup code ensures that hardware matches kernel configuration
83 */
84static inline int cache_is_vipt_aliasing(void)
85{
86#ifdef CONFIG_ARC_CACHE_VIPT_ALIASING
87 return 1;
88#else
89 return 0;
90#endif
91}
92
93#define CACHE_COLOR(addr) (((unsigned long)(addr) >> (PAGE_SHIFT)) & 3)
94
95/*
96 * checks if two addresses (after page aligning) index into same cache set
97 */
98#define addr_not_cache_congruent(addr1, addr2) \
99 cache_is_vipt_aliasing() ? \
100 (CACHE_COLOR(addr1) != CACHE_COLOR(addr2)) : 0 \
101
65#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ 102#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
66do { \ 103do { \
67 memcpy(dst, src, len); \ 104 memcpy(dst, src, len); \
diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
index bdf546104551..374a35514116 100644
--- a/arch/arc/include/asm/page.h
+++ b/arch/arc/include/asm/page.h
@@ -16,13 +16,27 @@
16#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) 16#define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
17#define free_user_page(page, addr) free_page(addr) 17#define free_user_page(page, addr) free_page(addr)
18 18
19/* TBD: for now don't worry about VIPT D$ aliasing */
20#define clear_page(paddr) memset((paddr), 0, PAGE_SIZE) 19#define clear_page(paddr) memset((paddr), 0, PAGE_SIZE)
21#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) 20#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
22 21
22#ifndef CONFIG_ARC_CACHE_VIPT_ALIASING
23
23#define clear_user_page(addr, vaddr, pg) clear_page(addr) 24#define clear_user_page(addr, vaddr, pg) clear_page(addr)
24#define copy_user_page(vto, vfrom, vaddr, pg) copy_page(vto, vfrom) 25#define copy_user_page(vto, vfrom, vaddr, pg) copy_page(vto, vfrom)
25 26
27#else /* VIPT aliasing dcache */
28
29struct vm_area_struct;
30struct page;
31
32#define __HAVE_ARCH_COPY_USER_HIGHPAGE
33
34void copy_user_highpage(struct page *to, struct page *from,
35 unsigned long u_vaddr, struct vm_area_struct *vma);
36void clear_user_page(void *to, unsigned long u_vaddr, struct page *page);
37
38#endif /* CONFIG_ARC_CACHE_VIPT_ALIASING */
39
26#undef STRICT_MM_TYPECHECKS 40#undef STRICT_MM_TYPECHECKS
27 41
28#ifdef STRICT_MM_TYPECHECKS 42#ifdef STRICT_MM_TYPECHECKS
diff --git a/arch/arc/include/asm/tlb.h b/arch/arc/include/asm/tlb.h
index fe91719866a5..85b6df839bd7 100644
--- a/arch/arc/include/asm/tlb.h
+++ b/arch/arc/include/asm/tlb.h
@@ -30,13 +30,20 @@ do { \
30/* 30/*
31 * This pair is called at time of munmap/exit to flush cache and TLB entries 31 * This pair is called at time of munmap/exit to flush cache and TLB entries
32 * for mappings being torn down. 32 * for mappings being torn down.
33 * 1) cache-flush part -implemented via tlb_start_vma( ) can be NOP (for now) 33 * 1) cache-flush part -implemented via tlb_start_vma( ) for VIPT aliasing D$
34 * as we don't support aliasing configs in our VIPT D$.
35 * 2) tlb-flush part - implemted via tlb_end_vma( ) flushes the TLB range 34 * 2) tlb-flush part - implemted via tlb_end_vma( ) flushes the TLB range
36 * 35 *
37 * Note, read http://lkml.org/lkml/2004/1/15/6 36 * Note, read http://lkml.org/lkml/2004/1/15/6
38 */ 37 */
38#ifndef CONFIG_ARC_CACHE_VIPT_ALIASING
39#define tlb_start_vma(tlb, vma) 39#define tlb_start_vma(tlb, vma)
40#else
41#define tlb_start_vma(tlb, vma) \
42do { \
43 if (!tlb->fullmm) \
44 flush_cache_range(vma, vma->vm_start, vma->vm_end); \
45} while(0)
46#endif
40 47
41#define tlb_end_vma(tlb, vma) \ 48#define tlb_end_vma(tlb, vma) \
42do { \ 49do { \
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c
index a9a37089257a..9887195379ef 100644
--- a/arch/arc/mm/cache_arc700.c
+++ b/arch/arc/mm/cache_arc700.c
@@ -68,6 +68,7 @@
68#include <linux/mmu_context.h> 68#include <linux/mmu_context.h>
69#include <linux/syscalls.h> 69#include <linux/syscalls.h>
70#include <linux/uaccess.h> 70#include <linux/uaccess.h>
71#include <linux/pagemap.h>
71#include <asm/cacheflush.h> 72#include <asm/cacheflush.h>
72#include <asm/cachectl.h> 73#include <asm/cachectl.h>
73#include <asm/setup.h> 74#include <asm/setup.h>
@@ -138,6 +139,7 @@ void __cpuinit arc_cache_init(void)
138 struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache; 139 struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
139 struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache; 140 struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache;
140 int way_pg_ratio = way_pg_ratio; 141 int way_pg_ratio = way_pg_ratio;
142 int dcache_does_alias;
141 char str[256]; 143 char str[256];
142 144
143 printk(arc_cache_mumbojumbo(0, str, sizeof(str))); 145 printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
@@ -184,9 +186,13 @@ chk_dc:
184 panic("Cache H/W doesn't match kernel Config"); 186 panic("Cache H/W doesn't match kernel Config");
185 } 187 }
186 188
189 dcache_does_alias = (dc->sz / ARC_DCACHE_WAYS) > PAGE_SIZE;
190
187 /* check for D-Cache aliasing */ 191 /* check for D-Cache aliasing */