On Wed, Jul 14, 2004 at 05:35:19PM +0100, Dominic Sweetman wrote: > This is fiddly, but not terribly difficult and should have a > negligible performance impact. > > Does that make sense? Am I now, having named the solution, > responsible for figuring out a patch (yeuch, I never wanted to be a > kernel programmer again...). No and yes - but here is a simpler solution. Below patch solves the problem and adds just 32 bytes of code but removes the special case for TX49/H2 entirely. Ralf arch/mips/mm/c-r4k.c | 59 -------------------------------------------- include/asm-mips/r4kcache.h | 18 ++++++++----- include/asm-mips/war.h | 14 ---------- 3 files changed, 13 insertions(+), 78 deletions(-) Index: arch/mips/mm/c-r4k.c =================================================================== RCS file: /home/cvs/linux/arch/mips/mm/c-r4k.c,v retrieving revision 1.88 diff -u -r1.88 c-r4k.c --- arch/mips/mm/c-r4k.c 16 Jul 2004 12:06:13 -0000 1.88 +++ arch/mips/mm/c-r4k.c 16 Jul 2004 12:17:05 -0000 @@ -96,16 +96,6 @@ r4k_blast_dcache = blast_dcache32; } -/* 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 blast_r4600_v1_icache32(void) { unsigned long flags; @@ -115,27 +105,6 @@ local_irq_restore(flags); } -static inline void tx49_blast_icache32(void) -{ - unsigned long start = INDEX_BASE; - 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 blast_icache32_r4600_v1_page_indexed(unsigned long page) { unsigned long flags; @@ -145,27 +114,6 @@ local_irq_restore(flags); } -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); static inline void r4k_blast_icache_page_setup(void) @@ -190,10 +138,7 @@ if (ic_lsize == 16) r4k_blast_icache_page_indexed = blast_icache16_page_indexed; else if (ic_lsize == 32) { - if (TX49XX_ICACHE_INDEX_INV_WAR) - r4k_blast_icache_page_indexed = - tx49_blast_icache32_page_indexed; - else if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x()) + if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x()) r4k_blast_icache_page_indexed = blast_icache32_r4600_v1_page_indexed; else @@ -214,8 +159,6 @@ else if (ic_lsize == 32) { if (R4600_V1_INDEX_ICACHEOP_WAR && cpu_is_r4600_v1_x()) r4k_blast_icache = blast_r4600_v1_icache32; - else if (TX49XX_ICACHE_INDEX_INV_WAR) - r4k_blast_icache = tx49_blast_icache32; else r4k_blast_icache = blast_icache32; } else if (ic_lsize == 64) Index: include/asm-mips/r4kcache.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/r4kcache.h,v retrieving revision 1.22 diff -u -r1.22 r4kcache.h --- include/asm-mips/r4kcache.h 5 Jan 2004 01:56:01 -0000 1.22 +++ include/asm-mips/r4kcache.h 16 Jul 2004 12:17:05 -0000 @@ -192,7 +192,7 @@ static inline void blast_icache16(void) { - unsigned long start = INDEX_BASE; + unsigned long start = (unsigned long) &&body + 0x100; 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 << @@ -200,8 +200,10 @@ unsigned long ws, addr; for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start; addr < end; addr += 0x200) + for (addr = start; addr < end; addr += 0x200) { +body: cache16_unroll32(addr|ws,Index_Invalidate_I); + } } static inline void blast_icache16_page(unsigned long page) @@ -335,7 +337,7 @@ static inline void blast_icache32(void) { - unsigned long start = INDEX_BASE; + unsigned long start = (unsigned long) &&body + 0x200; 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 << @@ -343,8 +345,10 @@ unsigned long ws, addr; for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start; addr < end; addr += 0x400) + for (addr = start; addr < end; addr += 0x400) { +body: cache32_unroll32(addr|ws,Index_Invalidate_I); + } } static inline void blast_icache32_page(unsigned long page) @@ -439,7 +443,7 @@ static inline void blast_icache64(void) { - unsigned long start = INDEX_BASE; + unsigned long start = (unsigned long) &&body + 0x400; 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 << @@ -447,8 +451,10 @@ unsigned long ws, addr; for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start; addr < end; addr += 0x800) + for (addr = start; addr < end; addr += 0x800) { +body: cache64_unroll32(addr|ws,Index_Invalidate_I); + } } static inline void blast_icache64_page(unsigned long page) Index: include/asm-mips/war.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/war.h,v retrieving revision 1.18 diff -u -r1.18 war.h --- include/asm-mips/war.h 5 Mar 2004 02:47:19 -0000 1.18 +++ include/asm-mips/war.h 16 Jul 2004 12:17:05 -0000 @@ -158,17 +158,6 @@ #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 - -/* * On the RM9000 there is a problem which makes the CreateDirtyExclusive * cache operation unusable on SMP systems. */ @@ -203,9 +192,6 @@ #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 #ifndef RM9000_CDEX_SMP_WAR #define RM9000_CDEX_SMP_WAR 0 #endif