[MIPS] R4000/R4400 errata workarounds
This is the gereric part of R4000/R4400 errata workarounds. They include compiler and assembler support as well as some source code modifications to address the problems with some combinations of multiply/divide+shift instructions as well as the daddi and daddiu instructions. Changes included are as follows: 1. New Kconfig options to select workarounds by platforms as necessary. 2. Arch top-level Makefile to pass necessary options to the compiler; also incompatible configurations are detected (-mno-sym32 unsupported as horribly intrusive for little gain). 3. Bug detection updated and shuffled -- the multiply/divide+shift problem is lethal enough that if not worked around it makes the kernel crash in time_init() because of a division by zero; the daddiu erratum might also trigger early potentially, though I have not observed it. On the other hand the daddi detection code requires the exception subsystem to have been initialised (and is there mainly for information). 4. r4k_daddiu_bug() added so that the existence of the erratum can be queried by code at the run time as necessary; useful for generated code like TLB fault and copy/clear page handlers. 5. __udelay() updated as it uses multiplication in inline assembly. Note that -mdaddi requires modified toolchain (which has been maintained by myself and available from my site for ~4years now -- versions covered are GCC 2.95.4 - 4.1.2 and binutils from 2.13 onwards). The -mfix-r4000 and -mfix-r4400 have been standard for a while though. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
committed by
Ralf Baechle
parent
2b22c034d0
commit
20d60d9973
@@ -18,6 +18,15 @@
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
static char bug64hit[] __initdata =
|
||||
"reliable operation impossible!\n%s";
|
||||
static char nowar[] __initdata =
|
||||
"Please report to <linux-mips@linux-mips.org>.";
|
||||
static char r4kwar[] __initdata =
|
||||
"Enable CPU_R4000_WORKAROUNDS to rectify.";
|
||||
static char daddiwar[] __initdata =
|
||||
"Enable CPU_DADDI_WORKAROUNDS to rectify.";
|
||||
|
||||
static inline void align_mod(const int align, const int mod)
|
||||
{
|
||||
asm volatile(
|
||||
@@ -155,13 +164,7 @@ static inline void check_mult_sh(void)
|
||||
}
|
||||
|
||||
printk("no.\n");
|
||||
panic("Reliable operation impossible!\n"
|
||||
#ifndef CONFIG_CPU_R4000
|
||||
"Configure for R4000 to enable the workaround."
|
||||
#else
|
||||
"Please report to <linux-mips@linux-mips.org>."
|
||||
#endif
|
||||
);
|
||||
panic(bug64hit, !R4000_WAR ? r4kwar : nowar);
|
||||
}
|
||||
|
||||
static volatile int daddi_ov __initdata = 0;
|
||||
@@ -233,15 +236,11 @@ static inline void check_daddi(void)
|
||||
}
|
||||
|
||||
printk("no.\n");
|
||||
panic("Reliable operation impossible!\n"
|
||||
#if !defined(CONFIG_CPU_R4000) && !defined(CONFIG_CPU_R4400)
|
||||
"Configure for R4000 or R4400 to enable the workaround."
|
||||
#else
|
||||
"Please report to <linux-mips@linux-mips.org>."
|
||||
#endif
|
||||
);
|
||||
panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
|
||||
}
|
||||
|
||||
int daddiu_bug __initdata = -1;
|
||||
|
||||
static inline void check_daddiu(void)
|
||||
{
|
||||
long v, w, tmp;
|
||||
@@ -281,7 +280,9 @@ static inline void check_daddiu(void)
|
||||
: "=&r" (v), "=&r" (w), "=&r" (tmp)
|
||||
: "I" (0xffffffffffffdb9aUL), "I" (0x1234));
|
||||
|
||||
if (v == w) {
|
||||
daddiu_bug = v != w;
|
||||
|
||||
if (!daddiu_bug) {
|
||||
printk("no.\n");
|
||||
return;
|
||||
}
|
||||
@@ -303,18 +304,16 @@ static inline void check_daddiu(void)
|
||||
}
|
||||
|
||||
printk("no.\n");
|
||||
panic("Reliable operation impossible!\n"
|
||||
#if !defined(CONFIG_CPU_R4000) && !defined(CONFIG_CPU_R4400)
|
||||
"Configure for R4000 or R4400 to enable the workaround."
|
||||
#else
|
||||
"Please report to <linux-mips@linux-mips.org>."
|
||||
#endif
|
||||
);
|
||||
panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
|
||||
}
|
||||
|
||||
void __init check_bugs64_early(void)
|
||||
{
|
||||
check_mult_sh();
|
||||
check_daddiu();
|
||||
}
|
||||
|
||||
void __init check_bugs64(void)
|
||||
{
|
||||
check_mult_sh();
|
||||
check_daddi();
|
||||
check_daddiu();
|
||||
}
|
||||
|
Reference in New Issue
Block a user