R5k CPUs have a bug, where ll access to XKPHYS addresses don't work. Check for this bug and enable workaround, if possible. Signed-off-by: Thomas Bogendoerfer <tsbogend@xxxxxxxxxxxxxxxx> --- arch/mips/kernel/cpu-bugs64.c | 36 ++++++++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-) diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c index 02b7713..8e55649 100644 --- a/arch/mips/kernel/cpu-bugs64.c +++ b/arch/mips/kernel/cpu-bugs64.c @@ -26,6 +26,8 @@ static char r4kwar[] __initdata = "Enable CPU_R4000_WORKAROUNDS to rectify."; static char daddiwar[] __initdata = "Enable CPU_DADDI_WORKAROUNDS to rectify."; +static char xkphysllwar[] __initdata = + "CPU has ll xkphys bug."; static inline void align_mod(const int align, const int mod) { @@ -307,10 +309,44 @@ static inline void check_daddiu(void) panic(bug64hit, !DADDI_WAR ? daddiwar : nowar); } +static u32 ll(u32 *p) +{ + u32 ret; + + asm volatile( + "ll %0, %1\n\t" + : "=&r" (ret) + : "m" (*p)); + + return ret; +} + +void __init check_ll_xkphys(void) +{ + static u32 val; + u32 *p = (u32 *)PHYS_TO_XKPHYS(K_CALG_NONCOHERENT, + CPHYSADDR((unsigned long)&val)); + + printk("Checking for the ll/lld xkphys bug... "); + memset(p, 0xff, sizeof(val)); + if (ll(p) != 0xffffffff) { + printk("yes, enabling workaround... "); + cpu_data[0].options &= ~MIPS_CPU_LLSC; + if (cpu_has_llsc != (cpu_data[0].options & MIPS_CPU_LLSC)) { + printk("failed.\n"); + panic(bug64hit, xkphysllwar); + } + printk("ok.\n"); + } else + printk("no.\n"); +} + + void __init check_bugs64_early(void) { check_mult_sh(); check_daddiu(); + check_ll_xkphys(); } void __init check_bugs64(void)