aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/kernel/cpu-bugs64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/cpu-bugs64.c')
-rw-r--r--arch/mips/kernel/cpu-bugs64.c79
1 files changed, 41 insertions, 38 deletions
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index 47a087b6c11..2d80b5f1aea 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -1,12 +1,12 @@
/*
- * Copyright (C) 2003, 2004 Maciej W. Rozycki
+ * Copyright (C) 2003, 2004, 2007 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
+#include <linux/context_tracking.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
@@ -17,7 +17,16 @@
#include <asm/cpu.h>
#include <asm/fpu.h>
#include <asm/mipsregs.h>
-#include <asm/system.h>
+#include <asm/setup.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)
{
@@ -30,7 +39,7 @@ static inline void align_mod(const int align, const int mod)
".endr\n\t"
".set pop"
:
- : "n" (align), "n" (mod));
+ : GCC_IMM_ASM() (align), GCC_IMM_ASM() (mod));
}
static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
@@ -65,7 +74,7 @@ static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
: "0" (5), "1" (8), "2" (5));
align_mod(align, mod);
/*
- * The trailing nop is needed to fullfill the two-instruction
+ * The trailing nop is needed to fulfill the two-instruction
* requirement between reading hi/lo and staring a mult/div.
* Leaving it out may cause gas insert a nop itself breaking
* the desired alignment of the next chunk.
@@ -76,9 +85,9 @@ static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
".set noreorder\n\t"
".set nomacro\n\t"
"mult %2, %3\n\t"
- "dsll32 %0, %4, %5\n\t"
+ "dsll32 %0, %4, %5\n\t"
"mflo $0\n\t"
- "dsll32 %1, %4, %5\n\t"
+ "dsll32 %1, %4, %5\n\t"
"nop\n\t"
".set pop"
: "=&r" (lv1), "=r" (lw)
@@ -156,21 +165,19 @@ 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;
+static volatile int daddi_ov;
asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
{
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
daddi_ov = 1;
regs->cp0_epc += 4;
+ exception_exit(prev_state);
}
static inline void check_daddi(void)
@@ -206,7 +213,7 @@ static inline void check_daddi(void)
"daddi %0, %1, %3\n\t"
".set pop"
: "=r" (v), "=&r" (tmp)
- : "I" (0xffffffffffffdb9a), "I" (0x1234));
+ : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
set_except_vector(12, handler);
local_irq_restore(flags);
@@ -224,7 +231,7 @@ static inline void check_daddi(void)
"dsrl %1, %1, 1\n\t"
"daddi %0, %1, %3"
: "=r" (v), "=&r" (tmp)
- : "I" (0xffffffffffffdb9a), "I" (0x1234));
+ : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
set_except_vector(12, handler);
local_irq_restore(flags);
@@ -234,15 +241,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 = -1;
+
static inline void check_daddiu(void)
{
long v, w, tmp;
@@ -275,14 +278,16 @@ static inline void check_daddiu(void)
#ifdef HAVE_AS_SET_DADDI
".set daddi\n\t"
#endif
- "daddiu %0, %2, %4\n\t"
+ "daddiu %0, %2, %4\n\t"
"addiu %1, $0, %4\n\t"
"daddu %1, %2\n\t"
".set pop"
: "=&r" (v), "=&r" (w), "=&r" (tmp)
- : "I" (0xffffffffffffdb9a), "I" (0x1234));
+ : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
- if (v == w) {
+ daddiu_bug = v != w;
+
+ if (!daddiu_bug) {
printk("no.\n");
return;
}
@@ -292,11 +297,11 @@ static inline void check_daddiu(void)
asm volatile(
"addiu %2, $0, %3\n\t"
"dsrl %2, %2, 1\n\t"
- "daddiu %0, %2, %4\n\t"
+ "daddiu %0, %2, %4\n\t"
"addiu %1, $0, %4\n\t"
"daddu %1, %2"
: "=&r" (v), "=&r" (w), "=&r" (tmp)
- : "I" (0xffffffffffffdb9a), "I" (0x1234));
+ : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
if (v == w) {
printk("yes.\n");
@@ -304,18 +309,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(void)
+void __init check_bugs64_early(void)
{
check_mult_sh();
- check_daddi();
check_daddiu();
}
+
+void __init check_bugs64(void)
+{
+ check_daddi();
+}