]> Git Repo - linux.git/commitdiff
Merge branch 'devel-stable' into for-next
authorRussell King (Oracle) <[email protected]>
Mon, 14 Aug 2023 11:18:06 +0000 (12:18 +0100)
committerRussell King (Oracle) <[email protected]>
Mon, 14 Aug 2023 11:18:06 +0000 (12:18 +0100)
1  2 
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/entry-armv.S
arch/arm/vfp/vfpmodule.c

index 6a80d4be743b4f9d95d3b29e9c36f5ef65c863b3,f9c7111c1d65ffda6957e3b2623bc4389e0eac85..219cbc7e5d134b5bb0638d158266f809968977b6
@@@ -17,7 -17,7 +17,7 @@@
  #include <asm/glue-pf.h>
  #include <asm/mach/arch.h>
  #include <asm/thread_info.h>
 -#include <asm/memory.h>
 +#include <asm/page.h>
  #include <asm/mpu.h>
  #include <asm/procinfo.h>
  #include <asm/suspend.h>
@@@ -47,7 -47,6 +47,6 @@@ int main(void
    DEFINE(TI_CPU_DOMAIN,               offsetof(struct thread_info, cpu_domain));
    DEFINE(TI_CPU_SAVE,         offsetof(struct thread_info, cpu_context));
    DEFINE(TI_ABI_SYSCALL,      offsetof(struct thread_info, abi_syscall));
-   DEFINE(TI_USED_CP,          offsetof(struct thread_info, used_cp));
    DEFINE(TI_TP_VALUE,         offsetof(struct thread_info, tp_value));
    DEFINE(TI_FPSTATE,          offsetof(struct thread_info, fpstate));
  #ifdef CONFIG_VFP
index 76e8125d05d26030fa02fcb36e3ca3014bea1a26,682e92664b07ffd9fc457582248f6b4ef2a8390b..6150a716828c3eca335ed52df75fe7fdcf40eb57
@@@ -15,7 -15,7 +15,7 @@@
  #include <linux/init.h>
  
  #include <asm/assembler.h>
 -#include <asm/memory.h>
 +#include <asm/page.h>
  #include <asm/glue-df.h>
  #include <asm/glue-pf.h>
  #include <asm/vfpmacros.h>
@@@ -446,258 -446,26 +446,26 @@@ ENDPROC(__irq_usr
  __und_usr:
        usr_entry uaccess=0
  
-       mov     r2, r4
-       mov     r3, r5
-       @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the
-       @      faulting instruction depending on Thumb mode.
-       @ r3 = regs->ARM_cpsr
-       @
-       @ The emulation code returns using r9 if it has emulated the
-       @ instruction, or the more conventional lr if we are to treat
-       @ this as a real undefined instruction
-       @
-       badr    r9, ret_from_exception
        @ IRQs must be enabled before attempting to read the instruction from
        @ user space since that could cause a page/translation fault if the
        @ page table was modified by another CPU.
        enable_irq
  
-       tst     r3, #PSR_T_BIT                  @ Thumb mode?
-       bne     __und_usr_thumb
-       sub     r4, r2, #4                      @ ARM instr at LR - 4
- 1:    ldrt    r0, [r4]
-  ARM_BE8(rev  r0, r0)                         @ little endian instruction
-       uaccess_disable ip
-       @ r0 = 32-bit ARM instruction which caused the exception
-       @ r2 = PC value for the following instruction (:= regs->ARM_pc)
-       @ r4 = PC value for the faulting instruction
-       @ lr = 32-bit undefined instruction function
-       badr    lr, __und_usr_fault_32
-       b       call_fpe
- __und_usr_thumb:
-       @ Thumb instruction
-       sub     r4, r2, #2                      @ First half of thumb instr at LR - 2
- #if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
- /*
-  * Thumb-2 instruction handling.  Note that because pre-v6 and >= v6 platforms
-  * can never be supported in a single kernel, this code is not applicable at
-  * all when __LINUX_ARM_ARCH__ < 6.  This allows simplifying assumptions to be
-  * made about .arch directives.
-  */
- #if __LINUX_ARM_ARCH__ < 7
- /* If the target CPU may not be Thumb-2-capable, a run-time check is needed: */
-       ldr_va  r5, cpu_architecture
-       cmp     r5, #CPU_ARCH_ARMv7
-       blo     __und_usr_fault_16              @ 16bit undefined instruction
- /*
-  * The following code won't get run unless the running CPU really is v7, so
-  * coding round the lack of ldrht on older arches is pointless.  Temporarily
-  * override the assembler target arch with the minimum required instead:
-  */
-       .arch   armv6t2
+       tst     r5, #PSR_T_BIT                  @ Thumb mode?
+       mov     r1, #2                          @ set insn size to 2 for Thumb
+       bne     0f                              @ handle as Thumb undef exception
+ #ifdef CONFIG_FPE_NWFPE
+       adr     r9, ret_from_exception
+       bl      call_fpe                        @ returns via R9 on success
  #endif
- 2:    ldrht   r5, [r4]
- ARM_BE8(rev16 r5, r5)                         @ little endian instruction
-       cmp     r5, #0xe800                     @ 32bit instruction if xx != 0
-       blo     __und_usr_fault_16_pan          @ 16bit undefined instruction
- 3:    ldrht   r0, [r2]
- ARM_BE8(rev16 r0, r0)                         @ little endian instruction
+       mov     r1, #4                          @ set insn size to 4 for ARM
+ 0:    mov     r0, sp
        uaccess_disable ip
-       add     r2, r2, #2                      @ r2 is PC + 2, make it PC + 4
-       str     r2, [sp, #S_PC]                 @ it's a 2x16bit instr, update
-       orr     r0, r0, r5, lsl #16
-       badr    lr, __und_usr_fault_32
-       @ r0 = the two 16-bit Thumb instructions which caused the exception
-       @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
-       @ r4 = PC value for the first 16-bit Thumb instruction
-       @ lr = 32bit undefined instruction function
- #if __LINUX_ARM_ARCH__ < 7
- /* If the target arch was overridden, change it back: */
- #ifdef CONFIG_CPU_32v6K
-       .arch   armv6k
- #else
-       .arch   armv6
- #endif
- #endif /* __LINUX_ARM_ARCH__ < 7 */
- #else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */
-       b       __und_usr_fault_16
- #endif
+       bl      __und_fault
+       b       ret_from_exception
   UNWIND(.fnend)
  ENDPROC(__und_usr)
  
- /*
-  * The out of line fixup for the ldrt instructions above.
-  */
-       .pushsection .text.fixup, "ax"
-       .align  2
- 4:    str     r4, [sp, #S_PC]                 @ retry current instruction
-       ret     r9
-       .popsection
-       .pushsection __ex_table,"a"
-       .long   1b, 4b
- #if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
-       .long   2b, 4b
-       .long   3b, 4b
- #endif
-       .popsection
- /*
-  * Check whether the instruction is a co-processor instruction.
-  * If yes, we need to call the relevant co-processor handler.
-  *
-  * Note that we don't do a full check here for the co-processor
-  * instructions; all instructions with bit 27 set are well
-  * defined.  The only instructions that should fault are the
-  * co-processor instructions.  However, we have to watch out
-  * for the ARM6/ARM7 SWI bug.
-  *
-  * NEON is a special case that has to be handled here. Not all
-  * NEON instructions are co-processor instructions, so we have
-  * to make a special case of checking for them. Plus, there's
-  * five groups of them, so we have a table of mask/opcode pairs
-  * to check against, and if any match then we branch off into the
-  * NEON handler code.
-  *
-  * Emulators may wish to make use of the following registers:
-  *  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
-  *  r2  = PC value to resume execution after successful emulation
-  *  r9  = normal "successful" return address
-  *  r10 = this threads thread_info structure
-  *  lr  = unrecognised instruction return address
-  * IRQs enabled, FIQs enabled.
-  */
-       @
-       @ Fall-through from Thumb-2 __und_usr
-       @
- #ifdef CONFIG_NEON
-       get_thread_info r10                     @ get current thread
-       adr     r6, .LCneon_thumb_opcodes
-       b       2f
- #endif
- call_fpe:
-       get_thread_info r10                     @ get current thread
- #ifdef CONFIG_NEON
-       adr     r6, .LCneon_arm_opcodes
- 2:    ldr     r5, [r6], #4                    @ mask value
-       ldr     r7, [r6], #4                    @ opcode bits matching in mask
-       cmp     r5, #0                          @ end mask?
-       beq     1f
-       and     r8, r0, r5
-       cmp     r8, r7                          @ NEON instruction?
-       bne     2b
-       mov     r7, #1
-       strb    r7, [r10, #TI_USED_CP + 10]     @ mark CP#10 as used
-       strb    r7, [r10, #TI_USED_CP + 11]     @ mark CP#11 as used
-       b       do_vfp                          @ let VFP handler handle this
- 1:
- #endif
-       tst     r0, #0x08000000                 @ only CDP/CPRT/LDC/STC have bit 27
-       tstne   r0, #0x04000000                 @ bit 26 set on both ARM and Thumb-2
-       reteq   lr
-       and     r8, r0, #0x00000f00             @ mask out CP number
-       mov     r7, #1
-       add     r6, r10, r8, lsr #8             @ add used_cp[] array offset first
-       strb    r7, [r6, #TI_USED_CP]           @ set appropriate used_cp[]
- #ifdef CONFIG_IWMMXT
-       @ Test if we need to give access to iWMMXt coprocessors
-       ldr     r5, [r10, #TI_FLAGS]
-       rsbs    r7, r8, #(1 << 8)               @ CP 0 or 1 only
-       movscs  r7, r5, lsr #(TIF_USING_IWMMXT + 1)
-       bcs     iwmmxt_task_enable
- #endif
-  ARM( add     pc, pc, r8, lsr #6      )
-  THUMB(       lsr     r8, r8, #6              )
-  THUMB(       add     pc, r8                  )
-       nop
-       ret.w   lr                              @ CP#0
-       W(b)    do_fpe                          @ CP#1 (FPE)
-       W(b)    do_fpe                          @ CP#2 (FPE)
-       ret.w   lr                              @ CP#3
-       ret.w   lr                              @ CP#4
-       ret.w   lr                              @ CP#5
-       ret.w   lr                              @ CP#6
-       ret.w   lr                              @ CP#7
-       ret.w   lr                              @ CP#8
-       ret.w   lr                              @ CP#9
- #ifdef CONFIG_VFP
-       W(b)    do_vfp                          @ CP#10 (VFP)
-       W(b)    do_vfp                          @ CP#11 (VFP)
- #else
-       ret.w   lr                              @ CP#10 (VFP)
-       ret.w   lr                              @ CP#11 (VFP)
- #endif
-       ret.w   lr                              @ CP#12
-       ret.w   lr                              @ CP#13
-       ret.w   lr                              @ CP#14 (Debug)
-       ret.w   lr                              @ CP#15 (Control)
- #ifdef CONFIG_NEON
-       .align  6
- .LCneon_arm_opcodes:
-       .word   0xfe000000                      @ mask
-       .word   0xf2000000                      @ opcode
-       .word   0xff100000                      @ mask
-       .word   0xf4000000                      @ opcode
-       .word   0x00000000                      @ mask
-       .word   0x00000000                      @ opcode
- .LCneon_thumb_opcodes:
-       .word   0xef000000                      @ mask
-       .word   0xef000000                      @ opcode
-       .word   0xff100000                      @ mask
-       .word   0xf9000000                      @ opcode
-       .word   0x00000000                      @ mask
-       .word   0x00000000                      @ opcode
- #endif
- do_fpe:
-       add     r10, r10, #TI_FPSTATE           @ r10 = workspace
-       ldr_va  pc, fp_enter, tmp=r4            @ Call FP module USR entry point
- /*
-  * The FP module is called with these registers set:
-  *  r0  = instruction
-  *  r2  = PC+4
-  *  r9  = normal "successful" return address
-  *  r10 = FP workspace
-  *  lr  = unrecognised FP instruction return address
-  */
-       .pushsection .data
-       .align  2
- ENTRY(fp_enter)
-       .word   no_fp
-       .popsection
- ENTRY(no_fp)
-       ret     lr
- ENDPROC(no_fp)
- __und_usr_fault_32:
-       mov     r1, #4
-       b       1f
- __und_usr_fault_16_pan:
-       uaccess_disable ip
- __und_usr_fault_16:
-       mov     r1, #2
- 1:    mov     r0, sp
-       badr    lr, ret_from_exception
-       b       __und_fault
- ENDPROC(__und_usr_fault_32)
- ENDPROC(__und_usr_fault_16)
        .align  5
  __pabt_usr:
        usr_entry
@@@ -875,7 -643,7 +643,7 @@@ ENDPROC(__bad_stack
   * existing ones.  This mechanism should be used only for things that are
   * really small and justified, and not be abused freely.
   *
 - * See Documentation/arm/kernel_user_helpers.rst for formal definitions.
 + * See Documentation/arch/arm/kernel_user_helpers.rst for formal definitions.
   */
   THUMB(       .arm    )
  
diff --combined arch/arm/vfp/vfpmodule.c
index 1ba5078c10258b2b0ae1b334796bf5c78a431445,58a9442add24b2272ccb942bfabd469cf7b30f7b..7e8773a2d99d086383fa334b6a10dd9b3a26b011
@@@ -18,6 -18,7 +18,7 @@@
  #include <linux/uaccess.h>
  #include <linux/user.h>
  #include <linux/export.h>
+ #include <linux/perf_event.h>
  
  #include <asm/cp15.h>
  #include <asm/cputype.h>
  #include <asm/thread_notify.h>
  #include <asm/traps.h>
  #include <asm/vfp.h>
 +#include <asm/neon.h>
  
  #include "vfpinstr.h"
  #include "vfp.h"
  
- /*
-  * Our undef handlers (in entry.S)
-  */
- asmlinkage void vfp_support_entry(u32, void *, u32, u32);
  static bool have_vfp __ro_after_init;
  
  /*
   * Used in startup: set to non-zero if VFP checks fail
   * After startup, holds VFP architecture
   */
- static unsigned int __initdata VFP_arch;
+ static unsigned int VFP_arch;
+ #ifdef CONFIG_CPU_FEROCEON
+ extern unsigned int VFP_arch_feroceon __alias(VFP_arch);
+ #endif
  
  /*
   * The pointer to the vfpstate structure of the thread which currently
@@@ -314,13 -313,14 +314,14 @@@ static u32 vfp_emulate_instruction(u32 
                 * emulate it.
                 */
        }
+       perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc);
        return exceptions & ~VFP_NAN_FLAG;
  }
  
  /*
   * Package up a bounce condition.
   */
- void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
  {
        u32 fpscr, orig_fpscr, fpsid, exceptions;
  
        }
  
        if (fpexc & FPEXC_EX) {
- #ifndef CONFIG_CPU_FEROCEON
                /*
                 * Asynchronous exception. The instruction is read from FPINST
                 * and the interrupted instruction has to be restarted.
                 */
                trigger = fmrx(FPINST);
                regs->ARM_pc -= 4;
- #endif
        } else if (!(fpexc & FPEXC_DEX)) {
                /*
                 * Illegal combination of bits. It can be caused by an
                 * on VFP subarch 1.
                 */
                 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
-               goto exit;
+               return;
        }
  
        /*
         * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
         */
        if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))
-               goto exit;
+               return;
  
        /*
         * The barrier() here prevents fpinst2 being read
        exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
        if (exceptions)
                vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
-  exit:
-       local_bh_enable();
  }
  
  static void vfp_enable(void *unused)
@@@ -645,27 -641,6 +642,6 @@@ static int vfp_starting_cpu(unsigned in
        return 0;
  }
  
- /*
-  * Entered with:
-  *
-  *  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
-  *  r1  = thread_info pointer
-  *  r2  = PC value to resume execution after successful emulation
-  *  r3  = normal "successful" return address
-  *  lr  = unrecognised instruction return address
-  */
- asmlinkage void vfp_entry(u32 trigger, struct thread_info *ti, u32 resume_pc,
-                         u32 resume_return_address)
- {
-       if (unlikely(!have_vfp))
-               return;
-       local_bh_disable();
-       vfp_support_entry(trigger, ti, resume_pc, resume_return_address);
- }
- #ifdef CONFIG_KERNEL_MODE_NEON
  static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)
  {
        /*
        return 1;
  }
  
- static struct undef_hook vfp_kmode_exception_hook[] = {{
+ /*
+  * vfp_support_entry - Handle VFP exception
+  *
+  * @regs:     pt_regs structure holding the register state at exception entry
+  * @trigger:  The opcode of the instruction that triggered the exception
+  *
+  * Returns 0 if the exception was handled, or an error code otherwise.
+  */
+ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
+ {
+       struct thread_info *ti = current_thread_info();
+       u32 fpexc;
+       if (unlikely(!have_vfp))
+               return -ENODEV;
+       if (!user_mode(regs))
+               return vfp_kmode_exception(regs, trigger);
+       local_bh_disable();
+       fpexc = fmrx(FPEXC);
+       /*
+        * If the VFP unit was not enabled yet, we have to check whether the
+        * VFP state in the CPU's registers is the most recent VFP state
+        * associated with the process. On UP systems, we don't save the VFP
+        * state eagerly on a context switch, so we may need to save the
+        * VFP state to memory first, as it may belong to another process.
+        */
+       if (!(fpexc & FPEXC_EN)) {
+               /*
+                * Enable the VFP unit but mask the FP exception flag for the
+                * time being, so we can access all the registers.
+                */
+               fpexc |= FPEXC_EN;
+               fmxr(FPEXC, fpexc & ~FPEXC_EX);
+               /*
+                * Check whether or not the VFP state in the CPU's registers is
+                * the most recent VFP state associated with this task. On SMP,
+                * migration may result in multiple CPUs holding VFP states
+                * that belong to the same task, but only the most recent one
+                * is valid.
+                */
+               if (!vfp_state_in_hw(ti->cpu, ti)) {
+                       if (!IS_ENABLED(CONFIG_SMP) &&
+                           vfp_current_hw_state[ti->cpu] != NULL) {
+                               /*
+                                * This CPU is currently holding the most
+                                * recent VFP state associated with another
+                                * task, and we must save that to memory first.
+                                */
+                               vfp_save_state(vfp_current_hw_state[ti->cpu],
+                                              fpexc);
+                       }
+                       /*
+                        * We can now proceed with loading the task's VFP state
+                        * from memory into the CPU registers.
+                        */
+                       fpexc = vfp_load_state(&ti->vfpstate);
+                       vfp_current_hw_state[ti->cpu] = &ti->vfpstate;
+ #ifdef CONFIG_SMP
+                       /*
+                        * Record that this CPU is now the one holding the most
+                        * recent VFP state of the task.
+                        */
+                       ti->vfpstate.hard.cpu = ti->cpu;
+ #endif
+               }
+               if (fpexc & FPEXC_EX)
+                       /*
+                        * Might as well handle the pending exception before
+                        * retrying branch out before setting an FPEXC that
+                        * stops us reading stuff.
+                        */
+                       goto bounce;
+               /*
+                * No FP exception is pending: just enable the VFP and
+                * replay the instruction that trapped.
+                */
+               fmxr(FPEXC, fpexc);
+       } else {
+               /* Check for synchronous or asynchronous exceptions */
+               if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) {
+                       u32 fpscr = fmrx(FPSCR);
+                       /*
+                        * On some implementations of the VFP subarch 1,
+                        * setting FPSCR.IXE causes all the CDP instructions to
+                        * be bounced synchronously without setting the
+                        * FPEXC.EX bit
+                        */
+                       if (!(fpscr & FPSCR_IXE)) {
+                               if (!(fpscr & FPSCR_LENGTH_MASK)) {
+                                       pr_debug("not VFP\n");
+                                       local_bh_enable();
+                                       return -ENOEXEC;
+                               }
+                               fpexc |= FPEXC_DEX;
+                       }
+               }
+ bounce:               regs->ARM_pc += 4;
+               VFP_bounce(trigger, fpexc, regs);
+       }
+       local_bh_enable();
+       return 0;
+ }
+ static struct undef_hook neon_support_hook[] = {{
        .instr_mask     = 0xfe000000,
        .instr_val      = 0xf2000000,
-       .cpsr_mask      = MODE_MASK | PSR_T_BIT,
-       .cpsr_val       = SVC_MODE,
-       .fn             = vfp_kmode_exception,
+       .cpsr_mask      = PSR_T_BIT,
+       .cpsr_val       = 0,
+       .fn             = vfp_support_entry,
  }, {
        .instr_mask     = 0xff100000,
        .instr_val      = 0xf4000000,
-       .cpsr_mask      = MODE_MASK | PSR_T_BIT,
-       .cpsr_val       = SVC_MODE,
-       .fn             = vfp_kmode_exception,
+       .cpsr_mask      = PSR_T_BIT,
+       .cpsr_val       = 0,
+       .fn             = vfp_support_entry,
  }, {
        .instr_mask     = 0xef000000,
        .instr_val      = 0xef000000,
-       .cpsr_mask      = MODE_MASK | PSR_T_BIT,
-       .cpsr_val       = SVC_MODE | PSR_T_BIT,
-       .fn             = vfp_kmode_exception,
+       .cpsr_mask      = PSR_T_BIT,
+       .cpsr_val       = PSR_T_BIT,
+       .fn             = vfp_support_entry,
  }, {
        .instr_mask     = 0xff100000,
        .instr_val      = 0xf9000000,
-       .cpsr_mask      = MODE_MASK | PSR_T_BIT,
-       .cpsr_val       = SVC_MODE | PSR_T_BIT,
-       .fn             = vfp_kmode_exception,
- }, {
-       .instr_mask     = 0x0c000e00,
-       .instr_val      = 0x0c000a00,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = SVC_MODE,
-       .fn             = vfp_kmode_exception,
+       .cpsr_mask      = PSR_T_BIT,
+       .cpsr_val       = PSR_T_BIT,
+       .fn             = vfp_support_entry,
  }};
  
- static int __init vfp_kmode_exception_hook_init(void)
- {
-       int i;
+ static struct undef_hook vfp_support_hook = {
+       .instr_mask     = 0x0c000e00,
+       .instr_val      = 0x0c000a00,
+       .fn             = vfp_support_entry,
+ };
  
-       for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++)
-               register_undef_hook(&vfp_kmode_exception_hook[i]);
-       return 0;
- }
- subsys_initcall(vfp_kmode_exception_hook_init);
+ #ifdef CONFIG_KERNEL_MODE_NEON
  
  /*
   * Kernel-side NEON support functions
@@@ -833,8 -912,11 +913,11 @@@ static int __init vfp_init(void
                 * for NEON if the hardware has the MVFR registers.
                 */
                if (IS_ENABLED(CONFIG_NEON) &&
-                  (fmrx(MVFR1) & 0x000fff00) == 0x00011100)
+                   (fmrx(MVFR1) & 0x000fff00) == 0x00011100) {
                        elf_hwcap |= HWCAP_NEON;
+                       for (int i = 0; i < ARRAY_SIZE(neon_support_hook); i++)
+                               register_undef_hook(&neon_support_hook[i]);
+               }
  
                if (IS_ENABLED(CONFIG_VFPv3)) {
                        u32 mvfr0 = fmrx(MVFR0);
  
        have_vfp = true;
  
+       register_undef_hook(&vfp_support_hook);
        thread_register_notifier(&vfp_notifier_block);
        vfp_pm_init();
  
This page took 0.104107 seconds and 4 git commands to generate.