From d9a6d25e750de3518a7b5b1ca92925121d8b6efe Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 26 Apr 2003 03:18:21 +0000 Subject: [PATCH] Redo R4600 workaround based on new information from PMC-Sierra. This improves interrupt latency significantly and fixes another problem with the old workaround so should be considered a critical upgrade for R4600 systems. Apply CPU workarounds only to those machines which were actually shipped with the affected processors. As for the R4600 the assumption is only IP22 was shipped with V1.7 and V2.0 processors and SNI RM200C only with V2.0 processors; for all other systems the workarounds are disabled. Control workarounds based on value of the preprocessor symbol, not based on it's definedness. Move R5432 workaround to the (hopefully ...) right place and copy it to those places where it was missing. --- arch/mips/kernel/entry.S | 6 ++-- arch/mips/mm/c-r4k.c | 81 +++++------------------------------------- arch/mips/mm/tlbex-r4k.S | 4 +-- arch/mips64/kernel/r4k_genex.S | 2 +- arch/mips64/mm/c-r4k.c | 81 +++++------------------------------------- arch/mips64/mm/tlb-glue-sb1.S | 2 +- arch/mips64/mm/tlbex-r4k.S | 2 +- drivers/char/sb1250_duart.c | 8 ++--- include/asm-mips/war.h | 50 +++++++++++++++++++++++--- include/asm-mips64/war.h | 50 +++++++++++++++++++++++--- 10 files changed, 120 insertions(+), 166 deletions(-) diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 21a6a8b02e7..5ec65839f4f 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -190,6 +190,9 @@ LEAF(spurious_interrupt) * and R4400 SC and MC versions. */ NESTED(except_vec3_generic, 0, sp) +#if R5432_CP0_INTERRUPT_WAR + mfc0 k0, CP0_INDEX +#endif mfc0 k1, CP0_CAUSE la k0, exception_handlers andi k1, k1, 0x7c @@ -204,9 +207,6 @@ LEAF(spurious_interrupt) .set push .set mips3 .set noat -#if defined(R5432_CP0_INTERRUPT_WAR) - mfc0 k0, CP0_INDEX -#endif mfc0 k1, CP0_CAUSE li k0, 31<<2 andi k1, k1, 0x7c diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 3be363028ba..879dc11f883 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -67,76 +67,20 @@ static struct bcache_ops no_sc_ops = { struct bcache_ops *bcops = &no_sc_ops; -#if defined(R4600_V1_HIT_CACHEOP_WAR) || defined(R4600_V2_HIT_CACHEOP_WAR) -#define R4600_HIT_CACHEOP_WAR_DECL \ - unsigned int prid = read_c0_prid() & 0xfff0; \ - unsigned long flags -#else -#define R4600_HIT_CACHEOP_WAR_DECL -#endif - -#ifdef R4600_V1_HIT_CACHEOP_WAR -#define R4600_V1_HIT_CACHEOP_WAR_PROLOG \ -do { \ - if (prid == 0x2010) { /* R4600 V1.7 */ \ - local_irq_save(flags); \ - __asm__ __volatile__("nop;nop;nop;nop"); \ - } \ -} while (0) -#define R4600_V1_HIT_CACHEOP_WAR_EPILOG \ -do { \ - if (prid == 0x2010) /* R4600 V1.7 */ \ - local_irq_restore(flags); \ -} while (0) - -#else - -#define R4600_V1_HIT_CACHEOP_WAR_DECL -#define R4600_V1_HIT_CACHEOP_WAR_PROLOG do { } while (0) -#define R4600_V1_HIT_CACHEOP_WAR_EPILOG do { } while (0) - -#endif - -#ifdef R4600_V2_HIT_CACHEOP_WAR - -#define R4600_V2_HIT_CACHEOP_WAR_PROLOG \ +#define R4600_HIT_CACHEOP_WAR_IMPL \ do { \ - if (prid == 0x2020) { /* R4600 V2.0 */ \ - local_irq_save(flags); \ + if (R4600_V2_HIT_CACHEOP_WAR && \ + (read_c0_prid() & 0xfff0) == 0x2020) { /* R4600 V2.0 */\ *(volatile unsigned long *)KSEG1; \ } \ -} while (0) -#define R4600_V2_HIT_CACHEOP_WAR_EPILOG \ -do { \ - if (prid == 0x2020) /* R4600 V2.0 */ \ - local_irq_restore(flags); \ -} while (0) - -#else - -#define R4600_V2_HIT_CACHEOP_WAR_DECL -#define R4600_V2_HIT_CACHEOP_WAR_PROLOG do { } while (0) -#define R4600_V2_HIT_CACHEOP_WAR_EPILOG do { } while (0) - -#endif - -#define R4600_HIT_CACHEOP_WAR_PROLOG \ -do { \ - R4600_V1_HIT_CACHEOP_WAR_PROLOG; \ - R4600_V2_HIT_CACHEOP_WAR_PROLOG; \ -} while (0) - -#define R4600_HIT_CACHEOP_WAR_EPILOG \ -do { \ - R4600_V1_HIT_CACHEOP_WAR_EPILOG; \ - R4600_V2_HIT_CACHEOP_WAR_EPILOG; \ + if (R4600_V1_HIT_CACHEOP_WAR) \ + __asm__ __volatile__("nop;nop;nop;nop"); \ } while (0) static void r4k_blast_dcache_page(unsigned long addr) { static void *l = &&init; unsigned long dc_lsize; - R4600_HIT_CACHEOP_WAR_DECL; goto *l; @@ -145,9 +89,8 @@ dc_16: return; dc_32: - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; blast_dcache32_page(addr); - R4600_HIT_CACHEOP_WAR_EPILOG; return; init: @@ -611,9 +554,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) r4k_blast_dcache(); } else { unsigned long dc_lsize = current_cpu_data.dcache.linesz; - R4600_HIT_CACHEOP_WAR_DECL; - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; a = addr & ~(dc_lsize - 1); end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { @@ -622,7 +564,6 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) break; a += dc_lsize; } - R4600_HIT_CACHEOP_WAR_EPILOG; } bc_wback_inv(addr, size); @@ -655,9 +596,8 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) r4k_blast_dcache(); } else { unsigned long dc_lsize = current_cpu_data.dcache.linesz; - R4600_HIT_CACHEOP_WAR_DECL; - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; a = addr & ~(dc_lsize - 1); end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { @@ -666,7 +606,6 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) break; a += dc_lsize; } - R4600_HIT_CACHEOP_WAR_EPILOG; } bc_inv(addr, size); @@ -682,12 +621,10 @@ static void r4k_flush_cache_sigtramp(unsigned long addr) { unsigned long ic_lsize = current_cpu_data.icache.linesz; unsigned long dc_lsize = current_cpu_data.dcache.linesz; - R4600_HIT_CACHEOP_WAR_DECL; - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); protected_flush_icache_line(addr & ~(ic_lsize - 1)); - R4600_HIT_CACHEOP_WAR_EPILOG; } static void r4k_flush_icache_all(void) diff --git a/arch/mips/mm/tlbex-r4k.S b/arch/mips/mm/tlbex-r4k.S index 8f2c8971fb6..ad188a6cda9 100644 --- a/arch/mips/mm/tlbex-r4k.S +++ b/arch/mips/mm/tlbex-r4k.S @@ -249,7 +249,7 @@ /* TLB refill, EXL == 0, SB1 with M3 errata handling version */ LEAF(except_vec0_sb1) -#ifdef BCM1250_M3_WAR +#if BCM1250_M3_WAR mfc0 k0, CP0_BADVADDR mfc0 k1, CP0_ENTRYHI xor k0, k1 @@ -438,7 +438,7 @@ .align 5 NESTED(handle_tlbl, PT_SIZE, sp) .set noat -#ifdef BCM1250_M3_WAR +#if BCM1250_M3_WAR mfc0 k0, CP0_BADVADDR mfc0 k1, CP0_ENTRYHI xor k0, k1 diff --git a/arch/mips64/kernel/r4k_genex.S b/arch/mips64/kernel/r4k_genex.S index 146ef81db8b..90c6914ab34 100644 --- a/arch/mips64/kernel/r4k_genex.S +++ b/arch/mips64/kernel/r4k_genex.S @@ -102,7 +102,7 @@ END(except_vec3_r4000) .set push .set noat NESTED(except_vec3_generic, 0, sp) -#if defined(R5432_CP0_INTERRUPT_WAR) +#if R5432_CP0_INTERRUPT_WAR mfc0 k0, CP0_INDEX #endif mfc0 k1, CP0_CAUSE diff --git a/arch/mips64/mm/c-r4k.c b/arch/mips64/mm/c-r4k.c index 3be363028ba..879dc11f883 100644 --- a/arch/mips64/mm/c-r4k.c +++ b/arch/mips64/mm/c-r4k.c @@ -67,76 +67,20 @@ static struct bcache_ops no_sc_ops = { struct bcache_ops *bcops = &no_sc_ops; -#if defined(R4600_V1_HIT_CACHEOP_WAR) || defined(R4600_V2_HIT_CACHEOP_WAR) -#define R4600_HIT_CACHEOP_WAR_DECL \ - unsigned int prid = read_c0_prid() & 0xfff0; \ - unsigned long flags -#else -#define R4600_HIT_CACHEOP_WAR_DECL -#endif - -#ifdef R4600_V1_HIT_CACHEOP_WAR -#define R4600_V1_HIT_CACHEOP_WAR_PROLOG \ -do { \ - if (prid == 0x2010) { /* R4600 V1.7 */ \ - local_irq_save(flags); \ - __asm__ __volatile__("nop;nop;nop;nop"); \ - } \ -} while (0) -#define R4600_V1_HIT_CACHEOP_WAR_EPILOG \ -do { \ - if (prid == 0x2010) /* R4600 V1.7 */ \ - local_irq_restore(flags); \ -} while (0) - -#else - -#define R4600_V1_HIT_CACHEOP_WAR_DECL -#define R4600_V1_HIT_CACHEOP_WAR_PROLOG do { } while (0) -#define R4600_V1_HIT_CACHEOP_WAR_EPILOG do { } while (0) - -#endif - -#ifdef R4600_V2_HIT_CACHEOP_WAR - -#define R4600_V2_HIT_CACHEOP_WAR_PROLOG \ +#define R4600_HIT_CACHEOP_WAR_IMPL \ do { \ - if (prid == 0x2020) { /* R4600 V2.0 */ \ - local_irq_save(flags); \ + if (R4600_V2_HIT_CACHEOP_WAR && \ + (read_c0_prid() & 0xfff0) == 0x2020) { /* R4600 V2.0 */\ *(volatile unsigned long *)KSEG1; \ } \ -} while (0) -#define R4600_V2_HIT_CACHEOP_WAR_EPILOG \ -do { \ - if (prid == 0x2020) /* R4600 V2.0 */ \ - local_irq_restore(flags); \ -} while (0) - -#else - -#define R4600_V2_HIT_CACHEOP_WAR_DECL -#define R4600_V2_HIT_CACHEOP_WAR_PROLOG do { } while (0) -#define R4600_V2_HIT_CACHEOP_WAR_EPILOG do { } while (0) - -#endif - -#define R4600_HIT_CACHEOP_WAR_PROLOG \ -do { \ - R4600_V1_HIT_CACHEOP_WAR_PROLOG; \ - R4600_V2_HIT_CACHEOP_WAR_PROLOG; \ -} while (0) - -#define R4600_HIT_CACHEOP_WAR_EPILOG \ -do { \ - R4600_V1_HIT_CACHEOP_WAR_EPILOG; \ - R4600_V2_HIT_CACHEOP_WAR_EPILOG; \ + if (R4600_V1_HIT_CACHEOP_WAR) \ + __asm__ __volatile__("nop;nop;nop;nop"); \ } while (0) static void r4k_blast_dcache_page(unsigned long addr) { static void *l = &&init; unsigned long dc_lsize; - R4600_HIT_CACHEOP_WAR_DECL; goto *l; @@ -145,9 +89,8 @@ dc_16: return; dc_32: - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; blast_dcache32_page(addr); - R4600_HIT_CACHEOP_WAR_EPILOG; return; init: @@ -611,9 +554,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) r4k_blast_dcache(); } else { unsigned long dc_lsize = current_cpu_data.dcache.linesz; - R4600_HIT_CACHEOP_WAR_DECL; - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; a = addr & ~(dc_lsize - 1); end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { @@ -622,7 +564,6 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) break; a += dc_lsize; } - R4600_HIT_CACHEOP_WAR_EPILOG; } bc_wback_inv(addr, size); @@ -655,9 +596,8 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) r4k_blast_dcache(); } else { unsigned long dc_lsize = current_cpu_data.dcache.linesz; - R4600_HIT_CACHEOP_WAR_DECL; - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; a = addr & ~(dc_lsize - 1); end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { @@ -666,7 +606,6 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) break; a += dc_lsize; } - R4600_HIT_CACHEOP_WAR_EPILOG; } bc_inv(addr, size); @@ -682,12 +621,10 @@ static void r4k_flush_cache_sigtramp(unsigned long addr) { unsigned long ic_lsize = current_cpu_data.icache.linesz; unsigned long dc_lsize = current_cpu_data.dcache.linesz; - R4600_HIT_CACHEOP_WAR_DECL; - R4600_HIT_CACHEOP_WAR_PROLOG; + R4600_HIT_CACHEOP_WAR_IMPL; protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); protected_flush_icache_line(addr & ~(ic_lsize - 1)); - R4600_HIT_CACHEOP_WAR_EPILOG; } static void r4k_flush_icache_all(void) diff --git a/arch/mips64/mm/tlb-glue-sb1.S b/arch/mips64/mm/tlb-glue-sb1.S index 22ffebdcdc8..3c236539f42 100644 --- a/arch/mips64/mm/tlb-glue-sb1.S +++ b/arch/mips64/mm/tlb-glue-sb1.S @@ -58,7 +58,7 @@ .endm tlb_handler xtlb_mod kmode 1 -#ifdef BCM1250_M3_WAR +#if BCM1250_M3_WAR tlb_handler_m3 xtlb_tlbl kmode 0 #else tlb_handler xtlb_tlbl kmode 0 diff --git a/arch/mips64/mm/tlbex-r4k.S b/arch/mips64/mm/tlbex-r4k.S index a9251b8ae49..5edd163e162 100644 --- a/arch/mips64/mm/tlbex-r4k.S +++ b/arch/mips64/mm/tlbex-r4k.S @@ -118,7 +118,7 @@ LEAF(except_vec1_r4k) END(except_vec1_r4k) LEAF(except_vec1_sb1) -#ifdef BCM1250_M3_WAR +#if BCM1250_M3_WAR dmfc0 k0, CP0_BADVADDR dmfc0 k1, CP0_ENTRYHI xor k0, k1 diff --git a/drivers/char/sb1250_duart.c b/drivers/char/sb1250_duart.c index 7cd5085eb3e..fd41f74251c 100644 --- a/drivers/char/sb1250_duart.c +++ b/drivers/char/sb1250_duart.c @@ -117,14 +117,14 @@ static uart_state_t uart_states[DUART_MAX_LINE]; * "write-mode-1 after any register access" is the accepted * workaround. */ -#ifdef SIBYTE_1956_WAR +#if SIBYTE_1956_WAR static unsigned int last_mode1[DUART_MAX_LINE]; #endif static inline u32 READ_SERCSR(u32 *addr, int line) { u32 val = csr_in32(addr); -#ifdef SIBYTE_1956_WAR +#if SIBYTE_1956_WAR csr_out32(last_mode1[line], uart_states[line].mode_1); #endif return val; @@ -133,7 +133,7 @@ static inline u32 READ_SERCSR(u32 *addr, int line) static inline void WRITE_SERCSR(u32 val, u32 *addr, int line) { csr_out32(val, addr); -#ifdef SIBYTE_1956_WAR +#if SIBYTE_1956_WAR csr_out32(last_mode1[line], uart_states[line].mode_1); #endif } @@ -895,7 +895,7 @@ static int ser_console_setup(struct console *cons, char *str) uart_state_t *port = uart_states + i; init_duart_port(port, i); -#ifdef SIBYTE_1956_WAR +#if SIBYTE_1956_WAR last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8; #endif WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8, diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h index 1ddc30e7c29..a62c7d63240 100644 --- a/include/asm-mips/war.h +++ b/include/asm-mips/war.h @@ -35,8 +35,9 @@ * nop * nop * cache Hit_Writeback_Invalidate_D + * + * #define R4600_V1_HIT_CACHEOP_WAR 1 */ -#define R4600_V1_HIT_CACHEOP_WAR /* @@ -49,8 +50,28 @@ * by a load instruction to an uncached address to empty the response buffer." * (Revision 2.0 device errata from IDT available on http://www.idt.com/ * in .pdf format.) + * + * #define R4600_V2_HIT_CACHEOP_WAR 1 + */ + +/* + * R4600 CPU modules for the Indy come with both V1.7 and V2.0 processors. + */ +#ifdef CONFIG_SGI_IP22 + +#define R4600_V1_HIT_CACHEOP_WAR 1 +#define R4600_V2_HIT_CACHEOP_WAR 1 + +#endif + +/* + * But the RM200C seems to have been shipped only with V2.0 R4600s */ -#define R4600_V2_HIT_CACHEOP_WAR +#ifdef CONFIG_SNI_RM200_PCI + +#define R4600_V2_HIT_CACHEOP_WAR 1 + +#endif #ifdef CONFIG_CPU_R5432 @@ -63,7 +84,7 @@ * first thing in the exception handler, which breaks one of the * pre-conditions for this problem. */ -#define R5432_CP0_INTERRUPT_WAR +#define R5432_CP0_INTERRUPT_WAR 1 #endif @@ -80,13 +101,32 @@ * will just return and take the exception again if the information was * found to be inconsistent. */ -#define BCM1250_M3_WAR +#define BCM1250_M3_WAR 1 /* * This is a DUART workaround related to glitches around register accesses */ -#define SIBYTE_1956_WAR +#define SIBYTE_1956_WAR 1 #endif +/* + * Workarounds default to off + */ +#ifndef R4600_V1_HIT_CACHEOP_WAR +#define R4600_V1_HIT_CACHEOP_WAR 0 +#endif +#ifndef R4600_V2_HIT_CACHEOP_WAR +#define R4600_V2_HIT_CACHEOP_WAR 0 +#endif +#ifndef R5432_CP0_INTERRUPT_WAR +#define R5432_CP0_INTERRUPT_WAR 0 +#endif +#ifndef BCM1250_M3_WAR +#define BCM1250_M3_WAR 0 +#endif +#ifndef SIBYTE_1956_WAR +#define SIBYTE_1956_WAR 0 +#endif + #endif /* _ASM_WAR_H */ diff --git a/include/asm-mips64/war.h b/include/asm-mips64/war.h index 1ddc30e7c29..a62c7d63240 100644 --- a/include/asm-mips64/war.h +++ b/include/asm-mips64/war.h @@ -35,8 +35,9 @@ * nop * nop * cache Hit_Writeback_Invalidate_D + * + * #define R4600_V1_HIT_CACHEOP_WAR 1 */ -#define R4600_V1_HIT_CACHEOP_WAR /* @@ -49,8 +50,28 @@ * by a load instruction to an uncached address to empty the response buffer." * (Revision 2.0 device errata from IDT available on http://www.idt.com/ * in .pdf format.) + * + * #define R4600_V2_HIT_CACHEOP_WAR 1 + */ + +/* + * R4600 CPU modules for the Indy come with both V1.7 and V2.0 processors. + */ +#ifdef CONFIG_SGI_IP22 + +#define R4600_V1_HIT_CACHEOP_WAR 1 +#define R4600_V2_HIT_CACHEOP_WAR 1 + +#endif + +/* + * But the RM200C seems to have been shipped only with V2.0 R4600s */ -#define R4600_V2_HIT_CACHEOP_WAR +#ifdef CONFIG_SNI_RM200_PCI + +#define R4600_V2_HIT_CACHEOP_WAR 1 + +#endif #ifdef CONFIG_CPU_R5432 @@ -63,7 +84,7 @@ * first thing in the exception handler, which breaks one of the * pre-conditions for this problem. */ -#define R5432_CP0_INTERRUPT_WAR +#define R5432_CP0_INTERRUPT_WAR 1 #endif @@ -80,13 +101,32 @@ * will just return and take the exception again if the information was * found to be inconsistent. */ -#define BCM1250_M3_WAR +#define BCM1250_M3_WAR 1 /* * This is a DUART workaround related to glitches around register accesses */ -#define SIBYTE_1956_WAR +#define SIBYTE_1956_WAR 1 #endif +/* + * Workarounds default to off + */ +#ifndef R4600_V1_HIT_CACHEOP_WAR +#define R4600_V1_HIT_CACHEOP_WAR 0 +#endif +#ifndef R4600_V2_HIT_CACHEOP_WAR +#define R4600_V2_HIT_CACHEOP_WAR 0 +#endif +#ifndef R5432_CP0_INTERRUPT_WAR +#define R5432_CP0_INTERRUPT_WAR 0 +#endif +#ifndef BCM1250_M3_WAR +#define BCM1250_M3_WAR 0 +#endif +#ifndef SIBYTE_1956_WAR +#define SIBYTE_1956_WAR 0 +#endif + #endif /* _ASM_WAR_H */ -- 2.11.4.GIT