aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp/vfpmodule.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-07-09 12:41:33 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-07-09 12:41:33 -0400
commit19dad35fe0f10df8f0524f98037469e3a0dd1ec2 (patch)
tree30a39e6f54b9a92a389e99773b8691ad901344ae /arch/arm/vfp/vfpmodule.c
parentf8f2a8522a88aacd62a310ce49e8dac530d1b403 (diff)
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/vfpmodule.c')
-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)
89 union vfp_state *vfp = &thread->vfpstate; 89 union vfp_state *vfp = &thread->vfpstate;
90 unsigned int cpu; 90 unsigned int cpu;
91 91
92 memset(vfp, 0, sizeof(union vfp_state));
93
94 vfp->hard.fpexc = FPEXC_EN;
95 vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
96#ifdef CONFIG_SMP
97 vfp->hard.cpu = NR_CPUS;
98#endif
99
100 /* 92 /*
101 * Disable VFP to ensure we initialize it first. We must ensure 93 * Disable VFP to ensure we initialize it first. We must ensure
102 * that the modification of vfp_current_hw_state[] and hardware disable 94 * that the modification of vfp_current_hw_state[] and hardware
103 * are done for the same CPU and without preemption. 95 * disable are done for the same CPU and without preemption.
96 *
97 * Do this first to ensure that preemption won't overwrite our
98 * state saving should access to the VFP be enabled at this point.
104 */ 99 */
105 cpu = get_cpu(); 100 cpu = get_cpu();
106 if (vfp_current_hw_state[cpu] == vfp) 101 if (vfp_current_hw_state[cpu] == vfp)
107 vfp_current_hw_state[cpu] = NULL; 102 vfp_current_hw_state[cpu] = NULL;
108 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); 103 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
109 put_cpu(); 104 put_cpu();
105
106 memset(vfp, 0, sizeof(union vfp_state));
107
108 vfp->hard.fpexc = FPEXC_EN;
109 vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
110#ifdef CONFIG_SMP
111 vfp->hard.cpu = NR_CPUS;
112#endif
110} 113}
111 114
112static void vfp_thread_exit(struct thread_info *thread) 115static void vfp_thread_exit(struct thread_info *thread)