diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2014-04-01 00:57:28 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-05-13 00:29:36 +0200 |
commit | 2db4bc3418c43f1e810b304c48f8ddff2535075b (patch) | |
tree | 70aecfaca9e45a7b2685ef3fb65f0cdf3f595e3a /arch/mips/lib | |
parent | 824122a319d827d42aeb4646a3bf639937fdb2ce (diff) | |
download | linux-2db4bc3418c43f1e810b304c48f8ddff2535075b.tar.gz linux-2db4bc3418c43f1e810b304c48f8ddff2535075b.tar.bz2 linux-2db4bc3418c43f1e810b304c48f8ddff2535075b.zip |
MIPS: __delay CPU_DADDI_WORKAROUNDS bug fix
With CPU_DADDI_WORKAROUNDS enabled __delay assembles with a macro in a
branch delay slot:
{standard input}: Assembler messages:
{standard input}:18: Warning: Macro instruction expanded into multiple
instructions in a branch delay slot
and broken code results:
0000000000000000 <__delay>:
0: 1480ffff bnez a0,0 <__delay>
4: 24010001 li at,1
8: 0081202f dsubu a0,a0,at
c: 03e00008 jr ra
10: 00000000 nop
14: 00000000 nop
Consequently the function loops indefinitely, showing up prominently as a
hang in the delay loop calibration at bootstrap.
This change corrects the problem by forcing the immediate 1 into a
register while keeping code produced identical where CPU_DADDI_WORKAROUNDS
is disabled.
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/6669/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/lib')
-rw-r--r-- | arch/mips/lib/delay.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/arch/mips/lib/delay.c b/arch/mips/lib/delay.c index 44713af15a62..705cfb7c1a74 100644 --- a/arch/mips/lib/delay.c +++ b/arch/mips/lib/delay.c @@ -6,7 +6,7 @@ * Copyright (C) 1994 by Waldorf Electronics * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - * Copyright (C) 2007 Maciej W. Rozycki + * Copyright (C) 2007, 2014 Maciej W. Rozycki */ #include <linux/module.h> #include <linux/param.h> @@ -15,6 +15,12 @@ #include <asm/compiler.h> #include <asm/war.h> +#ifndef CONFIG_CPU_DADDI_WORKAROUNDS +#define GCC_DADDI_IMM_ASM() "I" +#else +#define GCC_DADDI_IMM_ASM() "r" +#endif + void __delay(unsigned long loops) { __asm__ __volatile__ ( @@ -22,13 +28,13 @@ void __delay(unsigned long loops) " .align 3 \n" "1: bnez %0, 1b \n" #if BITS_PER_LONG == 32 - " subu %0, 1 \n" + " subu %0, %1 \n" #else - " dsubu %0, 1 \n" + " dsubu %0, %1 \n" #endif " .set reorder \n" : "=r" (loops) - : "0" (loops)); + : GCC_DADDI_IMM_ASM() (1), "0" (loops)); } EXPORT_SYMBOL(__delay); |