aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm/flush.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /arch/arm/mm/flush.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/arm/mm/flush.c')
-rw-r--r--arch/arm/mm/flush.c109
1 files changed, 79 insertions, 30 deletions
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 7f294f307c83..c6844cb9b508 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -13,6 +13,8 @@
13 13
14#include <asm/cacheflush.h> 14#include <asm/cacheflush.h>
15#include <asm/cachetype.h> 15#include <asm/cachetype.h>
16#include <asm/highmem.h>
17#include <asm/smp_plat.h>
16#include <asm/system.h> 18#include <asm/system.h>
17#include <asm/tlbflush.h> 19#include <asm/tlbflush.h>
18 20
@@ -35,14 +37,12 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
35 : 37 :
36 : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero) 38 : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
37 : "cc"); 39 : "cc");
38 __flush_icache_all();
39} 40}
40 41
41void flush_cache_mm(struct mm_struct *mm) 42void flush_cache_mm(struct mm_struct *mm)
42{ 43{
43 if (cache_is_vivt()) { 44 if (cache_is_vivt()) {
44 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) 45 vivt_flush_cache_mm(mm);
45 __cpuc_flush_user_all();
46 return; 46 return;
47 } 47 }
48 48
@@ -52,16 +52,13 @@ void flush_cache_mm(struct mm_struct *mm)
52 : 52 :
53 : "r" (0) 53 : "r" (0)
54 : "cc"); 54 : "cc");
55 __flush_icache_all();
56 } 55 }
57} 56}
58 57
59void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) 58void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
60{ 59{
61 if (cache_is_vivt()) { 60 if (cache_is_vivt()) {
62 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) 61 vivt_flush_cache_range(vma, start, end);
63 __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
64 vma->vm_flags);
65 return; 62 return;
66 } 63 }
67 64
@@ -71,27 +68,41 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
71 : 68 :
72 : "r" (0) 69 : "r" (0)
73 : "cc"); 70 : "cc");
74 __flush_icache_all();
75 } 71 }
72
73 if (vma->vm_flags & VM_EXEC)
74 __flush_icache_all();
76} 75}
77 76
78void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn) 77void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
79{ 78{
80 if (cache_is_vivt()) { 79 if (cache_is_vivt()) {
81 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { 80 vivt_flush_cache_page(vma, user_addr, pfn);
82 unsigned long addr = user_addr & PAGE_MASK;
83 __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
84 }
85 return; 81 return;
86 } 82 }
87 83
88 if (cache_is_vipt_aliasing()) 84 if (cache_is_vipt_aliasing()) {
89 flush_pfn_alias(pfn, user_addr); 85 flush_pfn_alias(pfn, user_addr);
86 __flush_icache_all();
87 }
88
89 if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
90 __flush_icache_all();
90} 91}
92#else
93#define flush_pfn_alias(pfn,vaddr) do { } while (0)
94#endif
91 95
96#ifdef CONFIG_SMP
97static void flush_ptrace_access_other(void *args)
98{
99 __flush_icache_all();
100}
101#endif
102
103static
92void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, 104void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
93 unsigned long uaddr, void *kaddr, 105 unsigned long uaddr, void *kaddr, unsigned long len)
94 unsigned long len, int write)
95{ 106{
96 if (cache_is_vivt()) { 107 if (cache_is_vivt()) {
97 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { 108 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
@@ -103,20 +114,42 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
103 114
104 if (cache_is_vipt_aliasing()) { 115 if (cache_is_vipt_aliasing()) {
105 flush_pfn_alias(page_to_pfn(page), uaddr); 116 flush_pfn_alias(page_to_pfn(page), uaddr);
117 __flush_icache_all();
106 return; 118 return;
107 } 119 }
108 120
109 /* VIPT non-aliasing cache */ 121 /* VIPT non-aliasing cache */
110 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)) && 122 if (vma->vm_flags & VM_EXEC) {
111 vma->vm_flags & VM_EXEC) {
112 unsigned long addr = (unsigned long)kaddr; 123 unsigned long addr = (unsigned long)kaddr;
113 /* only flushing the kernel mapping on non-aliasing VIPT */
114 __cpuc_coherent_kern_range(addr, addr + len); 124 __cpuc_coherent_kern_range(addr, addr + len);
125#ifdef CONFIG_SMP
126 if (cache_ops_need_broadcast())
127 smp_call_function(flush_ptrace_access_other,
128 NULL, 1);
129#endif
115 } 130 }
116} 131}
117#else 132
118#define flush_pfn_alias(pfn,vaddr) do { } while (0) 133/*
134 * Copy user data from/to a page which is mapped into a different
135 * processes address space. Really, we want to allow our "user
136 * space" model to handle this.
137 *
138 * Note that this code needs to run on the current CPU.
139 */
140void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
141 unsigned long uaddr, void *dst, const void *src,
142 unsigned long len)
143{
144#ifdef CONFIG_SMP
145 preempt_disable();
146#endif
147 memcpy(dst, src, len);
148 flush_ptrace_access(vma, page, uaddr, dst, len);
149#ifdef CONFIG_SMP
150 preempt_enable();
119#endif 151#endif
152}
120 153
121void __flush_dcache_page(struct address_space *mapping, struct page *page) 154void __flush_dcache_page(struct address_space *mapping, struct page *page)
122{ 155{
@@ -125,14 +158,20 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
125 * page. This ensures that data in the physical page is mutually 158 * page. This ensures that data in the physical page is mutually
126 * coherent with the kernels mapping. 159 * coherent with the kernels mapping.
127 */ 160 */
128#ifdef CONFIG_HIGHMEM 161 if (!PageHighMem(page)) {
129 /* 162 __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
130 * kmap_atomic() doesn't set the page virtual address, and 163 } else {
131 * kunmap_atomic() takes care of cache flushing already. 164 void *addr = kmap_high_get(page);
132 */ 165 if (addr) {
133 if (page_address(page)) 166 __cpuc_flush_dcache_area(addr, PAGE_SIZE);
134#endif 167 kunmap_high(page);
135 __cpuc_flush_dcache_page(page_address(page)); 168 } else if (cache_is_vipt()) {
169 pte_t saved_pte;
170 addr = kmap_high_l1_vipt(page, &saved_pte);
171 __cpuc_flush_dcache_area(addr, PAGE_SIZE);
172 kunmap_high_l1_vipt(page, saved_pte);
173 }
174 }
136 175
137 /* 176 /*
138 * If this is a page cache page, and we have an aliasing VIPT cache, 177 * If this is a page cache page, and we have an aliasing VIPT cache,
@@ -196,7 +235,16 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p
196 */ 235 */
197void flush_dcache_page(struct page *page) 236void flush_dcache_page(struct page *page)
198{ 237{
199 struct address_space *mapping = page_mapping(page); 238 struct address_space *mapping;
239
240 /*
241 * The zero page is never written to, so never has any dirty
242 * cache lines, and therefore never needs to be flushed.
243 */
244 if (page == ZERO_PAGE(0))
245 return;
246
247 mapping = page_mapping(page);
200 248
201#ifndef CONFIG_SMP 249#ifndef CONFIG_SMP
202 if (!PageHighMem(page) && mapping && !mapping_mapped(mapping)) 250 if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
@@ -242,6 +290,7 @@ void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned l
242 * userspace address only. 290 * userspace address only.
243 */ 291 */
244 flush_pfn_alias(pfn, vmaddr); 292 flush_pfn_alias(pfn, vmaddr);
293 __flush_icache_all();
245 } 294 }
246 295
247 /* 296 /*
@@ -249,5 +298,5 @@ void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned l
249 * in this mapping of the page. FIXME: this is overkill 298 * in this mapping of the page. FIXME: this is overkill
250 * since we actually ask for a write-back and invalidate. 299 * since we actually ask for a write-back and invalidate.
251 */ 300 */
252 __cpuc_flush_dcache_page(page_address(page)); 301 __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
253} 302}