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.h49
1 files changed, 41 insertions, 8 deletions
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index dd562414cd5e..994d21939676 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -36,14 +36,16 @@ extern void _restore_fp(struct task_struct *);
36 36
37/* 37/*
38 * This enum specifies a mode in which we want the FPU to operate, for cores 38 * This enum specifies a mode in which we want the FPU to operate, for cores
39 * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT 39 * which implement the Status.FR bit. Note that the bottom bit of the value
40 * purposefully have the values 0 & 1 respectively, so that an integer value 40 * purposefully matches the desired value of the Status.FR bit.
41 * of Status.FR can be trivially casted to the corresponding enum fpu_mode.
42 */ 41 */
43enum fpu_mode { 42enum fpu_mode {
44 FPU_32BIT = 0, /* FR = 0 */ 43 FPU_32BIT = 0, /* FR = 0 */
45 FPU_64BIT, /* FR = 1 */ 44 FPU_64BIT, /* FR = 1, FRE = 0 */
46 FPU_AS_IS, 45 FPU_AS_IS,
46 FPU_HYBRID, /* FR = 1, FRE = 1 */
47
48#define FPU_FR_MASK 0x1
47}; 49};
48 50
49static inline int __enable_fpu(enum fpu_mode mode) 51static inline int __enable_fpu(enum fpu_mode mode)
@@ -57,6 +59,14 @@ static inline int __enable_fpu(enum fpu_mode mode)
57 enable_fpu_hazard(); 59 enable_fpu_hazard();
58 return 0; 60 return 0;
59 61
62 case FPU_HYBRID:
63 if (!cpu_has_fre)
64 return SIGFPE;
65
66 /* set FRE */
67 write_c0_config5(read_c0_config5() | MIPS_CONF5_FRE);
68 goto fr_common;
69
60 case FPU_64BIT: 70 case FPU_64BIT:
61#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT)) 71#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT))
62 /* we only have a 32-bit FPU */ 72 /* we only have a 32-bit FPU */
@@ -64,8 +74,11 @@ static inline int __enable_fpu(enum fpu_mode mode)
64#endif 74#endif
65 /* fall through */ 75 /* fall through */
66 case FPU_32BIT: 76 case FPU_32BIT:
77 /* clear FRE */
78 write_c0_config5(read_c0_config5() & ~MIPS_CONF5_FRE);
79fr_common:
67 /* set CU1 & change FR appropriately */ 80 /* set CU1 & change FR appropriately */
68 fr = (int)mode; 81 fr = (int)mode & FPU_FR_MASK;
69 change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0)); 82 change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
70 enable_fpu_hazard(); 83 enable_fpu_hazard();
71 84
@@ -102,13 +115,17 @@ static inline int __own_fpu(void)
102 enum fpu_mode mode; 115 enum fpu_mode mode;
103 int ret; 116 int ret;
104 117
105 mode = !test_thread_flag(TIF_32BIT_FPREGS); 118 if (test_thread_flag(TIF_HYBRID_FPREGS))
119 mode = FPU_HYBRID;
120 else
121 mode = !test_thread_flag(TIF_32BIT_FPREGS);
122
106 ret = __enable_fpu(mode); 123 ret = __enable_fpu(mode);
107 if (ret) 124 if (ret)
108 return ret; 125 return ret;
109 126
110 KSTK_STATUS(current) |= ST0_CU1; 127 KSTK_STATUS(current) |= ST0_CU1;
111 if (mode == FPU_64BIT) 128 if (mode == FPU_64BIT || mode == FPU_HYBRID)
112 KSTK_STATUS(current) |= ST0_FR; 129 KSTK_STATUS(current) |= ST0_FR;
113 else /* mode == FPU_32BIT */ 130 else /* mode == FPU_32BIT */
114 KSTK_STATUS(current) &= ~ST0_FR; 131 KSTK_STATUS(current) &= ~ST0_FR;
@@ -166,8 +183,24 @@ static inline int init_fpu(void)
166 183
167 if (cpu_has_fpu) { 184 if (cpu_has_fpu) {
168 ret = __own_fpu(); 185 ret = __own_fpu();
169 if (!ret) 186 if (!ret) {
187 unsigned int config5 = read_c0_config5();
188
189 /*
190 * Ensure FRE is clear whilst running _init_fpu, since
191 * single precision FP instructions are used. If FRE
192 * was set then we'll just end up initialising all 32
193 * 64b registers.
194 */
195 write_c0_config5(config5 & ~MIPS_CONF5_FRE);
196 enable_fpu_hazard();
197
170 _init_fpu(); 198 _init_fpu();
199
200 /* Restore FRE */
201 write_c0_config5(config5);
202 enable_fpu_hazard();
203 }
171 } else 204 } else
172 fpu_emulator_init_fpu(); 205 fpu_emulator_init_fpu();
173 206