aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-12-03 12:04:11 -0500
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-12-07 08:54:47 -0500
commit68ca3e537f12044af05a653fa9d28b4fe80117e8 (patch)
treea8a2e4f9e2e18e031739a8af1e8e3d08af1770ac
parent2507bc1338e43eadfef5b604d2c47e4f8180718f (diff)
[AVR32] Fix copy_to_user_page() breakage
The current implementation of copy_to_user_page() gives "vaddr" to the cache instruction when trying to sync the icache with the dcache. If vaddr does not exist in the TLB, the CPU will silently abort the operation, which may result in the caches staying out of sync. To fix this, pass the "dst" parameter to flush_icache_range() instead -- we know this is valid because we just wrote to it. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
-rw-r--r--arch/avr32/mm/cache.c20
-rw-r--r--include/asm-avr32/cacheflush.h19
2 files changed, 20 insertions, 19 deletions
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index c1233c615e67..15a4e5e142c1 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -122,16 +122,6 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page)
122 } 122 }
123} 123}
124 124
125/*
126 * This one is used by copy_to_user_page()
127 */
128void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
129 unsigned long addr, int len)
130{
131 if (vma->vm_flags & VM_EXEC)
132 flush_icache_range(addr, addr + len);
133}
134
135asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len) 125asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
136{ 126{
137 int ret; 127 int ret;
@@ -159,3 +149,13 @@ asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
159out: 149out:
160 return ret; 150 return ret;
161} 151}
152
153void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
154 unsigned long vaddr, void *dst, const void *src,
155 unsigned long len)
156{
157 memcpy(dst, src, len);
158 if (vma->vm_flags & VM_EXEC)
159 flush_icache_range((unsigned long)dst,
160 (unsigned long)dst + len);
161}
diff --git a/include/asm-avr32/cacheflush.h b/include/asm-avr32/cacheflush.h
index dfaaa88cd412..670674749b20 100644
--- a/include/asm-avr32/cacheflush.h
+++ b/include/asm-avr32/cacheflush.h
@@ -116,15 +116,16 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
116 * flush with all configurations. 116 * flush with all configurations.
117 */ 117 */
118extern void flush_icache_range(unsigned long start, unsigned long end); 118extern void flush_icache_range(unsigned long start, unsigned long end);
119extern void flush_icache_user_range(struct vm_area_struct *vma,
120 struct page *page,
121 unsigned long addr, int len);
122 119
123#define copy_to_user_page(vma, page, vaddr, dst, src, len) do { \ 120extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
124 memcpy(dst, src, len); \ 121 unsigned long vaddr, void *dst, const void *src,
125 flush_icache_user_range(vma, page, vaddr, len); \ 122 unsigned long len);
126} while(0) 123
127#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ 124static inline void copy_from_user_page(struct vm_area_struct *vma,
128 memcpy(dst, src, len) 125 struct page *page, unsigned long vaddr, void *dst,
126 const void *src, unsigned long len)
127{
128 memcpy(dst, src, len);
129}
129 130
130#endif /* __ASM_AVR32_CACHEFLUSH_H */ 131#endif /* __ASM_AVR32_CACHEFLUSH_H */