diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2007-01-24 18:47:08 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-01-25 16:35:29 +0000 |
commit | c6428464894889e110418928e6b37dc2eb4cee56 (patch) | |
tree | 292410b297ef2332715aabd7a87ef9fe0c03de4a /arch/arm/vfp/vfpmodule.c | |
parent | 412489af76b5c0e4029d4406d93554c22a88fc73 (diff) |
[ARM] 4111/1: Allow VFP to work with thread migration on SMP
The current lazy saving of the VFP registers is no longer possible
with thread migration on SMP. This patch implements a per-CPU
vfp-state pointer and the saving of the VFP registers at every context
switch. The registers restoring is still performed in a lazy way.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
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.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 490d9d18a7d1..f1e5951dc721 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -28,7 +28,7 @@ void vfp_testing_entry(void); void vfp_support_entry(void); void (*vfp_vector)(void) = vfp_testing_entry; -union vfp_state *last_VFP_context; +union vfp_state *last_VFP_context[NR_CPUS]; /* * Dual-use variable. @@ -41,13 +41,35 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) { struct thread_info *thread = v; union vfp_state *vfp; + __u32 cpu = thread->cpu; if (likely(cmd == THREAD_NOTIFY_SWITCH)) { + u32 fpexc = fmrx(FPEXC); + +#ifdef CONFIG_SMP + /* + * On SMP, if VFP is enabled, save the old state in + * case the thread migrates to a different CPU. The + * restoring is done lazily. + */ + if ((fpexc & FPEXC_ENABLE) && last_VFP_context[cpu]) { + vfp_save_state(last_VFP_context[cpu], fpexc); + last_VFP_context[cpu]->hard.cpu = cpu; + } + /* + * Thread migration, just force the reloading of the + * state on the new CPU in case the VFP registers + * contain stale data. + */ + if (thread->vfpstate.hard.cpu != cpu) + last_VFP_context[cpu] = NULL; +#endif + /* * Always disable VFP so we can lazily save/restore the * old state. */ - fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE); + fmxr(FPEXC, fpexc & ~FPEXC_ENABLE); return NOTIFY_DONE; } @@ -68,8 +90,8 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) } /* flush and release case: Per-thread VFP cleanup. */ - if (last_VFP_context == vfp) - last_VFP_context = NULL; + if (last_VFP_context[cpu] == vfp) + last_VFP_context[cpu] = NULL; return NOTIFY_DONE; } |