]> Pileus Git - ~andy/linux/blobdiff - arch/mips/include/asm/fpu.h
nfsd: fix lost nfserrno() call in nfsd_setattr()
[~andy/linux] / arch / mips / include / asm / fpu.h
index d088e5db49032bf3d2ed0f050ac49eb889446e8f..6b9749540edffedf8903b0384cb8a505d1054edd 100644 (file)
@@ -33,11 +33,50 @@ extern void _init_fpu(void);
 extern void _save_fp(struct task_struct *);
 extern void _restore_fp(struct task_struct *);
 
-#define __enable_fpu()                                                 \
-do {                                                                   \
-       set_c0_status(ST0_CU1);                                         \
-       enable_fpu_hazard();                                            \
-} while (0)
+/*
+ * This enum specifies a mode in which we want the FPU to operate, for cores
+ * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT
+ * purposefully have the values 0 & 1 respectively, so that an integer value
+ * of Status.FR can be trivially casted to the corresponding enum fpu_mode.
+ */
+enum fpu_mode {
+       FPU_32BIT = 0,          /* FR = 0 */
+       FPU_64BIT,              /* FR = 1 */
+       FPU_AS_IS,
+};
+
+static inline int __enable_fpu(enum fpu_mode mode)
+{
+       int fr;
+
+       switch (mode) {
+       case FPU_AS_IS:
+               /* just enable the FPU in its current mode */
+               set_c0_status(ST0_CU1);
+               enable_fpu_hazard();
+               return 0;
+
+       case FPU_64BIT:
+#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
+               /* we only have a 32-bit FPU */
+               return SIGFPE;
+#endif
+               /* fall through */
+       case FPU_32BIT:
+               /* set CU1 & change FR appropriately */
+               fr = (int)mode;
+               change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
+               enable_fpu_hazard();
+
+               /* check FR has the desired value */
+               return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE;
+
+       default:
+               BUG();
+       }
+
+       return SIGFPE;
+}
 
 #define __disable_fpu()                                                        \
 do {                                                                   \
@@ -45,19 +84,6 @@ do {                                                                 \
        disable_fpu_hazard();                                           \
 } while (0)
 
-#define enable_fpu()                                                   \
-do {                                                                   \
-       if (cpu_has_fpu)                                                \
-               __enable_fpu();                                         \
-} while (0)
-
-#define disable_fpu()                                                  \
-do {                                                                   \
-       if (cpu_has_fpu)                                                \
-               __disable_fpu();                                        \
-} while (0)
-
-
 #define clear_fpu_owner()      clear_thread_flag(TIF_USEDFPU)
 
 static inline int __is_fpu_owner(void)
@@ -70,27 +96,46 @@ static inline int is_fpu_owner(void)
        return cpu_has_fpu && __is_fpu_owner();
 }
 
-static inline void __own_fpu(void)
+static inline int __own_fpu(void)
 {
-       __enable_fpu();
+       enum fpu_mode mode;
+       int ret;
+
+       mode = !test_thread_flag(TIF_32BIT_FPREGS);
+       ret = __enable_fpu(mode);
+       if (ret)
+               return ret;
+
        KSTK_STATUS(current) |= ST0_CU1;
+       if (mode == FPU_64BIT)
+               KSTK_STATUS(current) |= ST0_FR;
+       else /* mode == FPU_32BIT */
+               KSTK_STATUS(current) &= ~ST0_FR;
+
        set_thread_flag(TIF_USEDFPU);
+       return 0;
 }
 
-static inline void own_fpu_inatomic(int restore)
+static inline int own_fpu_inatomic(int restore)
 {
+       int ret = 0;
+
        if (cpu_has_fpu && !__is_fpu_owner()) {
-               __own_fpu();
-               if (restore)
+               ret = __own_fpu();
+               if (restore && !ret)
                        _restore_fp(current);
        }
+       return ret;
 }
 
-static inline void own_fpu(int restore)
+static inline int own_fpu(int restore)
 {
+       int ret;
+
        preempt_disable();
-       own_fpu_inatomic(restore);
+       ret = own_fpu_inatomic(restore);
        preempt_enable();
+       return ret;
 }
 
 static inline void lose_fpu(int save)
@@ -106,16 +151,21 @@ static inline void lose_fpu(int save)
        preempt_enable();
 }
 
-static inline void init_fpu(void)
+static inline int init_fpu(void)
 {
+       int ret = 0;
+
        preempt_disable();
        if (cpu_has_fpu) {
-               __own_fpu();
-               _init_fpu();
+               ret = __own_fpu();
+               if (!ret)
+                       _init_fpu();
        } else {
                fpu_emulator_init_fpu();
        }
+
        preempt_enable();
+       return ret;
 }
 
 static inline void save_fp(struct task_struct *tsk)