summaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-07-09 17:41:33 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-07-09 17:41:33 +0100
commit19dad35fe0f10df8f0524f98037469e3a0dd1ec2 (patch)
tree30a39e6f54b9a92a389e99773b8691ad901344ae /arch/arm/vfp
parentf8f2a8522a88aacd62a310ce49e8dac530d1b403 (diff)
downloadlinux-stable-19dad35fe0f10df8f0524f98037469e3a0dd1ec2.tar.gz
linux-stable-19dad35fe0f10df8f0524f98037469e3a0dd1ec2.tar.bz2
linux-stable-19dad35fe0f10df8f0524f98037469e3a0dd1ec2.zip
ARM: vfp: ensure that thread flushing works if preempted
Prevent a preemption event causing the initialized VFP state being overwritten by ensuring that the VFP hardware access is disabled prior to starting initialization. We can then do this in safety while still allowing preemption to occur. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfpmodule.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 08ff93fa533c..0a96f71f0abd 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -89,24 +89,27 @@ static void vfp_thread_flush(struct thread_info *thread)
union vfp_state *vfp = &thread->vfpstate;
unsigned int cpu;
- memset(vfp, 0, sizeof(union vfp_state));
-
- vfp->hard.fpexc = FPEXC_EN;
- vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
-#ifdef CONFIG_SMP
- vfp->hard.cpu = NR_CPUS;
-#endif
-
/*
* Disable VFP to ensure we initialize it first. We must ensure
- * that the modification of vfp_current_hw_state[] and hardware disable
- * are done for the same CPU and without preemption.
+ * that the modification of vfp_current_hw_state[] and hardware
+ * disable are done for the same CPU and without preemption.
+ *
+ * Do this first to ensure that preemption won't overwrite our
+ * state saving should access to the VFP be enabled at this point.
*/
cpu = get_cpu();
if (vfp_current_hw_state[cpu] == vfp)
vfp_current_hw_state[cpu] = NULL;
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
put_cpu();
+
+ memset(vfp, 0, sizeof(union vfp_state));
+
+ vfp->hard.fpexc = FPEXC_EN;
+ vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
+#ifdef CONFIG_SMP
+ vfp->hard.cpu = NR_CPUS;
+#endif
}
static void vfp_thread_exit(struct thread_info *thread)