Skip to content

Commit f26bdbe

Browse files
Sebastian Andrzej SiewiorRussell King (Oracle)
authored andcommitted
ARM: 9423/1: vfp: Provide vfp_state_hold() for VFP locking.
kernel_neon_begin() uses local_bh_disable() to ensure exclusive access to the VFP unit. This is broken on PREEMPT_RT because a BH disabled section remains preemptible on PREEMPT_RT. Introduce vfp_state_hold() which uses local_bh_disable() and preempt_disable() on PREEMPT_RT. Since softirqs are processed always in thread context, disabling preemption is enough to ensure that the current context won't get interrupted by something that is using the VFP. Use it in kernel_neon_begin(). Reviewed-by: Ard Biesheuvel <[email protected]> Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]>
1 parent ad8d1e3 commit f26bdbe

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

arch/arm/vfp/vfpmodule.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,34 @@ extern unsigned int VFP_arch_feroceon __alias(VFP_arch);
5555
*/
5656
union 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.
@@ -837,7 +865,7 @@ void kernel_neon_begin(void)
837865
unsigned int cpu;
838866
u32 fpexc;
839867

840-
local_bh_disable();
868+
vfp_state_hold();
841869

842870
/*
843871
* Kernel mode NEON is only allowed outside of hardirq context with
@@ -868,7 +896,7 @@ void kernel_neon_end(void)
868896
{
869897
/* Disable the NEON/VFP unit. */
870898
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
871-
local_bh_enable();
899+
vfp_state_release();
872900
}
873901
EXPORT_SYMBOL(kernel_neon_end);
874902

0 commit comments

Comments
 (0)