Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tony Lindgren and committed by
Russell King
5aaf2544 e513f8bf

+25 -3
+18
arch/arm/include/asm/vfpmacros.h
··· 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) ··· 24 22 LDC p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d0-d15} 25 23 #endif 26 24 #ifdef CONFIG_VFPv3 25 + #if __LINUX_ARM_ARCH__ <= 6 26 + ldr \tmp, =elf_hwcap @ may not have MVFR regs 27 + ldr \tmp, [\tmp, #0] 28 + tst \tmp, #HWCAP_VFPv3D16 29 + ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} 30 + addne \base, \base, #32*4 @ step over unused register space 31 + #else 27 32 VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 28 33 and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field 29 34 cmp \tmp, #2 @ 32 x 64bit registers? 30 35 ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} 31 36 addne \base, \base, #32*4 @ step over unused register space 37 + #endif 32 38 #endif 33 39 .endm 34 40 ··· 48 38 STC p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d0-d15} 49 39 #endif 50 40 #ifdef CONFIG_VFPv3 41 + #if __LINUX_ARM_ARCH__ <= 6 42 + ldr \tmp, =elf_hwcap @ may not have MVFR regs 43 + ldr \tmp, [\tmp, #0] 44 + tst \tmp, #HWCAP_VFPv3D16 45 + stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} 46 + addne \base, \base, #32*4 @ step over unused register space 47 + #else 51 48 VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 52 49 and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field 53 50 cmp \tmp, #2 @ 32 x 64bit registers? 54 51 stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} 55 52 addne \base, \base, #32*4 @ step over unused register space 53 + #endif 56 54 #endif 57 55 .endm
+7 -3
arch/arm/vfp/vfpmodule.c
··· 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 ··· 550 549 /* 551 550 * Check for the presence of the Advanced SIMD 552 551 * load/store instructions, integer and single 553 - * precision floating point operations. 552 + * precision floating point operations. Only check 553 + * for NEON if the hardware has the MVFR registers. 554 554 */ 555 - if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) 556 - elf_hwcap |= HWCAP_NEON; 555 + if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 556 + if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) 557 + elf_hwcap |= HWCAP_NEON; 558 + } 557 559 #endif 558 560 } 559 561 return 0;