@@ -55,6 +55,34 @@ extern unsigned int VFP_arch_feroceon __alias(VFP_arch);
5555 */
5656union vfp_state * vfp_current_hw_state [NR_CPUS ];
5757
58+ /*
59+ * Claim ownership of the VFP unit.
60+ *
61+ * The caller may change VFP registers until vfp_state_release() is called.
62+ *
63+ * local_bh_disable() is used to disable preemption and to disable VFP
64+ * processing in softirq context. On PREEMPT_RT kernels local_bh_disable() is
65+ * not sufficient because it only serializes soft interrupt related sections
66+ * via a local lock, but stays preemptible. Disabling preemption is the right
67+ * choice here as bottom half processing is always in thread context on RT
68+ * kernels so it implicitly prevents bottom half processing as well.
69+ */
70+ static void vfp_state_hold (void )
71+ {
72+ if (!IS_ENABLED (CONFIG_PREEMPT_RT ))
73+ local_bh_disable ();
74+ else
75+ preempt_disable ();
76+ }
77+
78+ static void vfp_state_release (void )
79+ {
80+ if (!IS_ENABLED (CONFIG_PREEMPT_RT ))
81+ local_bh_enable ();
82+ else
83+ preempt_enable ();
84+ }
85+
5886/*
5987 * Is 'thread's most up to date state stored in this CPUs hardware?
6088 * Must be called from non-preemptible context.
@@ -240,16 +268,15 @@ static void vfp_panic(char *reason, u32 inst)
240268/*
241269 * Process bitmask of exception conditions.
242270 */
243- static void vfp_raise_exceptions (u32 exceptions , u32 inst , u32 fpscr , struct pt_regs * regs )
271+ static int vfp_raise_exceptions (u32 exceptions , u32 inst , u32 fpscr )
244272{
245273 int si_code = 0 ;
246274
247275 pr_debug ("VFP: raising exceptions %08x\n" , exceptions );
248276
249277 if (exceptions == VFP_EXCEPTION_ERROR ) {
250278 vfp_panic ("unhandled bounce" , inst );
251- vfp_raise_sigfpe (FPE_FLTINV , regs );
252- return ;
279+ return FPE_FLTINV ;
253280 }
254281
255282 /*
@@ -277,8 +304,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
277304 RAISE (FPSCR_OFC , FPSCR_OFE , FPE_FLTOVF );
278305 RAISE (FPSCR_IOC , FPSCR_IOE , FPE_FLTINV );
279306
280- if (si_code )
281- vfp_raise_sigfpe (si_code , regs );
307+ return si_code ;
282308}
283309
284310/*
@@ -324,6 +350,8 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
324350static void VFP_bounce (u32 trigger , u32 fpexc , struct pt_regs * regs )
325351{
326352 u32 fpscr , orig_fpscr , fpsid , exceptions ;
353+ int si_code2 = 0 ;
354+ int si_code = 0 ;
327355
328356 pr_debug ("VFP: bounce: trigger %08x fpexc %08x\n" , trigger , fpexc );
329357
@@ -369,8 +397,8 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
369397 * unallocated VFP instruction but with FPSCR.IXE set and not
370398 * on VFP subarch 1.
371399 */
372- vfp_raise_exceptions (VFP_EXCEPTION_ERROR , trigger , fpscr , regs );
373- return ;
400+ si_code = vfp_raise_exceptions (VFP_EXCEPTION_ERROR , trigger , fpscr );
401+ goto exit ;
374402 }
375403
376404 /*
@@ -394,14 +422,14 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
394422 */
395423 exceptions = vfp_emulate_instruction (trigger , fpscr , regs );
396424 if (exceptions )
397- vfp_raise_exceptions (exceptions , trigger , orig_fpscr , regs );
425+ si_code2 = vfp_raise_exceptions (exceptions , trigger , orig_fpscr );
398426
399427 /*
400428 * If there isn't a second FP instruction, exit now. Note that
401429 * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
402430 */
403431 if ((fpexc & (FPEXC_EX | FPEXC_FP2V )) != (FPEXC_EX | FPEXC_FP2V ))
404- return ;
432+ goto exit ;
405433
406434 /*
407435 * The barrier() here prevents fpinst2 being read
@@ -413,7 +441,13 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
413441 emulate :
414442 exceptions = vfp_emulate_instruction (trigger , orig_fpscr , regs );
415443 if (exceptions )
416- vfp_raise_exceptions (exceptions , trigger , orig_fpscr , regs );
444+ si_code = vfp_raise_exceptions (exceptions , trigger , orig_fpscr );
445+ exit :
446+ vfp_state_release ();
447+ if (si_code2 )
448+ vfp_raise_sigfpe (si_code2 , regs );
449+ if (si_code )
450+ vfp_raise_sigfpe (si_code , regs );
417451}
418452
419453static void vfp_enable (void * unused )
@@ -512,11 +546,9 @@ static inline void vfp_pm_init(void) { }
512546 */
513547void vfp_sync_hwstate (struct thread_info * thread )
514548{
515- unsigned int cpu = get_cpu ();
549+ vfp_state_hold ();
516550
517- local_bh_disable ();
518-
519- if (vfp_state_in_hw (cpu , thread )) {
551+ if (vfp_state_in_hw (raw_smp_processor_id (), thread )) {
520552 u32 fpexc = fmrx (FPEXC );
521553
522554 /*
@@ -527,8 +559,7 @@ void vfp_sync_hwstate(struct thread_info *thread)
527559 fmxr (FPEXC , fpexc );
528560 }
529561
530- local_bh_enable ();
531- put_cpu ();
562+ vfp_state_release ();
532563}
533564
534565/* Ensure that the thread reloads the hardware VFP state on the next use. */
@@ -683,7 +714,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
683714 if (!user_mode (regs ))
684715 return vfp_kmode_exception (regs , trigger );
685716
686- local_bh_disable ();
717+ vfp_state_hold ();
687718 fpexc = fmrx (FPEXC );
688719
689720 /*
@@ -748,6 +779,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
748779 * replay the instruction that trapped.
749780 */
750781 fmxr (FPEXC , fpexc );
782+ vfp_state_release ();
751783 } else {
752784 /* Check for synchronous or asynchronous exceptions */
753785 if (!(fpexc & (FPEXC_EX | FPEXC_DEX ))) {
@@ -762,17 +794,17 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
762794 if (!(fpscr & FPSCR_IXE )) {
763795 if (!(fpscr & FPSCR_LENGTH_MASK )) {
764796 pr_debug ("not VFP\n" );
765- local_bh_enable ();
797+ vfp_state_release ();
766798 return - ENOEXEC ;
767799 }
768800 fpexc |= FPEXC_DEX ;
769801 }
770802 }
771803bounce : regs -> ARM_pc += 4 ;
804+ /* VFP_bounce() will invoke vfp_state_release() */
772805 VFP_bounce (trigger , fpexc , regs );
773806 }
774807
775- local_bh_enable ();
776808 return 0 ;
777809}
778810
@@ -837,7 +869,7 @@ void kernel_neon_begin(void)
837869 unsigned int cpu ;
838870 u32 fpexc ;
839871
840- local_bh_disable ();
872+ vfp_state_hold ();
841873
842874 /*
843875 * Kernel mode NEON is only allowed outside of hardirq context with
@@ -868,7 +900,7 @@ void kernel_neon_end(void)
868900{
869901 /* Disable the NEON/VFP unit. */
870902 fmxr (FPEXC , fmrx (FPEXC ) & ~FPEXC_EN );
871- local_bh_enable ();
903+ vfp_state_release ();
872904}
873905EXPORT_SYMBOL (kernel_neon_end );
874906
0 commit comments