diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-04-10 20:52:08 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-06-12 06:03:45 -0400 |
commit | 5d89137a17ca804ee60077f5d4ad8d7ca60f0614 (patch) | |
tree | e6445551fdb86ffdbb3da14b8ab91d0e05c94612 /arch/blackfin/include/asm | |
parent | f82e0a0c67621df83458753aef580a3508d5428e (diff) |
Blackfin: fix data cache flushing when doing icache flushing
Make sure we flush all data caches and their write buffers before flushing
icache, otherwise random edge cases could crop up where stale data is read
into icache from external memory. As fallout, punt the combined icache +
dcache flush function since we cannot safely do them back to back -- the
SSYNC is needed between the dcache flush and the icache flush.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/include/asm')
-rw-r--r-- | arch/blackfin/include/asm/cacheflush.h | 35 |
1 files changed, 16 insertions, 19 deletions
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h index 1b040f5b4fe..d7726ab486f 100644 --- a/arch/blackfin/include/asm/cacheflush.h +++ b/arch/blackfin/include/asm/cacheflush.h @@ -30,7 +30,8 @@ #ifndef _BLACKFIN_CACHEFLUSH_H #define _BLACKFIN_CACHEFLUSH_H -extern void blackfin_icache_dcache_flush_range(unsigned long start_address, unsigned long end_address); +#include <asm/blackfin.h> /* for SSYNC() */ + extern void blackfin_icache_flush_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); @@ -54,32 +55,28 @@ extern void blackfin_invalidate_entire_dcache(void); static inline void flush_icache_range(unsigned start, unsigned end) { -#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE) - -# if defined(CONFIG_BFIN_WT) - blackfin_icache_flush_range((start), (end)); - flush_icache_range_others(start, end); -# else - blackfin_icache_dcache_flush_range((start), (end)); -# endif - -#else +#if defined(CONFIG_BFIN_WB) + blackfin_dcache_flush_range(start, end); +#endif -# if defined(CONFIG_BFIN_ICACHE) - blackfin_icache_flush_range((start), (end)); + /* Make sure all write buffers in the data side of the core + * are flushed before trying to invalidate the icache. This + * needs to be after the data flush and before the icache + * flush so that the SSYNC does the right thing in preventing + * the instruction prefetcher from hitting things in cached + * memory at the wrong time -- it runs much further ahead than + * the pipeline. + */ + SSYNC(); +#if defined(CONFIG_BFIN_ICACHE) + blackfin_icache_flush_range(start, end); flush_icache_range_others(start, end); -# endif -# if defined(CONFIG_BFIN_DCACHE) - blackfin_dcache_flush_range((start), (end)); -# endif - #endif } #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ do { memcpy(dst, src, len); \ flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \ - flush_icache_range_others((unsigned long) (dst), (unsigned long) (dst) + (len));\ } while (0) #define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) |