diff options
author | Paul Walmsley | 2012-10-23 14:32:59 -0500 |
---|---|---|
committer | Greg Kroah-Hartman | 2012-12-17 12:49:02 -0600 |
commit | 15a83cc22d40240f1f551b4c2092f7f246bdbfce (patch) | |
tree | f20379fa5c82ccd5e14f87164528f310c43e0344 /arch | |
parent | 4eb15b7fe7ad2a055f79eb1056a0c2d3317ff6f0 (diff) | |
download | kernel-common-15a83cc22d40240f1f551b4c2092f7f246bdbfce.tar.gz kernel-common-15a83cc22d40240f1f551b4c2092f7f246bdbfce.tar.xz kernel-common-15a83cc22d40240f1f551b4c2092f7f246bdbfce.zip |
ARM: 7566/1: vfp: fix save and restore when running on pre-VFPv3 and CONFIG_VFPv3 set
commit 39141ddfb63a664f26d3f42f64ee386e879b492c upstream.
After commit 846a136881b8f73c1f74250bf6acfaa309cab1f2 ("ARM: vfp: fix
saving d16-d31 vfp registers on v6+ kernels"), the OMAP 2430SDP board
started crashing during boot with omap2plus_defconfig:
[ 3.875122] mmcblk0: mmc0:e624 SD04G 3.69 GiB
[ 3.915954] mmcblk0: p1
[ 4.086639] Internal error: Oops - undefined instruction: 0 [#1] SMP ARM
[ 4.093719] Modules linked in:
[ 4.096954] CPU: 0 Not tainted (3.6.0-02232-g759e00b #570)
[ 4.103149] PC is at vfp_reload_hw+0x1c/0x44
[ 4.107666] LR is at __und_usr_fault_32+0x0/0x8
It turns out that the context save/restore fix unmasked a latent bug
in commit 5aaf254409f8d58229107b59507a8235b715a960 ("ARM: 6203/1: Make
VFPv3 usable on ARMv6"). When CONFIG_VFPv3 is set, but the kernel is
booted on a pre-VFPv3 core, the code attempts to save and restore the
d16-d31 VFP registers. These are only present on non-D16 VFPv3+, so
this results in an undefined instruction exception. The code didn't
crash before commit 846a136 because the save and restore code was
only touching d0-d15, present on all VFP.
Fix by implementing a request from Russell King to add a new HWCAP
flag that affirmatively indicates the presence of the d16-d31
registers:
http://marc.info/?l=linux-arm-kernel&m=135013547905283&w=2
and some feedback from Måns to clarify the name of the HWCAP flag.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dave Martin <dave.martin@linaro.org>
Cc: Måns Rullgård <mans.rullgard@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/hwcap.h | 3 | ||||
-rw-r--r-- | arch/arm/include/asm/vfpmacros.h | 12 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 9 |
3 files changed, 14 insertions, 10 deletions
diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h index c1062c31710..1e3f30f535f 100644 --- a/arch/arm/include/asm/hwcap.h +++ b/arch/arm/include/asm/hwcap.h | |||
@@ -18,8 +18,9 @@ | |||
18 | #define HWCAP_THUMBEE 2048 | 18 | #define HWCAP_THUMBEE 2048 |
19 | #define HWCAP_NEON 4096 | 19 | #define HWCAP_NEON 4096 |
20 | #define HWCAP_VFPv3 8192 | 20 | #define HWCAP_VFPv3 8192 |
21 | #define HWCAP_VFPv3D16 16384 | 21 | #define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */ |
22 | #define HWCAP_TLS 32768 | 22 | #define HWCAP_TLS 32768 |
23 | #define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ | ||
23 | 24 | ||
24 | #if defined(__KERNEL__) && !defined(__ASSEMBLY__) | 25 | #if defined(__KERNEL__) && !defined(__ASSEMBLY__) |
25 | /* | 26 | /* |
diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index bf5304797c7..c49c8f778b5 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h | |||
@@ -27,9 +27,9 @@ | |||
27 | #if __LINUX_ARM_ARCH__ <= 6 | 27 | #if __LINUX_ARM_ARCH__ <= 6 |
28 | ldr \tmp, =elf_hwcap @ may not have MVFR regs | 28 | ldr \tmp, =elf_hwcap @ may not have MVFR regs |
29 | ldr \tmp, [\tmp, #0] | 29 | ldr \tmp, [\tmp, #0] |
30 | tst \tmp, #HWCAP_VFPv3D16 | 30 | tst \tmp, #HWCAP_VFPD32 |
31 | ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} | 31 | ldcnel p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} |
32 | addne \base, \base, #32*4 @ step over unused register space | 32 | addeq \base, \base, #32*4 @ step over unused register space |
33 | #else | 33 | #else |
34 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 | 34 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 |
35 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field | 35 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field |
@@ -51,9 +51,9 @@ | |||
51 | #if __LINUX_ARM_ARCH__ <= 6 | 51 | #if __LINUX_ARM_ARCH__ <= 6 |
52 | ldr \tmp, =elf_hwcap @ may not have MVFR regs | 52 | ldr \tmp, =elf_hwcap @ may not have MVFR regs |
53 | ldr \tmp, [\tmp, #0] | 53 | ldr \tmp, [\tmp, #0] |
54 | tst \tmp, #HWCAP_VFPv3D16 | 54 | tst \tmp, #HWCAP_VFPD32 |
55 | stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} | 55 | stcnel p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} |
56 | addne \base, \base, #32*4 @ step over unused register space | 56 | addeq \base, \base, #32*4 @ step over unused register space |
57 | #else | 57 | #else |
58 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 | 58 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 |
59 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field | 59 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field |
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f25e7ec8941..ce188028696 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
@@ -575,11 +575,14 @@ static int __init vfp_init(void) | |||
575 | elf_hwcap |= HWCAP_VFPv3; | 575 | elf_hwcap |= HWCAP_VFPv3; |
576 | 576 | ||
577 | /* | 577 | /* |
578 | * Check for VFPv3 D16. CPUs in this configuration | 578 | * Check for VFPv3 D16 and VFPv4 D16. CPUs in |
579 | * only have 16 x 64bit registers. | 579 | * this configuration only have 16 x 64bit |
580 | * registers. | ||
580 | */ | 581 | */ |
581 | if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) | 582 | if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) |
582 | elf_hwcap |= HWCAP_VFPv3D16; | 583 | elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */ |
584 | else | ||
585 | elf_hwcap |= HWCAP_VFPD32; | ||
583 | } | 586 | } |
584 | #endif | 587 | #endif |
585 | #ifdef CONFIG_NEON | 588 | #ifdef CONFIG_NEON |