diff options
-rw-r--r-- | arch/arm/mm/flush.c | 39 | ||||
-rw-r--r-- | include/asm-arm/cacheflush.h | 10 |
2 files changed, 49 insertions, 0 deletions
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 628348c9f6c5..9df507d36e0b 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
@@ -202,3 +202,42 @@ void flush_dcache_page(struct page *page) | |||
202 | } | 202 | } |
203 | } | 203 | } |
204 | EXPORT_SYMBOL(flush_dcache_page); | 204 | EXPORT_SYMBOL(flush_dcache_page); |
205 | |||
206 | /* | ||
207 | * Flush an anonymous page so that users of get_user_pages() | ||
208 | * can safely access the data. The expected sequence is: | ||
209 | * | ||
210 | * get_user_pages() | ||
211 | * -> flush_anon_page | ||
212 | * memcpy() to/from page | ||
213 | * if written to page, flush_dcache_page() | ||
214 | */ | ||
215 | void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) | ||
216 | { | ||
217 | unsigned long pfn; | ||
218 | |||
219 | /* VIPT non-aliasing caches need do nothing */ | ||
220 | if (cache_is_vipt_nonaliasing()) | ||
221 | return; | ||
222 | |||
223 | /* | ||
224 | * Write back and invalidate userspace mapping. | ||
225 | */ | ||
226 | pfn = page_to_pfn(page); | ||
227 | if (cache_is_vivt()) { | ||
228 | flush_cache_page(vma, vmaddr, pfn); | ||
229 | } else { | ||
230 | /* | ||
231 | * For aliasing VIPT, we can flush an alias of the | ||
232 | * userspace address only. | ||
233 | */ | ||
234 | flush_pfn_alias(pfn, vmaddr); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Invalidate kernel mapping. No data should be contained | ||
239 | * in this mapping of the page. FIXME: this is overkill | ||
240 | * since we actually ask for a write-back and invalidate. | ||
241 | */ | ||
242 | __cpuc_flush_dcache_page(page_address(page)); | ||
243 | } | ||
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index d51049522cd0..5f531ea03059 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h | |||
@@ -357,6 +357,16 @@ extern void flush_dcache_page(struct page *); | |||
357 | 357 | ||
358 | extern void __flush_dcache_page(struct address_space *mapping, struct page *page); | 358 | extern void __flush_dcache_page(struct address_space *mapping, struct page *page); |
359 | 359 | ||
360 | #define ARCH_HAS_FLUSH_ANON_PAGE | ||
361 | static inline void flush_anon_page(struct vm_area_struct *vma, | ||
362 | struct page *page, unsigned long vmaddr) | ||
363 | { | ||
364 | extern void __flush_anon_page(struct vm_area_struct *vma, | ||
365 | struct page *, unsigned long); | ||
366 | if (PageAnon(page)) | ||
367 | __flush_anon_page(vma, page, vmaddr); | ||
368 | } | ||
369 | |||
360 | #define flush_dcache_mmap_lock(mapping) \ | 370 | #define flush_dcache_mmap_lock(mapping) \ |
361 | write_lock_irq(&(mapping)->tree_lock) | 371 | write_lock_irq(&(mapping)->tree_lock) |
362 | #define flush_dcache_mmap_unlock(mapping) \ | 372 | #define flush_dcache_mmap_unlock(mapping) \ |