]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/arm/vfp/vfpmodule.c
Update vfpmodule.c
[mirror_ubuntu-artful-kernel.git] / arch / arm / vfp / vfpmodule.c
index a71a48e71fffa8626fe90106815376c44bbe679b..d6c0a5a0a5ae3510db3ace5e3f5d341075193f99 100644 (file)
@@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
                 * case the thread migrates to a different CPU. The
                 * restoring is done lazily.
                 */
-               if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
+               if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
+                       /* vfp_save_state oopses on VFP11 if EX bit set */
+                       fmxr(FPEXC, fpexc & ~FPEXC_EX);
                        vfp_save_state(vfp_current_hw_state[cpu], fpexc);
+               }
 #endif
 
                /*
@@ -463,13 +466,16 @@ static int vfp_pm_suspend(void)
        /* if vfp is on, then save state for resumption */
        if (fpexc & FPEXC_EN) {
                pr_debug("%s: saving vfp state\n", __func__);
+               /* vfp_save_state oopses on VFP11 if EX bit set */
+               fmxr(FPEXC, fpexc & ~FPEXC_EX);
                vfp_save_state(&ti->vfpstate, fpexc);
 
                /* disable, just in case */
                fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
        } else if (vfp_current_hw_state[ti->cpu]) {
 #ifndef CONFIG_SMP
-               fmxr(FPEXC, fpexc | FPEXC_EN);
+               /* vfp_save_state oopses on VFP11 if EX bit set */
+               fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
                vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
                fmxr(FPEXC, fpexc);
 #endif
@@ -532,7 +538,8 @@ void vfp_sync_hwstate(struct thread_info *thread)
                /*
                 * Save the last VFP state on this CPU.
                 */
-               fmxr(FPEXC, fpexc | FPEXC_EN);
+               /* vfp_save_state oopses on VFP11 if EX bit set */
+               fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
                vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
                fmxr(FPEXC, fpexc);
        }
@@ -604,6 +611,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
        struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
        unsigned long fpexc;
        int err = 0;
+       u32 fpsid = fmrx(FPSID);
 
        /* Disable VFP to avoid corrupting the new thread state. */
        vfp_flush_hwstate(thread);
@@ -627,8 +635,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
        /* Ensure the VFP is enabled. */
        fpexc |= FPEXC_EN;
 
-       /* Ensure FPINST2 is invalid and the exception flag is cleared. */
-       fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+       /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */
+       if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) {
+               /* Ensure FPINST2 is invalid and the exception flag is cleared. */
+               fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+       }
+
        hwstate->fpexc = fpexc;
 
        __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
@@ -698,7 +710,8 @@ void kernel_neon_begin(void)
        cpu = get_cpu();
 
        fpexc = fmrx(FPEXC) | FPEXC_EN;
-       fmxr(FPEXC, fpexc);
+       /* vfp_save_state oopses on VFP11 if EX bit set */
+       fmxr(FPEXC, fpexc & ~FPEXC_EX);
 
        /*
         * Save the userland NEON/VFP state. Under UP,