^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2003, 2004, 2007 Maciej W. Rozycki
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/context_tracking.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/bugs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/fpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/mipsregs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static char bug64hit[] __initdata =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) "reliable operation impossible!\n%s";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static char nowar[] __initdata =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) "Please report to <linux-mips@linux-mips.org>.";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static char r4kwar[] __initdata =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) "Enable CPU_R4000_WORKAROUNDS to rectify.";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static char daddiwar[] __initdata =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) "Enable CPU_DADDI_WORKAROUNDS to rectify.";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static __always_inline __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void align_mod(const int align, const int mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ".set push\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) ".set noreorder\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ".balign %0\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) ".rept %1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) "nop\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ".endr\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ".set pop"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) : "n"(align), "n"(mod));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static __always_inline __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) void mult_sh_align_mod(long *v1, long *v2, long *w,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) const int align, const int mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int m1, m2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) long p, s, lv1, lv2, lw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * We want the multiply and the shift to be isolated from the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * rest of the code to disable gcc optimizations. Hence the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * asm statements that execute nothing, but make gcc not know
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * what the values of m1, m2 and s are and what lv2 and p are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * used for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * The following code leads to a wrong result of the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * dsll32 when executed on R4000 rev. 2.2 or 3.0 (PRId
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * 00000422 or 00000430, respectively).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * See "MIPS R4000PC/SC Errata, Processor Revision 2.2 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * 3.0" by MIPS Technologies, Inc., errata #16 and #28 for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * details. I got no permission to duplicate them here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * sigh... --macro
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) : "=r" (m1), "=r" (m2), "=r" (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) : "0" (5), "1" (8), "2" (5));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) align_mod(align, mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * The trailing nop is needed to fulfill the two-instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * requirement between reading hi/lo and staring a mult/div.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * Leaving it out may cause gas insert a nop itself breaking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * the desired alignment of the next chunk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ".set push\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ".set noat\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ".set noreorder\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ".set nomacro\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) "mult %2, %3\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) "dsll32 %0, %4, %5\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "mflo $0\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) "dsll32 %1, %4, %5\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) "nop\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ".set pop"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) : "=&r" (lv1), "=r" (lw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) : "r" (m1), "r" (m2), "r" (s), "I" (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) : "hi", "lo", "$0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* We have to use single integers for m1 and m2 and a double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * one for p to be sure the mulsidi3 gcc's RTL multiplication
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * instruction has the workaround applied. Older versions of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * gcc have correct umulsi3 and mulsi3, but other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * multiplication variants lack the workaround.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) : "=r" (m1), "=r" (m2), "=r" (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) : "0" (m1), "1" (m2), "2" (s));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) align_mod(align, mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) p = m1 * m2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) lv2 = s << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) : "=r" (lv2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) : "0" (lv2), "r" (p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) *v1 = lv1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *v2 = lv2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) *w = lw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static __always_inline __init void check_mult_sh(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) long v1[8], v2[8], w[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int bug, fix, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) printk("Checking for the multiply/shift bug... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * Testing discovered false negatives for certain code offsets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * into cache lines. Hence we test all possible offsets for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * the worst assumption of an R4000 I-cache line width of 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * We can't use a loop as alignment directives need to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * immediates.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) mult_sh_align_mod(&v1[0], &v2[0], &w[0], 32, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) mult_sh_align_mod(&v1[1], &v2[1], &w[1], 32, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) mult_sh_align_mod(&v1[2], &v2[2], &w[2], 32, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) mult_sh_align_mod(&v1[3], &v2[3], &w[3], 32, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) mult_sh_align_mod(&v1[4], &v2[4], &w[4], 32, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) mult_sh_align_mod(&v1[5], &v2[5], &w[5], 32, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) mult_sh_align_mod(&v1[6], &v2[6], &w[6], 32, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) mult_sh_align_mod(&v1[7], &v2[7], &w[7], 32, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) bug = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) for (i = 0; i < 8; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (v1[i] != w[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) bug = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (bug == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) pr_cont("no.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pr_cont("yes, workaround... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) fix = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) for (i = 0; i < 8; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (v2[i] != w[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) fix = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (fix == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pr_cont("yes.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) pr_cont("no.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) panic(bug64hit, !R4000_WAR ? r4kwar : nowar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static volatile int daddi_ov;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) enum ctx_state prev_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) prev_state = exception_enter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) daddi_ov = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) regs->cp0_epc += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) exception_exit(prev_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static __init void check_daddi(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) extern asmlinkage void handle_daddi_ov(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) void *handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) long v, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) printk("Checking for the daddi bug... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) handler = set_except_vector(EXCCODE_OV, handle_daddi_ov);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * The following code fails to trigger an overflow exception
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * when executed on R4000 rev. 2.2 or 3.0 (PRId 00000422 or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * 00000430, respectively).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * See "MIPS R4000PC/SC Errata, Processor Revision 2.2 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * 3.0" by MIPS Technologies, Inc., erratum #23 for details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * I got no permission to duplicate it here, sigh... --macro
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) ".set push\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) ".set noat\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) ".set noreorder\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) ".set nomacro\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) "addiu %1, $0, %2\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) "dsrl %1, %1, 1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) #ifdef HAVE_AS_SET_DADDI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ".set daddi\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) "daddi %0, %1, %3\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ".set pop"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) : "=r" (v), "=&r" (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) set_except_vector(EXCCODE_OV, handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (daddi_ov) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) pr_cont("no.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) pr_cont("yes, workaround... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) handler = set_except_vector(EXCCODE_OV, handle_daddi_ov);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) "addiu %1, $0, %2\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) "dsrl %1, %1, 1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) "daddi %0, %1, %3"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) : "=r" (v), "=&r" (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) set_except_vector(EXCCODE_OV, handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (daddi_ov) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) pr_cont("yes.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) pr_cont("no.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int daddiu_bug = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static __init void check_daddiu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) long v, w, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) printk("Checking for the daddiu bug... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * The following code leads to a wrong result of daddiu when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * executed on R4400 rev. 1.0 (PRId 00000440).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * See "MIPS R4400PC/SC Errata, Processor Revision 1.0" by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * MIPS Technologies, Inc., erratum #7 for details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * According to "MIPS R4000PC/SC Errata, Processor Revision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * 2.2 and 3.0" by MIPS Technologies, Inc., erratum #41 this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * problem affects R4000 rev. 2.2 and 3.0 (PRId 00000422 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * 00000430, respectively), too. Testing failed to trigger it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * so far.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * I got no permission to duplicate the errata here, sigh...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * --macro
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) ".set push\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) ".set noat\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) ".set noreorder\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) ".set nomacro\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) "addiu %2, $0, %3\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) "dsrl %2, %2, 1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) #ifdef HAVE_AS_SET_DADDI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ".set daddi\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) "daddiu %0, %2, %4\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) "addiu %1, $0, %4\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) "daddu %1, %2\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) ".set pop"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) : "=&r" (v), "=&r" (w), "=&r" (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) daddiu_bug = v != w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!daddiu_bug) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) pr_cont("no.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) pr_cont("yes, workaround... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) "addiu %2, $0, %3\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) "dsrl %2, %2, 1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) "daddiu %0, %2, %4\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) "addiu %1, $0, %4\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) "daddu %1, %2"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) : "=&r" (v), "=&r" (w), "=&r" (tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (v == w) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) pr_cont("yes.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) pr_cont("no.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) void __init check_bugs64_early(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) check_mult_sh();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) check_daddiu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) void __init check_bugs64(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) check_daddi();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }