aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/include/asm/fpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/include/asm/fpu.h')
-rw-r--r--arch/mips/include/asm/fpu.h104
1 files changed, 76 insertions, 28 deletions
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index d088e5db4903..cfe092fc720d 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -33,11 +33,48 @@ extern void _init_fpu(void);
33extern void _save_fp(struct task_struct *); 33extern void _save_fp(struct task_struct *);
34extern void _restore_fp(struct task_struct *); 34extern void _restore_fp(struct task_struct *);
35 35
36#define __enable_fpu() \ 36/*
37do { \ 37 * This enum specifies a mode in which we want the FPU to operate, for cores
38 set_c0_status(ST0_CU1); \ 38 * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT
39 enable_fpu_hazard(); \ 39 * purposefully have the values 0 & 1 respectively, so that an integer value
40} while (0) 40 * of Status.FR can be trivially casted to the corresponding enum fpu_mode.
41 */
42enum fpu_mode {
43 FPU_32BIT = 0, /* FR = 0 */
44 FPU_64BIT, /* FR = 1 */
45 FPU_AS_IS,
46};
47
48static inline int __enable_fpu(enum fpu_mode mode)
49{
50 int fr;
51
52 switch (mode) {
53 case FPU_AS_IS:
54 /* just enable the FPU in its current mode */
55 set_c0_status(ST0_CU1);
56 enable_fpu_hazard();
57 return 0;
58
59 case FPU_64BIT:
60#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
61 /* we only have a 32-bit FPU */
62 return SIGFPE;
63#endif
64 /* fall through */
65 case FPU_32BIT:
66 /* set CU1 & change FR appropriately */
67 fr = (int)mode;
68 change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
69 enable_fpu_hazard();
70
71 /* check FR has the desired value */
72 return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE;
73
74 default:
75 BUG();
76 }
77}
41 78
42#define __disable_fpu() \ 79#define __disable_fpu() \
43do { \ 80do { \
@@ -45,19 +82,6 @@ do { \
45 disable_fpu_hazard(); \ 82 disable_fpu_hazard(); \
46} while (0) 83} while (0)
47 84
48#define enable_fpu() \
49do { \
50 if (cpu_has_fpu) \
51 __enable_fpu(); \
52} while (0)
53
54#define disable_fpu() \
55do { \
56 if (cpu_has_fpu) \
57 __disable_fpu(); \
58} while (0)
59
60
61#define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) 85#define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU)
62 86
63static inline int __is_fpu_owner(void) 87static inline int __is_fpu_owner(void)
@@ -70,27 +94,46 @@ static inline int is_fpu_owner(void)
70 return cpu_has_fpu && __is_fpu_owner(); 94 return cpu_has_fpu && __is_fpu_owner();
71} 95}
72 96
73static inline void __own_fpu(void) 97static inline int __own_fpu(void)
74{ 98{
75 __enable_fpu(); 99 enum fpu_mode mode;
100 int ret;
101
102 mode = !test_thread_flag(TIF_32BIT_FPREGS);
103 ret = __enable_fpu(mode);
104 if (ret)
105 return ret;
106
76 KSTK_STATUS(current) |= ST0_CU1; 107 KSTK_STATUS(current) |= ST0_CU1;
108 if (mode == FPU_64BIT)
109 KSTK_STATUS(current) |= ST0_FR;
110 else /* mode == FPU_32BIT */
111 KSTK_STATUS(current) &= ~ST0_FR;
112
77 set_thread_flag(TIF_USEDFPU); 113 set_thread_flag(TIF_USEDFPU);
114 return 0;
78} 115}
79 116
80static inline void own_fpu_inatomic(int restore) 117static inline int own_fpu_inatomic(int restore)
81{ 118{
119 int ret = 0;
120
82 if (cpu_has_fpu && !__is_fpu_owner()) { 121 if (cpu_has_fpu && !__is_fpu_owner()) {
83 __own_fpu(); 122 ret = __own_fpu();
84 if (restore) 123 if (restore && !ret)
85 _restore_fp(current); 124 _restore_fp(current);
86 } 125 }
126 return ret;
87} 127}
88 128
89static inline void own_fpu(int restore) 129static inline int own_fpu(int restore)
90{ 130{
131 int ret;
132
91 preempt_disable(); 133 preempt_disable();
92 own_fpu_inatomic(restore); 134 ret = own_fpu_inatomic(restore);
93 preempt_enable(); 135 preempt_enable();
136 return ret;
94} 137}
95 138
96static inline void lose_fpu(int save) 139static inline void lose_fpu(int save)
@@ -106,16 +149,21 @@ static inline void lose_fpu(int save)
106 preempt_enable(); 149 preempt_enable();
107} 150}
108 151
109static inline void init_fpu(void) 152static inline int init_fpu(void)
110{ 153{
154 int ret = 0;
155
111 preempt_disable(); 156 preempt_disable();
112 if (cpu_has_fpu) { 157 if (cpu_has_fpu) {
113 __own_fpu(); 158 ret = __own_fpu();
114 _init_fpu(); 159 if (!ret)
160 _init_fpu();
115 } else { 161 } else {
116 fpu_emulator_init_fpu(); 162 fpu_emulator_init_fpu();
117 } 163 }
164
118 preempt_enable(); 165 preempt_enable();
166 return ret;
119} 167}
120 168
121static inline void save_fp(struct task_struct *tsk) 169static inline void save_fp(struct task_struct *tsk)