diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-02-06 11:27:45 +0000 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-02-15 21:39:53 +0000 |
commit | 54cb3dbb4a1cccd6b1bffc169ff638f8e74daf44 (patch) | |
tree | 454b05810dc96b288eabcc4e11046adb0bc8b8ec | |
parent | 462f39a8c7496c95f4de91ef46d875f46e0fa271 (diff) | |
download | linux-54cb3dbb4a1cccd6b1bffc169ff638f8e74daf44.tar.bz2 |
ARM: vfp: fix vfp_sync_state()
The more I look at vfp_sync_state(), the more I believe it's trying
to do its job in a really obscure way.
Essentially, last_VFP_context[] tracks who owns the state in the VFP
hardware. If last_VFP_context[] is the context for the thread which
we're interested in, then the VFP hardware has context which is not
saved in the software state - so we need to bring the software state
up to date.
If last_VFP_context[] is for some other thread, we really don't care
what state the VFP hardware is in; it doesn't contain any information
pertinent to the thread we're trying to deal with - so don't touch
the hardware.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 36 |
1 files changed, 16 insertions, 20 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f60a5400a25b..86a57aeeda4a 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -444,32 +444,28 @@ void vfp_sync_state(struct thread_info *thread) void vfp_sync_state(struct thread_info *thread) { unsigned int cpu = get_cpu(); - u32 fpexc = fmrx(FPEXC); /* - * If VFP is enabled, the previous state was already saved and - * last_VFP_context updated. + * If the thread we're interested in is the current owner of the + * hardware VFP state, then we need to save its state. */ - if (fpexc & FPEXC_EN) - goto out; - - if (!last_VFP_context[cpu]) - goto out; + if (last_VFP_context[cpu] == &thread->vfpstate) { + u32 fpexc = fmrx(FPEXC); - /* - * Save the last VFP state on this CPU. - */ - fmxr(FPEXC, fpexc | FPEXC_EN); - vfp_save_state(last_VFP_context[cpu], fpexc); - fmxr(FPEXC, fpexc); + /* + * Save the last VFP state on this CPU. + */ + fmxr(FPEXC, fpexc | FPEXC_EN); + vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); + fmxr(FPEXC, fpexc & ~FPEXC_EN); - /* - * Set the context to NULL to force a reload the next time the thread - * uses the VFP. - */ - last_VFP_context[cpu] = NULL; + /* + * Set the context to NULL to force a reload the next time + * the thread uses the VFP. + */ + last_VFP_context[cpu] = NULL; + } -out: put_cpu(); } #endif |