diff options
Diffstat (limited to 'arch/mips/include/asm/fpu.h')
-rw-r--r-- | arch/mips/include/asm/fpu.h | 49 |
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 | */ |
43 | enum fpu_mode { | 42 | enum 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 | ||
49 | static inline int __enable_fpu(enum fpu_mode mode) | 51 | static 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); | ||
79 | fr_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 | ||