aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-mips/delay.h
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2007-10-23 07:43:11 -0400
committerRalf Baechle <ralf@linux-mips.org>2008-01-29 05:14:54 -0500
commit20d60d9973c3b441902b0a3f4f6f7e7ade08f77d (patch)
tree2dbadcb5600fcb486612ec30d972e6c29195ee1d /include/asm-mips/delay.h
parent2b22c034d04d3632a339d14d5803c8f94e412608 (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.h12
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
17static inline void __delay(unsigned long loops) 20static inline void __delay(unsigned long loops)
18{ 21{
@@ -50,7 +53,7 @@ static inline void __delay(unsigned long loops)
50 53
51static inline void __udelay(unsigned long usecs, unsigned long lpj) 54static 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}