diff options
Diffstat (limited to 'arch/arm/vfp/vfpmodule.c')
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index aed05bc3c2ea..a63c4be99b36 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
@@ -63,14 +63,15 @@ static void vfp_thread_flush(struct thread_info *thread) | |||
63 | put_cpu(); | 63 | put_cpu(); |
64 | } | 64 | } |
65 | 65 | ||
66 | static void vfp_thread_release(struct thread_info *thread) | 66 | static void vfp_thread_exit(struct thread_info *thread) |
67 | { | 67 | { |
68 | /* release case: Per-thread VFP cleanup. */ | 68 | /* release case: Per-thread VFP cleanup. */ |
69 | union vfp_state *vfp = &thread->vfpstate; | 69 | union vfp_state *vfp = &thread->vfpstate; |
70 | unsigned int cpu = thread->cpu; | 70 | unsigned int cpu = get_cpu(); |
71 | 71 | ||
72 | if (last_VFP_context[cpu] == vfp) | 72 | if (last_VFP_context[cpu] == vfp) |
73 | last_VFP_context[cpu] = NULL; | 73 | last_VFP_context[cpu] = NULL; |
74 | put_cpu(); | ||
74 | } | 75 | } |
75 | 76 | ||
76 | /* | 77 | /* |
@@ -88,11 +89,13 @@ static void vfp_thread_release(struct thread_info *thread) | |||
88 | * but may change at any time. | 89 | * but may change at any time. |
89 | * - we could be preempted if tree preempt rcu is enabled, so | 90 | * - we could be preempted if tree preempt rcu is enabled, so |
90 | * it is unsafe to use thread->cpu. | 91 | * it is unsafe to use thread->cpu. |
91 | * THREAD_NOTIFY_RELEASE: | 92 | * THREAD_NOTIFY_EXIT |
92 | * - the thread (v) will not be running on any CPU; it is a dead thread. | 93 | * - the thread (v) will be running on the local CPU, so |
93 | * - thread->cpu will be the last CPU the thread ran on, which may not | 94 | * v === current_thread_info() |
94 | * be the current CPU. | 95 | * - thread->cpu is the local CPU number at the time it is accessed, |
95 | * - we could be preempted if tree preempt rcu is enabled. | 96 | * but may change at any time. |
97 | * - we could be preempted if tree preempt rcu is enabled, so | ||
98 | * it is unsafe to use thread->cpu. | ||
96 | */ | 99 | */ |
97 | static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) | 100 | static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) |
98 | { | 101 | { |
@@ -133,7 +136,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) | |||
133 | if (cmd == THREAD_NOTIFY_FLUSH) | 136 | if (cmd == THREAD_NOTIFY_FLUSH) |
134 | vfp_thread_flush(thread); | 137 | vfp_thread_flush(thread); |
135 | else | 138 | else |
136 | vfp_thread_release(thread); | 139 | vfp_thread_exit(thread); |
137 | 140 | ||
138 | return NOTIFY_DONE; | 141 | return NOTIFY_DONE; |
139 | } | 142 | } |
@@ -194,10 +197,13 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_ | |||
194 | } | 197 | } |
195 | 198 | ||
196 | /* | 199 | /* |
197 | * Update the FPSCR with the additional exception flags. | 200 | * If any of the status flags are set, update the FPSCR. |
198 | * Comparison instructions always return at least one of | 201 | * Comparison instructions always return at least one of |
199 | * these flags set. | 202 | * these flags set. |
200 | */ | 203 | */ |
204 | if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) | ||
205 | fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); | ||
206 | |||
201 | fpscr |= exceptions; | 207 | fpscr |= exceptions; |
202 | 208 | ||
203 | fmxr(FPSCR, fpscr); | 209 | fmxr(FPSCR, fpscr); |