MIPS: Fix code generation for non-DSP capable CPUs

Commit 32a7ede (MIPS: dsp: Add assembler support for DSP ASEs) has
enabled the use of DSP ASE specific instructions such as rddsp and wrdsp
under the idea that all code path that will make use of these two
instructions are properly checking for cpu_has_dsp to ensure that the
particular CPU we are running on *actually* supports DSP ASE.

This commit actually causes the following oops on QEMU Malta emulating a
MIPS 24Kc without the DSP ASE implemented:

[    7.960000] Reserved instruction in kernel
[    7.960000] Cpu 0
[    7.960000] $ 0   : 00000000 00000000 00000014 00000005
[    7.960000] $ 4   : 8fc2de48 00000001 00000000 8f59ddb0
[    7.960000] $ 8   : 8f5ceec4 00000018 00000c00 00800000
[    7.960000] $12   : 00000100 00000200 00000000 00457b84
[    7.960000] $16   : 00000000 8fc2ba78 8f4ec980 00000001
[    7.960000] $20   : 80418f90 00000000 00000000 000002dd
[    7.960000] $24   : 0000009c 7730d7b8
[    7.960000] $28   : 8f59c000 8f59dd38 00000001 80104248
[    7.960000] Hi    : 0000001d
[    7.960000] Lo    : 0000000b
[    7.960000] epc   : 801041ec thread_saved_pc+0x2c/0x38
[    7.960000]     Not tainted
[    7.960000] ra    : 80104248 get_wchan+0x48/0xac
[    7.960000] Status: 1000b703    KERNEL EXL IE
[    7.960000] Cause : 10800028
[    7.960000] PrId  : 00019300 (MIPS 24Kc)
[    7.960000] Modules linked in:
[    7.960000] Process killall (pid: 1574, threadinfo=8f59c000,
task=8fd14558, tls=773aa440)
[    7.960000] Stack : 8fc2ba78 8012b008 0000000c 0000001d 00000000
00000000 8f58a380
                  8f58a380 8fc2ba78 80202668 8f59de78 8f468600 8f59de28
801b2a3c 8f59df00 8f98ba20 74696e69
                  8f468600 8f59de28 801b7308 0081c007 00000000 00000000
00000000 00000000 00000000 00000000
                  00000000 8fc2bbb4 00000001 0000001d 0000000b 77f038cc
7fe80648 ffffffff ffffffff 00000000
                  00000001 0016e000 00000000 ...
[    7.960000] Call Trace:
[    7.960000] [<801041ec>] thread_saved_pc+0x2c/0x38
[    7.960000] [<80104248>] get_wchan+0x48/0xac

The disassembly of thread_saved_pc points to the following:
000006d0 <thread_saved_pc>:
 6d0:   8c820208        lw      v0,520(a0)
 6d4:   3c030000        lui     v1,0x0
 6d8:   24630000        addiu   v1,v1,0
 6dc:   10430008        beq     v0,v1,700 <thread_saved_pc+0x30>
 6e0:   00000000        nop
 6e4:   3c020000        lui     v0,0x0
 6e8:   8c43000c        lw      v1,12(v0)
 6ec:   04620004        bltzl   v1,700 <thread_saved_pc+0x30>
 6f0:   00001021        move    v0,zero
 6f4:   8c840200        lw      a0,512(a0)
 6f8:   00031080        sll     v0,v1,0x2
 6fc:   7c44100a        lwx     v0,a0(v0)   <------------
 700:   03e00008        jr      ra
 704:   00000000        nop

If we specifically disable -mdsp/-mdspr2 for arch/mips/kernel/process.o,
we get the following (non-crashing) assembly:

00000708 <thread_saved_pc>:
 708:   8c820208        lw      v0,520(a0)
 70c:   3c030000        lui     v1,0x0
 710:   24630000        addiu   v1,v1,0
 714:   10430009        beq     v0,v1,73c <thread_saved_pc+0x34>
 718:   00000000        nop
 71c:   3c020000        lui     v0,0x0
 720:   8c42000c        lw      v0,12(v0)
 724:   04420005        bltzl   v0,73c <thread_saved_pc+0x34>
 728:   00001021        move    v0,zero
 72c:   8c830200        lw      v1,512(a0)
 730:   00021080        sll     v0,v0,0x2
 734:   00431021        addu    v0,v0,v1
 738:   8c420000        lw      v0,0(v0)
 73c:   03e00008        jr      ra
 740:   00000000        nop

The specific line that leads a different assembly being produced is:

unsigned long thread_saved_pc(struct task_struct *tsk)
...
	return ((unsigned long *)t->reg29)[schedule_mfi.pc_offset]; <---

The problem here is that the compiler was given the right to use DSP
instructions with the -mdsp / -mdspr2 command-line switches and
performed some optimization for us and used DSP ASE instructions where
we are not checking that the running CPU actually supports DSP ASE.

This patch fixes the issue by partially reverting commit 32a7ede for
arch/mips/kernel/Makefile in order to remove the -mdsp / -mdspr2
compiler command-line switches such that we are now guaranteed that the
compiler will not optimize using DSP ASE reserved instructions. We also
need to fixup the rddsp/wrdsp and m{t,h}{hi,lo}{0,1,2,3} macros in
arch/mips/include/asm/mipsregs.h to tell the assembler that we are going
to explicitely use DSP ASE reserved instructions. The comment in
arch/mips/kernel/Makefile is also updated to reflect that.

