*/
void vfp_testing_entry(void);
void vfp_support_entry(void);
+void vfp_null_entry(void);
-void (*vfp_vector)(void) = vfp_testing_entry;
-union vfp_state *last_VFP_context;
+void (*vfp_vector)(void) = vfp_null_entry;
+union vfp_state *last_VFP_context[NR_CPUS];
/*
* Dual-use variable.
{
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_EN) && 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_EN);
return NOTIFY_DONE;
}
*/
memset(vfp, 0, sizeof(union vfp_state));
- vfp->hard.fpexc = FPEXC_ENABLE;
+ vfp->hard.fpexc = FPEXC_EN;
vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
/*
* Disable VFP to ensure we initialise it first.
*/
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
}
/* 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;
}
/*
* Enable access to the VFP so we can handle the bounce.
*/
- fmxr(FPEXC, fpexc & ~(FPEXC_EXCEPTION|FPEXC_INV|FPEXC_UFC|FPEXC_IOC));
+ fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_INV|FPEXC_UFC|FPEXC_IOC));
orig_fpscr = fpscr = fmrx(FPSCR);
/*
* Modify fpscr to indicate the number of iterations remaining
*/
- if (fpexc & FPEXC_EXCEPTION) {
+ if (fpexc & FPEXC_EX) {
u32 len;
len = fpexc + (1 << FPEXC_LENGTH_BIT);
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
}
+static void vfp_enable(void *unused)
+{
+ u32 access = get_copro_access();
+
+ /*
+ * Enable full access to VFP (cp10 and cp11)
+ */
+ set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+}
+
+#include <linux/smp.h>
+
/*
* VFP support code initialisation.
*/
* The handler is already setup to just log calls, so
* we just need to read the VFPSID register.
*/
+ vfp_vector = vfp_testing_entry;
vfpsid = fmrx(FPSID);
+ barrier();
+ vfp_vector = vfp_null_entry;
printk(KERN_INFO "VFP support v0.3: ");
if (VFP_arch) {
} else if (vfpsid & FPSID_NODOUBLE) {
printk("no double precision support\n");
} else {
+ smp_call_function(vfp_enable, NULL, 1, 1);
+
VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
printk("implementor %02x architecture %d part %02x variant %x rev %x\n",
(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,