diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2007-10-23 07:43:11 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2008-01-29 05:14:54 -0500 |
commit | 20d60d9973c3b441902b0a3f4f6f7e7ade08f77d (patch) | |
tree | 2dbadcb5600fcb486612ec30d972e6c29195ee1d /include/asm-mips/delay.h | |
parent | 2b22c034d04d3632a339d14d5803c8f94e412608 (diff) |
[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>
Diffstat (limited to 'include/asm-mips/delay.h')
-rw-r--r-- | include/asm-mips/delay.h | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index fab32131e9b4..de5105d05f1e 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h | |||
@@ -6,13 +6,16 @@ | |||
6 | * Copyright (C) 1994 by Waldorf Electronics | 6 | * Copyright (C) 1994 by Waldorf Electronics |
7 | * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle | 7 | * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle |
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
9 | * Copyright (C) 2007 Maciej W. Rozycki | ||
9 | */ | 10 | */ |
10 | #ifndef _ASM_DELAY_H | 11 | #ifndef _ASM_DELAY_H |
11 | #define _ASM_DELAY_H | 12 | #define _ASM_DELAY_H |
12 | 13 | ||
13 | #include <linux/param.h> | 14 | #include <linux/param.h> |
14 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
16 | |||
15 | #include <asm/compiler.h> | 17 | #include <asm/compiler.h> |
18 | #include <asm/war.h> | ||
16 | 19 | ||
17 | static inline void __delay(unsigned long loops) | 20 | static inline void __delay(unsigned long loops) |
18 | { | 21 | { |
@@ -50,7 +53,7 @@ static inline void __delay(unsigned long loops) | |||
50 | 53 | ||
51 | static inline void __udelay(unsigned long usecs, unsigned long lpj) | 54 | static inline void __udelay(unsigned long usecs, unsigned long lpj) |
52 | { | 55 | { |
53 | unsigned long lo; | 56 | unsigned long hi, lo; |
54 | 57 | ||
55 | /* | 58 | /* |
56 | * The rates of 128 is rounded wrongly by the catchall case | 59 | * The rates of 128 is rounded wrongly by the catchall case |
@@ -70,11 +73,16 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj) | |||
70 | : "=h" (usecs), "=l" (lo) | 73 | : "=h" (usecs), "=l" (lo) |
71 | : "r" (usecs), "r" (lpj) | 74 | : "r" (usecs), "r" (lpj) |
72 | : GCC_REG_ACCUM); | 75 | : GCC_REG_ACCUM); |
73 | else if (sizeof(long) == 8) | 76 | else if (sizeof(long) == 8 && !R4000_WAR) |
74 | __asm__("dmultu\t%2, %3" | 77 | __asm__("dmultu\t%2, %3" |
75 | : "=h" (usecs), "=l" (lo) | 78 | : "=h" (usecs), "=l" (lo) |
76 | : "r" (usecs), "r" (lpj) | 79 | : "r" (usecs), "r" (lpj) |
77 | : GCC_REG_ACCUM); | 80 | : GCC_REG_ACCUM); |
81 | else if (sizeof(long) == 8 && R4000_WAR) | ||
82 | __asm__("dmultu\t%3, %4\n\tmfhi\t%0" | ||
83 | : "=r" (usecs), "=h" (hi), "=l" (lo) | ||
84 | : "r" (usecs), "r" (lpj) | ||
85 | : GCC_REG_ACCUM); | ||
78 | 86 | ||
79 | __delay(usecs); | 87 | __delay(usecs); |
80 | } | 88 | } |