summaryrefslogtreecommitdiff
path: root/arch/arm/vfp/vfpmodule.c
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2024-10-02 17:15:32 +0100
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2024-11-12 16:41:46 +0000
commitf26bdbe1fa9f79fa8cb0d0bf39303c3573c60552 (patch)
tree38b5b3dea42e33bfed587f8e4e4b3698c413bcbb /arch/arm/vfp/vfpmodule.c
parentad8d1e323dd37f91d0c973e2a74c7b9054219adc (diff)
downloadlwn-f26bdbe1fa9f79fa8cb0d0bf39303c3573c60552.tar.gz
lwn-f26bdbe1fa9f79fa8cb0d0bf39303c3573c60552.zip
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 <ardb@kernel.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'arch/arm/vfp/vfpmodule.c')
-rw-r--r--arch/arm/vfp/vfpmodule.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index b68efe643a12..63de164c7fc7 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -56,6 +56,34 @@ extern unsigned int VFP_arch_feroceon __alias(VFP_arch);
union vfp_state *vfp_current_hw_state[NR_CPUS];
/*
+ * Claim ownership of the VFP unit.
+ *
+ * The caller may change VFP registers until vfp_state_release() is called.
+ *
+ * local_bh_disable() is used to disable preemption and to disable VFP
+ * processing in softirq context. On PREEMPT_RT kernels local_bh_disable() is
+ * not sufficient because it only serializes soft interrupt related sections
+ * via a local lock, but stays preemptible. Disabling preemption is the right
+ * choice here as bottom half processing is always in thread context on RT
+ * kernels so it implicitly prevents bottom half processing as well.
+ */
+static void vfp_state_hold(void)
+{
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+ local_bh_disable();
+ else
+ preempt_disable();
+}
+
+static void vfp_state_release(void)
+{
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+ local_bh_enable();
+ else
+ preempt_enable();
+}
+
+/*
* Is 'thread's most up to date state stored in this CPUs hardware?
* Must be called from non-preemptible context.
*/
@@ -837,7 +865,7 @@ void kernel_neon_begin(void)
unsigned int cpu;
u32 fpexc;
- local_bh_disable();
+ vfp_state_hold();
/*
* Kernel mode NEON is only allowed outside of hardirq context with
@@ -868,7 +896,7 @@ void kernel_neon_end(void)
{
/* Disable the NEON/VFP unit. */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
- local_bh_enable();
+ vfp_state_release();
}
EXPORT_SYMBOL(kernel_neon_end);