Pull button into test branch
[pandora-kernel.git] / arch / arm / vfp / vfpmodule.c
index 9d265d5..e26cc1f 100644 (file)
@@ -40,10 +40,19 @@ unsigned int VFP_arch;
 static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
 {
        struct thread_info *thread = v;
-       union vfp_state *vfp = &thread->vfpstate;
+       union vfp_state *vfp;
 
-       switch (cmd) {
-       case THREAD_NOTIFY_FLUSH:
+       if (likely(cmd == THREAD_NOTIFY_SWITCH)) {
+               /*
+                * Always disable VFP so we can lazily save/restore the
+                * old state.
+                */
+               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+               return NOTIFY_DONE;
+       }
+
+       vfp = &thread->vfpstate;
+       if (cmd == THREAD_NOTIFY_FLUSH) {
                /*
                 * Per-thread VFP initialisation.
                 */
@@ -56,29 +65,12 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                 * Disable VFP to ensure we initialise it first.
                 */
                fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
-
-               /*
-                * 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;
        }
 
+       /* flush and release case: Per-thread VFP cleanup. */
+       if (last_VFP_context == vfp)
+               last_VFP_context = NULL;
+
        return NOTIFY_DONE;
 }
 
@@ -98,7 +90,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
 
        info.si_signo = SIGFPE;
        info.si_code = sicode;
-       info.si_addr = (void *)(instruction_pointer(regs) - 4);
+       info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
 
        /*
         * This is the same as NWFPE, because it's not clear what
@@ -131,7 +123,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;
@@ -156,6 +148,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
        /*
         * These are arranged in priority order, least to highest.
         */
+       RAISE(FPSCR_DZC, FPSCR_DZE, FPE_FLTDIV);
        RAISE(FPSCR_IXC, FPSCR_IXE, FPE_FLTRES);
        RAISE(FPSCR_UFC, FPSCR_UFE, FPE_FLTUND);
        RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
@@ -170,7 +163,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);
 
@@ -270,13 +263,24 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
        if (exceptions)
                vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
 }
+
 /*
  * VFP support code initialisation.
  */
 static int __init vfp_init(void)
 {
        unsigned int vfpsid;
+       unsigned int cpu_arch = cpu_architecture();
+       u32 access = 0;
+
+       if (cpu_arch >= CPU_ARCH_ARMv6) {
+               access = get_copro_access();
+
+               /*
+                * Enable full access to VFP (cp10 and cp11)
+                */
+               set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+       }
 
        /*
         * First check that there is a VFP that we can use.
@@ -288,6 +292,12 @@ static int __init vfp_init(void)
        printk(KERN_INFO "VFP support v0.3: ");
        if (VFP_arch) {
                printk("not present\n");
+
+               /*
+                * Restore the copro access register.
+                */
+               if (cpu_arch >= CPU_ARCH_ARMv6)
+                       set_copro_access(access);
        } else if (vfpsid & FPSID_NODOUBLE) {
                printk("no double precision support\n");
        } else {
@@ -298,9 +308,16 @@ static int __init vfp_init(void)
                        (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
                        (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);
+
+               /*
+                * We detected VFP, and the support code is
+                * in place; report VFP support to userspace.
+                */
+               elf_hwcap |= HWCAP_VFP;
        }
        return 0;
 }