diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-mips/bugs.h | 25 | ||||
-rw-r--r-- | include/asm-mips/delay.h | 12 | ||||
-rw-r--r-- | include/asm-mips/war.h | 62 |
3 files changed, 97 insertions, 2 deletions
diff --git a/include/asm-mips/bugs.h b/include/asm-mips/bugs.h index 0d7f9c1f5546..9dc10df32078 100644 --- a/include/asm-mips/bugs.h +++ b/include/asm-mips/bugs.h @@ -1,19 +1,34 @@ /* * This is included by init/main.c to check for architecture-dependent bugs. * + * Copyright (C) 2007 Maciej W. Rozycki + * * Needs: * void check_bugs(void); */ #ifndef _ASM_BUGS_H #define _ASM_BUGS_H +#include <linux/bug.h> #include <linux/delay.h> + #include <asm/cpu.h> #include <asm/cpu-info.h> +extern int daddiu_bug; + +extern void check_bugs64_early(void); + extern void check_bugs32(void); extern void check_bugs64(void); +static inline void check_bugs_early(void) +{ +#ifdef CONFIG_64BIT + check_bugs64_early(); +#endif +} + static inline void check_bugs(void) { unsigned int cpu = smp_processor_id(); @@ -25,4 +40,14 @@ static inline void check_bugs(void) #endif } +static inline int r4k_daddiu_bug(void) +{ +#ifdef CONFIG_64BIT + WARN_ON(daddiu_bug < 0); + return daddiu_bug != 0; +#else + return 0; +#endif +} + #endif /* _ASM_BUGS_H */ diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index fab32131e9b4..de5105d05f1e 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h @@ -6,13 +6,16 @@ * Copyright (C) 1994 by Waldorf Electronics * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2007 Maciej W. Rozycki */ #ifndef _ASM_DELAY_H #define _ASM_DELAY_H #include <linux/param.h> #include <linux/smp.h> + #include <asm/compiler.h> +#include <asm/war.h> static inline void __delay(unsigned long loops) { @@ -50,7 +53,7 @@ static inline void __delay(unsigned long loops) static inline void __udelay(unsigned long usecs, unsigned long lpj) { - unsigned long lo; + unsigned long hi, lo; /* * The rates of 128 is rounded wrongly by the catchall case @@ -70,11 +73,16 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj) : "=h" (usecs), "=l" (lo) : "r" (usecs), "r" (lpj) : GCC_REG_ACCUM); - else if (sizeof(long) == 8) + else if (sizeof(long) == 8 && !R4000_WAR) __asm__("dmultu\t%2, %3" : "=h" (usecs), "=l" (lo) : "r" (usecs), "r" (lpj) : GCC_REG_ACCUM); + else if (sizeof(long) == 8 && R4000_WAR) + __asm__("dmultu\t%3, %4\n\tmfhi\t%0" + : "=r" (usecs), "=h" (hi), "=l" (lo) + : "r" (usecs), "r" (lpj) + : GCC_REG_ACCUM); __delay(usecs); } diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h index d2808edfd4e9..22361d5e3bf0 100644 --- a/include/asm-mips/war.h +++ b/include/asm-mips/war.h @@ -4,6 +4,7 @@ * for more details. * * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + * Copyright (C) 2007 Maciej W. Rozycki */ #ifndef _ASM_WAR_H #define _ASM_WAR_H @@ -11,6 +12,67 @@ #include <war.h> /* + * Work around certain R4000 CPU errata (as implemented by GCC): + * + * - A double-word or a variable shift may give an incorrect result + * if executed immediately after starting an integer division: + * "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0", + * erratum #28 + * "MIPS R4000MC Errata, Processor Revision 2.2 and 3.0", erratum + * #19 + * + * - A double-word or a variable shift may give an incorrect result + * if executed while an integer multiplication is in progress: + * "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0", + * errata #16 & #28 + * + * - An integer division may give an incorrect result if started in + * a delay slot of a taken branch or a jump: + * "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0", + * erratum #52 + */ +#ifdef CONFIG_CPU_R4000_WORKAROUNDS +#define R4000_WAR 1 +#else +#define R4000_WAR 0 +#endif + +/* + * Work around certain R4400 CPU errata (as implemented by GCC): + * + * - A double-word or a variable shift may give an incorrect result + * if executed immediately after starting an integer division: + * "MIPS R4400MC Errata, Processor Revision 1.0", erratum #10 + * "MIPS R4400MC Errata, Processor Revision 2.0 & 3.0", erratum #4 + */ +#ifdef CONFIG_CPU_R4400_WORKAROUNDS +#define R4400_WAR 1 +#else +#define R4400_WAR 0 +#endif + +/* + * Work around the "daddi" and "daddiu" CPU errata: + * + * - The `daddi' instruction fails to trap on overflow. + * "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0", + * erratum #23 + * + * - The `daddiu' instruction can produce an incorrect result. + * "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0", + * erratum #41 + * "MIPS R4000MC Errata, Processor Revision 2.2 and 3.0", erratum + * #15 + * "MIPS R4400PC/SC Errata, Processor Revision 1.0", erratum #7 + * "MIPS R4400MC Errata, Processor Revision 1.0", erratum #5 + */ +#ifdef CONFIG_CPU_DADDI_WORKAROUNDS +#define DADDI_WAR 1 +#else +#define DADDI_WAR 0 +#endif + +/* * Another R4600 erratum. Due to the lack of errata information the exact * technical details aren't known. I've experimentally found that disabling * interrupts during indexed I-cache flushes seems to be sufficient to deal |