Signed-off-by: Florian Fainelli <florian@openwrt.org>
Acked-by: Steven J. Hill <Steven.Hill@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: blogic@openwrt.org
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Florian Fainelli 2013-03-18 15:56:10 +00:00 committed by Ralf Baechle
parent a4285b99e0
commit 63c2b6812f
2 changed files with 193 additions and 35 deletions

View File

@ -1166,7 +1166,10 @@ do { \
unsigned int __dspctl; \ unsigned int __dspctl; \
\ \
__asm__ __volatile__( \ __asm__ __volatile__( \
" .set push \n" \
" .set dsp \n" \
" rddsp %0, %x1 \n" \ " rddsp %0, %x1 \n" \
" .set pop \n" \
: "=r" (__dspctl) \ : "=r" (__dspctl) \
: "i" (mask)); \ : "i" (mask)); \
__dspctl; \ __dspctl; \
@ -1175,30 +1178,198 @@ do { \
#define wrdsp(val, mask) \ #define wrdsp(val, mask) \
do { \ do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
" .set push \n" \
" .set dsp \n" \
" wrdsp %0, %x1 \n" \ " wrdsp %0, %x1 \n" \
" .set pop \n" \
: \ : \
: "r" (val), "i" (mask)); \ : "r" (val), "i" (mask)); \
} while (0) } while (0)
#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;}) #define mflo0() \
#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;}) ({ \
#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;}) long mflo0; \
#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;}) __asm__( \
" .set push \n" \
" .set dsp \n" \
" mflo %0, $ac0 \n" \
" .set pop \n" \
: "=r" (mflo0)); \
mflo0; \
})
#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;}) #define mflo1() \
#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;}) ({ \
#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;}) long mflo1; \
#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;}) __asm__( \
" .set push \n" \
" .set dsp \n" \
" mflo %0, $ac1 \n" \
" .set pop \n" \
: "=r" (mflo1)); \
mflo1; \
})
#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x)) #define mflo2() \
#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x)) ({ \
#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x)) long mflo2; \
#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x)) __asm__( \
" .set push \n" \
" .set dsp \n" \
" mflo %0, $ac2 \n" \
" .set pop \n" \
: "=r" (mflo2)); \
mflo2; \
})
#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x)) #define mflo3() \
#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x)) ({ \
#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x)) long mflo3; \
#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x)) __asm__( \
" .set push \n" \
" .set dsp \n" \
" mflo %0, $ac3 \n" \
" .set pop \n" \
: "=r" (mflo3)); \
mflo3; \
})
#define mfhi0() \
({ \
long mfhi0; \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mfhi %0, $ac0 \n" \
" .set pop \n" \
: "=r" (mfhi0)); \
mfhi0; \
})
#define mfhi1() \
({ \
long mfhi1; \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mfhi %0, $ac1 \n" \
" .set pop \n" \
: "=r" (mfhi1)); \
mfhi1; \
})
#define mfhi2() \
({ \
long mfhi2; \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mfhi %0, $ac2 \n" \
" .set pop \n" \
: "=r" (mfhi2)); \
mfhi2; \
})
#define mfhi3() \
({ \
long mfhi3; \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mfhi %0, $ac3 \n" \
" .set pop \n" \
: "=r" (mfhi3)); \
mfhi3; \
})
#define mtlo0(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mtlo %0, $ac0 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mtlo1(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mtlo %0, $ac1 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mtlo2(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mtlo %0, $ac2 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mtlo3(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mtlo %0, $ac3 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mthi0(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mthi %0, $ac0 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mthi1(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mthi %0, $ac1 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mthi2(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mthi %0, $ac2 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#define mthi3(x) \
({ \
__asm__( \
" .set push \n" \
" .set dsp \n" \
" mthi %0, $ac3 \n" \
" .set pop \n" \
: \
: "r" (x)); \
})
#else #else

View File

@ -100,29 +100,16 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o
# #
# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is safe # DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not
# to enable DSP assembler support here even if the MIPS Release 2 CPU we # safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches
# are targetting does not support DSP because all code-paths making use of # here because the compiler may use DSP ASE instructions (such as lwx) in
# it properly check that the running CPU *actually does* support these # code paths where we cannot check that the CPU we are running on supports it.
# instructions. # Proper abstraction using HAVE_AS_DSP and macros is done in
# arch/mips/include/asm/mipsregs.h.
# #
ifeq ($(CONFIG_CPU_MIPSR2), y) ifeq ($(CONFIG_CPU_MIPSR2), y)
CFLAGS_DSP = -DHAVE_AS_DSP CFLAGS_DSP = -DHAVE_AS_DSP
#
# Check if assembler supports DSP ASE
#
ifeq ($(call cc-option-yn,-mdsp), y)
CFLAGS_DSP += -mdsp
endif
#
# Check if assembler supports DSP ASE Rev2
#
ifeq ($(call cc-option-yn,-mdspr2), y)
CFLAGS_DSP += -mdspr2
endif
CFLAGS_signal.o = $(CFLAGS_DSP) CFLAGS_signal.o = $(CFLAGS_DSP)
CFLAGS_signal32.o = $(CFLAGS_DSP) CFLAGS_signal32.o = $(CFLAGS_DSP)
CFLAGS_process.o = $(CFLAGS_DSP) CFLAGS_process.o = $(CFLAGS_DSP)