>>>>> 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
|