diff options
Diffstat (limited to 'arch/mips/kernel/cpu-bugs64.c')
| -rw-r--r-- | arch/mips/kernel/cpu-bugs64.c | 70 |
1 files changed, 37 insertions, 33 deletions
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c index c09337b947b..2d80b5f1aea 100644 --- a/arch/mips/kernel/cpu-bugs64.c +++ b/arch/mips/kernel/cpu-bugs64.c @@ -1,11 +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/context_tracking.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/ptrace.h> @@ -16,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) { @@ -29,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, @@ -64,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. @@ -75,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) @@ -155,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) @@ -233,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; @@ -274,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" (0xffffffffffffdb9aUL), "I" (0x1234)); - if (v == w) { + daddiu_bug = v != w; + + if (!daddiu_bug) { printk("no.\n"); return; } @@ -291,7 +297,7 @@ 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) @@ -303,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(); +} |
