Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / arm / vfp / vfpmodule.c
index 03486be..4178f6c 100644 (file)
@@ -9,12 +9,13 @@
  * published by the Free Software Foundation.
  */
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+
+#include <asm/thread_notify.h>
 #include <asm/vfp.h>
 
 #include "vfpinstr.h"
@@ -36,38 +37,55 @@ union vfp_state *last_VFP_context;
  */
 unsigned int VFP_arch;
 
-/*
- * Per-thread VFP initialisation.
- */
-void vfp_flush_thread(union vfp_state *vfp)
+static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
 {
-       memset(vfp, 0, sizeof(union vfp_state));
+       struct thread_info *thread = v;
+       union vfp_state *vfp = &thread->vfpstate;
 
-       vfp->hard.fpexc = FPEXC_ENABLE;
-       vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
+       switch (cmd) {
+       case THREAD_NOTIFY_FLUSH:
+               /*
+                * Per-thread VFP initialisation.
+                */
+               memset(vfp, 0, sizeof(union vfp_state));
 
-       /*
-        * Disable VFP to ensure we initialise it first.
-        */
-       fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+               vfp->hard.fpexc = FPEXC_ENABLE;
+               vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
 
-       /*
-        * Ensure we don't try to overwrite our newly initialised
-        * state information on the first fault.
-        */
-       if (last_VFP_context == vfp)
-               last_VFP_context = NULL;
-}
+               /*
+                * Disable VFP to ensure we initialise it first.
+                */
+               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
 
-/*
- * Per-thread VFP cleanup.
- */
-void vfp_release_thread(union vfp_state *vfp)
-{
-       if (last_VFP_context == vfp)
-               last_VFP_context = NULL;
+               /*
+                * FALLTHROUGH: Ensure we don't try to overwrite our newly
+                * initialised state information on the first fault.
+                */
+
+       case THREAD_NOTIFY_RELEASE:
+               /*
+                * Per-thread VFP cleanup.
+                */
+               if (last_VFP_context == vfp)
+                       last_VFP_context = NULL;
+               break;
+
+       case THREAD_NOTIFY_SWITCH:
+               /*
+                * Always disable VFP so we can lazily save/restore the
+                * old state.
+                */
+               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+               break;
+       }
+
+       return NOTIFY_DONE;
 }
 
+static struct notifier_block vfp_notifier_block = {
+       .notifier_call  = vfp_notifier,
+};
+
 /*
  * Raise a SIGFPE for the current process.
  * sicode describes the signal being raised.
@@ -113,7 +131,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
 
        pr_debug("VFP: raising exceptions %08x\n", exceptions);
 
-       if (exceptions == (u32)-1) {
+       if (exceptions == VFP_EXCEPTION_ERROR) {
                vfp_panic("unhandled bounce");
                vfp_raise_sigfpe(0, regs);
                return;
@@ -152,7 +170,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
  */
 static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
 {
-       u32 exceptions = (u32)-1;
+       u32 exceptions = VFP_EXCEPTION_ERROR;
 
        pr_debug("VFP: emulate: INST=0x%08x SCR=0x%08x\n", inst, fpscr);
 
@@ -281,6 +299,8 @@ static int __init vfp_init(void)
                        (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
                        (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
                vfp_vector = vfp_support_entry;
+
+               thread_register_notifier(&vfp_notifier_block);
        }
        return 0;
 }