]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
ARM: 8991/1: use VFP assembler mnemonics if available
authorStefan Agner <stefan@agner.ch>
Thu, 9 Jul 2020 10:21:27 +0000 (11:21 +0100)
committerRussell King <rmk+kernel@armlinux.org.uk>
Tue, 21 Jul 2020 15:33:39 +0000 (16:33 +0100)
The integrated assembler of Clang 10 and earlier do not allow to access
the VFP registers through the coprocessor load/store instructions:
arch/arm/vfp/vfpmodule.c:342:2: error: invalid operand for instruction
        fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK));
        ^
arch/arm/vfp/vfpinstr.h:79:6: note: expanded from macro 'fmxr'
        asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr   " #_vfp_ ", %0"
            ^
<inline asm>:1:6: note: instantiated into assembly here
        mcr p10, 7, r0, cr8, cr0, 0 @ fmxr      FPEXC, r0
            ^

This has been addressed with Clang 11 [0]. However, to support earlier
versions of Clang and for better readability use of VFP assembler
mnemonics still is preferred.

Ideally we would replace this code with the unified assembler language
mnemonics vmrs/vmsr on call sites along with .fpu assembler directives.
The GNU assembler supports the .fpu directive at least since 2.17 (when
documentation has been added). Since Linux requires binutils 2.21 it is
safe to use .fpu directive. However, binutils does not allow to use
FPINST or FPINST2 as an argument to vmrs/vmsr instructions up to
binutils 2.24 (see binutils commit 16d02dc907c5):
arch/arm/vfp/vfphw.S: Assembler messages:
arch/arm/vfp/vfphw.S:162: Error: operand 0 must be FPSID or FPSCR pr FPEXC -- `vmsr FPINST,r6'
arch/arm/vfp/vfphw.S:165: Error: operand 0 must be FPSID or FPSCR pr FPEXC -- `vmsr FPINST2,r8'
arch/arm/vfp/vfphw.S:235: Error: operand 1 must be a VFP extension System Register -- `vmrs r3,FPINST'
arch/arm/vfp/vfphw.S:238: Error: operand 1 must be a VFP extension System Register -- `vmrs r12,FPINST2'

Use as-instr in Kconfig to check if FPINST/FPINST2 can be used. If they
can be used make use of .fpu directives and UAL VFP mnemonics for
register access.

This allows to build vfpmodule.c with Clang and its integrated assembler.

[0] https://reviews.llvm.org/D59733

Link: https://github.com/ClangBuiltLinux/linux/issues/905
Signed-off-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
arch/arm/Kconfig
arch/arm/Kconfig.assembler [new file with mode: 0644]
arch/arm/include/asm/vfp.h
arch/arm/include/asm/vfpmacros.h
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpinstr.h

index 2ac74904a3ce586aa003c56752c85bb613ef6f53..911f55a11c6363a88fd5102b4c56aff6cd081bf4 100644 (file)
@@ -2097,3 +2097,5 @@ source "drivers/firmware/Kconfig"
 if CRYPTO
 source "arch/arm/crypto/Kconfig"
 endif
+
+source "arch/arm/Kconfig.assembler"
diff --git a/arch/arm/Kconfig.assembler b/arch/arm/Kconfig.assembler
new file mode 100644 (file)
index 0000000..5cb31aa
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config AS_VFP_VMRS_FPINST
+       def_bool $(as-instr,.fpu vfpv2\nvmrs r0$(comma)FPINST)
+       help
+         Supported by binutils >= 2.24 and LLVM integrated assembler.
index 7157d2a30a49dd412525fe944fedd57828a6b45d..19928bfb4f9cdb729885e829b175e1527a1dd0d1 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef __ASM_VFP_H
 #define __ASM_VFP_H
 
+#ifndef CONFIG_AS_VFP_VMRS_FPINST
 #define FPSID                  cr0
 #define FPSCR                  cr1
 #define MVFR1                  cr6
@@ -16,6 +17,7 @@
 #define FPEXC                  cr8
 #define FPINST                 cr9
 #define FPINST2                        cr10
+#endif
 
 /* FPSID bits */
 #define FPSID_IMPLEMENTER_BIT  (24)
index 947ee5395e1fb39ac137d3f99fce499c349bc72a..ba0d4cb5377e0759b7b557ad2f65f9b091d17ca3 100644 (file)
@@ -8,7 +8,16 @@
 
 #include <asm/vfp.h>
 
-@ Macros to allow building with old toolkits (with no VFP support)
+#ifdef CONFIG_AS_VFP_VMRS_FPINST
+       .macro  VFPFMRX, rd, sysreg, cond
+       vmrs\cond       \rd, \sysreg
+       .endm
+
+       .macro  VFPFMXR, sysreg, rd, cond
+       vmsr\cond       \sysreg, \rd
+       .endm
+#else
+       @ Macros to allow building with old toolkits (with no VFP support)
        .macro  VFPFMRX, rd, sysreg, cond
        MRC\cond        p10, 7, \rd, \sysreg, cr0, 0    @ FMRX  \rd, \sysreg
        .endm
@@ -16,6 +25,7 @@
        .macro  VFPFMXR, sysreg, rd, cond
        MCR\cond        p10, 7, \rd, \sysreg, cr0, 0    @ FMXR  \sysreg, \rd
        .endm
+#endif
 
        @ read all the working registers back into the VFP
        .macro  VFPFLDMIA, base, tmp
index 29ed36b99d1d77ccc8678fb84557fcdb632d1cd8..4fcff9f59947d6985809111012b420eda4b84ccd 100644 (file)
@@ -78,6 +78,7 @@
 ENTRY(vfp_support_entry)
        DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10
 
+       .fpu    vfpv2
        ldr     r3, [sp, #S_PSR]        @ Neither lazy restore nor FP exceptions
        and     r3, r3, #MODE_MASK      @ are supported in kernel mode
        teq     r3, #USR_MODE
index 38dc154e39ffca84a1f03edb90f10726ac4c3b06..3c7938fd40aad6030972db8bddd9d96d6aba5416 100644 (file)
 #define FPSCR_C (1 << 29)
 #define FPSCR_V        (1 << 28)
 
-/*
- * Since we aren't building with -mfpu=vfp, we need to code
- * these instructions using their MRC/MCR equivalents.
- */
+#ifdef CONFIG_AS_VFP_VMRS_FPINST
+
+#define fmrx(_vfp_) ({                 \
+       u32 __v;                        \
+       asm(".fpu       vfpv2\n"        \
+           "vmrs       %0, " #_vfp_    \
+           : "=r" (__v) : : "cc");     \
+       __v;                            \
+ })
+
+#define fmxr(_vfp_,_var_)              \
+       asm(".fpu       vfpv2\n"        \
+           "vmsr       " #_vfp_ ", %0" \
+          : : "r" (_var_) : "cc")
+
+#else
+
 #define vfpreg(_vfp_) #_vfp_
 
 #define fmrx(_vfp_) ({                 \
@@ -79,6 +92,8 @@
        asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr   " #_vfp_ ", %0" \
           : : "r" (_var_) : "cc")
 
+#endif
+
 u32 vfp_single_cpdo(u32 inst, u32 fpscr);
 u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs);