aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-07-09 17:41:33 +0100
committerChristian Neumüller <cn00@gmx.at>2014-12-30 12:53:20 +0100
commite123d36f95b22fea6ebfc8afd609bfac871c0d73 (patch)
tree919a1d622f4705f2f6a89b4d6be9a1ccf7b68bf7
parent37119c4ee25e1b163bec3d9d471fae6cb37bb832 (diff)
downloadkernel_samsung_smdk4412-e123d36f95b22fea6ebfc8afd609bfac871c0d73.zip
kernel_samsung_smdk4412-e123d36f95b22fea6ebfc8afd609bfac871c0d73.tar.gz
kernel_samsung_smdk4412-e123d36f95b22fea6ebfc8afd609bfac871c0d73.tar.bz2
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. Change-Id: I93922d95f641aa989b2acefe009a656e27d4d9bf Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Lanchon <lanchon@gmail.com>
-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 9245b86..fe2913c 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -90,24 +90,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)