Commit 5aaf254409f8d58229107b59507a8235b715a960

Authored by Tony Lindgren
Committed by Russell King
1 parent e513f8bf24

ARM: 6203/1: Make VFPv3 usable on ARMv6

MVFR0 and MVFR1 are only available starting with ARM1136 r1p0 release
according to "B.5 VFP changes" in DDI0211F_arm1136_r1p0_trm.pdf. This is
also when TLS register got added, so we can use HAS_TLS also to test for
MVFR0 and MVFR1.

Otherwise VFPFMRX and VFPFMXR access fails and we get:

Internal error: Oops - undefined instruction: 0 [#1]
PC is at no_old_VFP_process+0x8/0x3c
LR is at __und_svc+0x48/0x80
...

Signed-off-by: Tony Lindgren <tony@atomide.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Showing 2 changed files with 25 additions and 3 deletions Side-by-side Diff

arch/arm/include/asm/vfpmacros.h
... ... @@ -3,6 +3,8 @@
3 3 *
4 4 * Assembler-only file containing VFP macros and register definitions.
5 5 */
  6 +#include <asm/hwcap.h>
  7 +
6 8 #include "vfp.h"
7 9  
8 10 @ Macros to allow building with old toolkits (with no VFP support)
9 11  
... ... @@ -22,12 +24,20 @@
22 24 LDC p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d0-d15}
23 25 #endif
24 26 #ifdef CONFIG_VFPv3
  27 +#if __LINUX_ARM_ARCH__ <= 6
  28 + ldr \tmp, =elf_hwcap @ may not have MVFR regs
  29 + ldr \tmp, [\tmp, #0]
  30 + tst \tmp, #HWCAP_VFPv3D16
  31 + ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31}
  32 + addne \base, \base, #32*4 @ step over unused register space
  33 +#else
25 34 VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0
26 35 and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field
27 36 cmp \tmp, #2 @ 32 x 64bit registers?
28 37 ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31}
29 38 addne \base, \base, #32*4 @ step over unused register space
30 39 #endif
  40 +#endif
31 41 .endm
32 42  
33 43 @ write all the working registers out of the VFP
34 44  
... ... @@ -38,11 +48,19 @@
38 48 STC p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d0-d15}
39 49 #endif
40 50 #ifdef CONFIG_VFPv3
  51 +#if __LINUX_ARM_ARCH__ <= 6
  52 + ldr \tmp, =elf_hwcap @ may not have MVFR regs
  53 + ldr \tmp, [\tmp, #0]
  54 + tst \tmp, #HWCAP_VFPv3D16
  55 + stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31}
  56 + addne \base, \base, #32*4 @ step over unused register space
  57 +#else
41 58 VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0
42 59 and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field
43 60 cmp \tmp, #2 @ 32 x 64bit registers?
44 61 stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31}
45 62 addne \base, \base, #32*4 @ step over unused register space
  63 +#endif
46 64 #endif
47 65 .endm
arch/arm/vfp/vfpmodule.c
... ... @@ -15,6 +15,7 @@
15 15 #include <linux/sched.h>
16 16 #include <linux/init.h>
17 17  
  18 +#include <asm/cputype.h>
18 19 #include <asm/thread_notify.h>
19 20 #include <asm/vfp.h>
20 21  
21 22  
... ... @@ -549,10 +550,13 @@
549 550 /*
550 551 * Check for the presence of the Advanced SIMD
551 552 * load/store instructions, integer and single
552   - * precision floating point operations.
  553 + * precision floating point operations. Only check
  554 + * for NEON if the hardware has the MVFR registers.
553 555 */
554   - if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
555   - elf_hwcap |= HWCAP_NEON;
  556 + if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
  557 + if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
  558 + elf_hwcap |= HWCAP_NEON;
  559 + }
556 560 #endif
557 561 }
558 562 return 0;