>>>>> On Mon, 14 Apr 2003 12:35:14 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> said: anemo> TOSHIBA_ICACHE_WAR can be removed. This workaround is not anemo> needed if kernel does not modify the cache codes itself in anemo> run-time. anemo> When I wrote c-tx49.c I blindly followed the statement in anemo> TX49/H2 manual's statement. ("If the instruction (i.e. CACHE) anemo> is issued for the line which this instruction itself exists, anemo> the following operation is not guaranteed.") Now I know this anemo> warning is only for self-modified code. There must be no anemo> problem if the codes is not modified in run-time. So please anemo> remove all TOSHIBA_ICACHE_WAR stuff and make c-r4k.c more anemo> clean. Very sorry, I was wrong (unfortunately). TX49 does NOT work correctly if CACHE instruction was issued for the line which the code exists (even if the code was never modified in run-time). I implemented the workaround again in another way (put the flushing loop on an aligned place and do two phase flushing). I did not use "#ifdef" in c-r4k.c since gcc will be omit unnecessary codes automatically. This is a patch against 2.4 branch (mips version only. mips64 is same). This also can be applied for 2.6 branch. Please apply. diff -ur linux-mips-cvs/arch/mips/mm/c-r4k.c linux.new/arch/mips/mm/c-r4k.c --- linux-mips-cvs/arch/mips/mm/c-r4k.c Fri Aug 1 22:03:00 2003 +++ linux.new/arch/mips/mm/c-r4k.c Fri Aug 1 22:08:52 2003 @@ -149,6 +149,58 @@ goto *l; } +/* force code alignment (used for TX49XX_ICACHE_INDEX_INV_WAR) */ +#define JUMP_TO_ALIGN(order) \ + __asm__ __volatile__( \ + "b\t1f\n\t" \ + ".align\t" #order "\n\t" \ + "1:\n\t" \ + ) +#define CACHE32_UNROLL32_ALIGN JUMP_TO_ALIGN(10) /* 32 * 32 = 1024 */ +#define CACHE32_UNROLL32_ALIGN2 JUMP_TO_ALIGN(11) + +static inline void tx49_blast_icache32(void) +{ + unsigned long start = KSEG0; + unsigned long end = start + current_cpu_data.icache.waysize; + unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; + unsigned long ws_end = current_cpu_data.icache.ways << + current_cpu_data.icache.waybit; + unsigned long ws, addr; + + CACHE32_UNROLL32_ALIGN2; + /* I'm in even chunk. blast odd chunks */ + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start + 0x400; addr < end; addr += 0x400 * 2) + cache32_unroll32(addr|ws,Index_Invalidate_I); + CACHE32_UNROLL32_ALIGN; + /* I'm in odd chunk. blast even chunks */ + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start; addr < end; addr += 0x400 * 2) + cache32_unroll32(addr|ws,Index_Invalidate_I); +} + +static inline void tx49_blast_icache32_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = start + PAGE_SIZE; + unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; + unsigned long ws_end = current_cpu_data.icache.ways << + current_cpu_data.icache.waybit; + unsigned long ws, addr; + + CACHE32_UNROLL32_ALIGN2; + /* I'm in even chunk. blast odd chunks */ + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start + 0x400; addr < end; addr += 0x400 * 2) + cache32_unroll32(addr|ws,Index_Invalidate_I); + CACHE32_UNROLL32_ALIGN; + /* I'm in odd chunk. blast even chunks */ + for (ws = 0; ws < ws_end; ws += ws_inc) + for (addr = start; addr < end; addr += 0x400 * 2) + cache32_unroll32(addr|ws,Index_Invalidate_I); +} + static void r4k_blast_icache_page(unsigned long addr) { unsigned long ic_lsize = current_cpu_data.icache.linesz; @@ -197,11 +249,18 @@ blast_icache64_page_indexed(addr); return; +ic_32_tx49: + tx49_blast_icache32_page_indexed(addr); + return; + init: if (ic_lsize == 16) l = &&ic_16; else if (ic_lsize == 32) - l = &&ic_32; + if (TX49XX_ICACHE_INDEX_INV_WAR) + l = &&ic_32_tx49; + else + l = &&ic_32; else if (ic_lsize == 64) l = &&ic_64; goto *l; @@ -226,11 +285,18 @@ blast_icache64(); return; +ic_32_tx49: + tx49_blast_icache32(); + return; + init: if (ic_lsize == 16) l = &&ic_16; else if (ic_lsize == 32) - l = &&ic_32; + if (TX49XX_ICACHE_INDEX_INV_WAR) + l = &&ic_32_tx49; + else + l = &&ic_32; else if (ic_lsize == 64) l = &&ic_64; goto *l; diff -ur linux-mips-cvs/include/asm-mips/war.h linux.new/include/asm-mips/war.h --- linux-mips-cvs/include/asm-mips/war.h Fri Aug 1 22:01:30 2003 +++ linux.new/include/asm-mips/war.h Fri Aug 1 21:53:39 2003 @@ -148,6 +148,17 @@ #endif /* + * From TX49/H2 manual: "If the instruction (i.e. CACHE) is issued for + * the line which this instruction itself exists, the following + * operation is not guaranteed." + * + * Workaround: do two phase flushing for Index_Invalidate_I + */ +#ifdef CONFIG_CPU_TX49XX +#define TX49XX_ICACHE_INDEX_INV_WAR 1 +#endif + +/* * Workarounds default to off */ #ifndef R4600_V1_HIT_CACHEOP_WAR @@ -171,5 +182,8 @@ #ifndef MIPS_CACHE_SYNC_WAR #define MIPS_CACHE_SYNC_WAR 0 #endif +#ifndef TX49XX_ICACHE_INDEX_INV_WAR +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#endif #endif /* _ASM_WAR_H */ --- Atsushi Nemoto