1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * Processor capabilities determination functi 3 * Processor capabilities determination functions. 4 * 4 * 5 * Copyright (C) xxxx the Anonymous 5 * Copyright (C) xxxx the Anonymous 6 * Copyright (C) 1994 - 2006 Ralf Baechle 6 * Copyright (C) 1994 - 2006 Ralf Baechle 7 * Copyright (C) 2003, 2004 Maciej W. Rozycki 7 * Copyright (C) 2003, 2004 Maciej W. Rozycki 8 * Copyright (C) 2001, 2004, 2011, 2012 MIPS 8 * Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc. 9 */ 9 */ 10 10 11 #include <linux/init.h> 11 #include <linux/init.h> 12 #include <linux/kernel.h> 12 #include <linux/kernel.h> 13 13 14 #include <asm/bugs.h> 14 #include <asm/bugs.h> 15 #include <asm/cpu.h> 15 #include <asm/cpu.h> 16 #include <asm/cpu-features.h> 16 #include <asm/cpu-features.h> 17 #include <asm/cpu-type.h> 17 #include <asm/cpu-type.h> 18 #include <asm/elf.h> 18 #include <asm/elf.h> 19 #include <asm/fpu.h> 19 #include <asm/fpu.h> 20 #include <asm/mipsregs.h> 20 #include <asm/mipsregs.h> 21 21 22 #include "fpu-probe.h" 22 #include "fpu-probe.h" 23 23 24 /* 24 /* 25 * Get the FPU Implementation/Revision. 25 * Get the FPU Implementation/Revision. 26 */ 26 */ 27 static inline unsigned long cpu_get_fpu_id(voi 27 static inline unsigned long cpu_get_fpu_id(void) 28 { 28 { 29 unsigned long tmp, fpu_id; 29 unsigned long tmp, fpu_id; 30 30 31 tmp = read_c0_status(); 31 tmp = read_c0_status(); 32 __enable_fpu(FPU_AS_IS); 32 __enable_fpu(FPU_AS_IS); 33 fpu_id = read_32bit_cp1_register(CP1_R 33 fpu_id = read_32bit_cp1_register(CP1_REVISION); 34 write_c0_status(tmp); 34 write_c0_status(tmp); 35 return fpu_id; 35 return fpu_id; 36 } 36 } 37 37 38 /* 38 /* 39 * Check if the CPU has an external FPU. 39 * Check if the CPU has an external FPU. 40 */ 40 */ 41 int __cpu_has_fpu(void) 41 int __cpu_has_fpu(void) 42 { 42 { 43 return (cpu_get_fpu_id() & FPIR_IMP_MA 43 return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE; 44 } 44 } 45 45 46 /* 46 /* 47 * Determine the FCSR mask for FPU hardware. 47 * Determine the FCSR mask for FPU hardware. 48 */ 48 */ 49 static inline void cpu_set_fpu_fcsr_mask(struc 49 static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c) 50 { 50 { 51 unsigned long sr, mask, fcsr, fcsr0, f 51 unsigned long sr, mask, fcsr, fcsr0, fcsr1; 52 52 53 fcsr = c->fpu_csr31; 53 fcsr = c->fpu_csr31; 54 mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | 54 mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM; 55 55 56 sr = read_c0_status(); 56 sr = read_c0_status(); 57 __enable_fpu(FPU_AS_IS); 57 __enable_fpu(FPU_AS_IS); 58 58 59 fcsr0 = fcsr & mask; 59 fcsr0 = fcsr & mask; 60 write_32bit_cp1_register(CP1_STATUS, f 60 write_32bit_cp1_register(CP1_STATUS, fcsr0); 61 fcsr0 = read_32bit_cp1_register(CP1_ST 61 fcsr0 = read_32bit_cp1_register(CP1_STATUS); 62 62 63 fcsr1 = fcsr | ~mask; 63 fcsr1 = fcsr | ~mask; 64 write_32bit_cp1_register(CP1_STATUS, f 64 write_32bit_cp1_register(CP1_STATUS, fcsr1); 65 fcsr1 = read_32bit_cp1_register(CP1_ST 65 fcsr1 = read_32bit_cp1_register(CP1_STATUS); 66 66 67 write_32bit_cp1_register(CP1_STATUS, f 67 write_32bit_cp1_register(CP1_STATUS, fcsr); 68 68 69 write_c0_status(sr); 69 write_c0_status(sr); 70 70 71 c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mas 71 c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask; 72 } 72 } 73 73 74 /* 74 /* 75 * Determine the IEEE 754 NaN encodings and AB 75 * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes 76 * supported by FPU hardware. 76 * supported by FPU hardware. 77 */ 77 */ 78 static void cpu_set_fpu_2008(struct cpuinfo_mi 78 static void cpu_set_fpu_2008(struct cpuinfo_mips *c) 79 { 79 { 80 if (c->isa_level & (MIPS_CPU_ISA_M32R1 80 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 81 MIPS_CPU_ISA_M32R2 81 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 82 MIPS_CPU_ISA_M32R5 82 MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | 83 MIPS_CPU_ISA_M32R6 83 MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { 84 unsigned long sr, fir, fcsr, f 84 unsigned long sr, fir, fcsr, fcsr0, fcsr1; 85 85 86 sr = read_c0_status(); 86 sr = read_c0_status(); 87 __enable_fpu(FPU_AS_IS); 87 __enable_fpu(FPU_AS_IS); 88 88 89 fir = read_32bit_cp1_register( 89 fir = read_32bit_cp1_register(CP1_REVISION); 90 if (fir & MIPS_FPIR_HAS2008) { 90 if (fir & MIPS_FPIR_HAS2008) { 91 fcsr = read_32bit_cp1_ 91 fcsr = read_32bit_cp1_register(CP1_STATUS); 92 92 93 /* 93 /* 94 * MAC2008 toolchain n 94 * MAC2008 toolchain never landed in real world, so 95 * we're only testing 95 * we're only testing whether it can be disabled and 96 * don't try to enabl 96 * don't try to enabled it. 97 */ 97 */ 98 fcsr0 = fcsr & ~(FPU_C 98 fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008 | 99 FPU_C 99 FPU_CSR_MAC2008); 100 write_32bit_cp1_regist 100 write_32bit_cp1_register(CP1_STATUS, fcsr0); 101 fcsr0 = read_32bit_cp1 101 fcsr0 = read_32bit_cp1_register(CP1_STATUS); 102 102 103 fcsr1 = fcsr | FPU_CSR 103 fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008; 104 write_32bit_cp1_regist 104 write_32bit_cp1_register(CP1_STATUS, fcsr1); 105 fcsr1 = read_32bit_cp1 105 fcsr1 = read_32bit_cp1_register(CP1_STATUS); 106 106 107 write_32bit_cp1_regist 107 write_32bit_cp1_register(CP1_STATUS, fcsr); 108 108 109 if (c->isa_level & (MI 109 if (c->isa_level & (MIPS_CPU_ISA_M32R2 | 110 MI 110 MIPS_CPU_ISA_M64R2)) { 111 /* 111 /* 112 * The bit for 112 * The bit for MAC2008 might be reused by R6 113 * in future, 113 * in future, so we only test for R2-R5. 114 */ 114 */ 115 if (fcsr0 & FP 115 if (fcsr0 & FPU_CSR_MAC2008) 116 c->opt 116 c->options |= MIPS_CPU_MAC_2008_ONLY; 117 } 117 } 118 118 119 if (!(fcsr0 & FPU_CSR_ 119 if (!(fcsr0 & FPU_CSR_NAN2008)) 120 c->options |= 120 c->options |= MIPS_CPU_NAN_LEGACY; 121 if (fcsr1 & FPU_CSR_NA 121 if (fcsr1 & FPU_CSR_NAN2008) 122 c->options |= 122 c->options |= MIPS_CPU_NAN_2008; 123 123 124 if ((fcsr0 ^ fcsr1) & 124 if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008) 125 c->fpu_msk31 & 125 c->fpu_msk31 &= ~FPU_CSR_ABS2008; 126 else 126 else 127 c->fpu_csr31 | 127 c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008; 128 128 129 if ((fcsr0 ^ fcsr1) & 129 if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008) 130 c->fpu_msk31 & 130 c->fpu_msk31 &= ~FPU_CSR_NAN2008; 131 else 131 else 132 c->fpu_csr31 | 132 c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008; 133 } else { 133 } else { 134 c->options |= MIPS_CPU 134 c->options |= MIPS_CPU_NAN_LEGACY; 135 } 135 } 136 136 137 write_c0_status(sr); 137 write_c0_status(sr); 138 } else { 138 } else { 139 c->options |= MIPS_CPU_NAN_LEG 139 c->options |= MIPS_CPU_NAN_LEGACY; 140 } 140 } 141 } 141 } 142 142 143 /* 143 /* 144 * IEEE 754 conformance mode to use. Affects 144 * IEEE 754 conformance mode to use. Affects the NaN encoding and the 145 * ABS.fmt/NEG.fmt execution mode. 145 * ABS.fmt/NEG.fmt execution mode. 146 */ 146 */ 147 static enum { STRICT, EMULATED, LEGACY, STD200 !! 147 static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT; 148 148 149 /* 149 /* 150 * Set the IEEE 754 NaN encodings and the ABS. 150 * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes 151 * to support by the FPU emulator according to 151 * to support by the FPU emulator according to the IEEE 754 conformance 152 * mode selected. Note that "relaxed" straps 152 * mode selected. Note that "relaxed" straps the emulator so that it 153 * allows 2008-NaN binaries even for legacy pr 153 * allows 2008-NaN binaries even for legacy processors. 154 */ 154 */ 155 static void cpu_set_nofpu_2008(struct cpuinfo_ 155 static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) 156 { 156 { 157 c->options &= ~(MIPS_CPU_NAN_2008 | MI 157 c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY); 158 c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FP 158 c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); 159 c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FP 159 c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); 160 160 161 switch (ieee754) { 161 switch (ieee754) { 162 case STRICT: 162 case STRICT: 163 case EMULATED: << 164 if (c->isa_level & (MIPS_CPU_I 163 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 165 MIPS_CPU_I 164 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 166 MIPS_CPU_I 165 MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | 167 MIPS_CPU_I 166 MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { 168 c->options |= MIPS_CPU 167 c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; 169 } else { 168 } else { 170 c->options |= MIPS_CPU 169 c->options |= MIPS_CPU_NAN_LEGACY; 171 c->fpu_msk31 |= FPU_CS 170 c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; 172 } 171 } 173 break; 172 break; 174 case LEGACY: 173 case LEGACY: 175 c->options |= MIPS_CPU_NAN_LEG 174 c->options |= MIPS_CPU_NAN_LEGACY; 176 c->fpu_msk31 |= FPU_CSR_ABS200 175 c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; 177 break; 176 break; 178 case STD2008: 177 case STD2008: 179 c->options |= MIPS_CPU_NAN_200 178 c->options |= MIPS_CPU_NAN_2008; 180 c->fpu_csr31 |= FPU_CSR_ABS200 179 c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; 181 c->fpu_msk31 |= FPU_CSR_ABS200 180 c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; 182 break; 181 break; 183 case RELAXED: 182 case RELAXED: 184 c->options |= MIPS_CPU_NAN_200 183 c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; 185 break; 184 break; 186 } 185 } 187 } 186 } 188 187 189 /* 188 /* 190 * Override the IEEE 754 NaN encoding and ABS. 189 * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode 191 * according to the "ieee754=" parameter. 190 * according to the "ieee754=" parameter. 192 */ 191 */ 193 static void cpu_set_nan_2008(struct cpuinfo_mi 192 static void cpu_set_nan_2008(struct cpuinfo_mips *c) 194 { 193 { 195 switch (ieee754) { 194 switch (ieee754) { 196 case STRICT: 195 case STRICT: 197 mips_use_nan_legacy = !!cpu_ha 196 mips_use_nan_legacy = !!cpu_has_nan_legacy; 198 mips_use_nan_2008 = !!cpu_has_ 197 mips_use_nan_2008 = !!cpu_has_nan_2008; 199 break; 198 break; 200 case LEGACY: 199 case LEGACY: 201 mips_use_nan_legacy = !!cpu_ha 200 mips_use_nan_legacy = !!cpu_has_nan_legacy; 202 mips_use_nan_2008 = !cpu_has_n 201 mips_use_nan_2008 = !cpu_has_nan_legacy; 203 break; 202 break; 204 case STD2008: 203 case STD2008: 205 mips_use_nan_legacy = !cpu_has 204 mips_use_nan_legacy = !cpu_has_nan_2008; 206 mips_use_nan_2008 = !!cpu_has_ 205 mips_use_nan_2008 = !!cpu_has_nan_2008; 207 break; 206 break; 208 case EMULATED: << 209 /* Pretend ABS2008/NAN2008 opt << 210 c->fpu_msk31 &= ~(FPU_CSR_NAN2 << 211 fallthrough; << 212 case RELAXED: 207 case RELAXED: 213 mips_use_nan_legacy = true; 208 mips_use_nan_legacy = true; 214 mips_use_nan_2008 = true; 209 mips_use_nan_2008 = true; 215 break; 210 break; 216 } 211 } 217 } 212 } 218 213 219 /* 214 /* 220 * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt e 215 * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override 221 * settings: 216 * settings: 222 * 217 * 223 * strict: accept binaries that request a NaN 218 * strict: accept binaries that request a NaN encoding supported by the FPU 224 * legacy: only accept legacy-NaN binaries 219 * legacy: only accept legacy-NaN binaries 225 * 2008: only accept 2008-NaN binaries 220 * 2008: only accept 2008-NaN binaries 226 * relaxed: accept any binaries regardless of 221 * relaxed: accept any binaries regardless of whether supported by the FPU 227 */ 222 */ 228 static int __init ieee754_setup(char *s) 223 static int __init ieee754_setup(char *s) 229 { 224 { 230 if (!s) 225 if (!s) 231 return -1; 226 return -1; 232 else if (!strcmp(s, "strict")) 227 else if (!strcmp(s, "strict")) 233 ieee754 = STRICT; 228 ieee754 = STRICT; 234 else if (!strcmp(s, "emulated")) << 235 ieee754 = EMULATED; << 236 else if (!strcmp(s, "legacy")) 229 else if (!strcmp(s, "legacy")) 237 ieee754 = LEGACY; 230 ieee754 = LEGACY; 238 else if (!strcmp(s, "2008")) 231 else if (!strcmp(s, "2008")) 239 ieee754 = STD2008; 232 ieee754 = STD2008; 240 else if (!strcmp(s, "relaxed")) 233 else if (!strcmp(s, "relaxed")) 241 ieee754 = RELAXED; 234 ieee754 = RELAXED; 242 else 235 else 243 return -1; 236 return -1; 244 237 245 if (!(boot_cpu_data.options & MIPS_CPU 238 if (!(boot_cpu_data.options & MIPS_CPU_FPU)) 246 cpu_set_nofpu_2008(&boot_cpu_d 239 cpu_set_nofpu_2008(&boot_cpu_data); 247 cpu_set_nan_2008(&boot_cpu_data); 240 cpu_set_nan_2008(&boot_cpu_data); 248 241 249 return 0; 242 return 0; 250 } 243 } 251 244 252 early_param("ieee754", ieee754_setup); 245 early_param("ieee754", ieee754_setup); 253 246 254 /* 247 /* 255 * Set the FIR feature flags for the FPU emula 248 * Set the FIR feature flags for the FPU emulator. 256 */ 249 */ 257 static void cpu_set_nofpu_id(struct cpuinfo_mi 250 static void cpu_set_nofpu_id(struct cpuinfo_mips *c) 258 { 251 { 259 u32 value; 252 u32 value; 260 253 261 value = 0; 254 value = 0; 262 if (c->isa_level & (MIPS_CPU_ISA_M32R1 255 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 263 MIPS_CPU_ISA_M32R2 256 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 264 MIPS_CPU_ISA_M32R5 257 MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | 265 MIPS_CPU_ISA_M32R6 258 MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) 266 value |= MIPS_FPIR_D | MIPS_FP 259 value |= MIPS_FPIR_D | MIPS_FPIR_S; 267 if (c->isa_level & (MIPS_CPU_ISA_M32R2 260 if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 268 MIPS_CPU_ISA_M32R5 261 MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | 269 MIPS_CPU_ISA_M32R6 262 MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) 270 value |= MIPS_FPIR_F64 | MIPS_ 263 value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W; 271 if (c->options & MIPS_CPU_NAN_2008) 264 if (c->options & MIPS_CPU_NAN_2008) 272 value |= MIPS_FPIR_HAS2008; 265 value |= MIPS_FPIR_HAS2008; 273 c->fpu_id = value; 266 c->fpu_id = value; 274 } 267 } 275 268 276 /* Determined FPU emulator mask to use for the 269 /* Determined FPU emulator mask to use for the boot CPU with "nofpu". */ 277 static unsigned int mips_nofpu_msk31; 270 static unsigned int mips_nofpu_msk31; 278 271 279 /* 272 /* 280 * Set options for FPU hardware. 273 * Set options for FPU hardware. 281 */ 274 */ 282 void cpu_set_fpu_opts(struct cpuinfo_mips *c) 275 void cpu_set_fpu_opts(struct cpuinfo_mips *c) 283 { 276 { 284 c->fpu_id = cpu_get_fpu_id(); 277 c->fpu_id = cpu_get_fpu_id(); 285 mips_nofpu_msk31 = c->fpu_msk31; 278 mips_nofpu_msk31 = c->fpu_msk31; 286 279 287 if (c->isa_level & (MIPS_CPU_ISA_M32R1 280 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 288 MIPS_CPU_ISA_M32R2 281 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 289 MIPS_CPU_ISA_M32R5 282 MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | 290 MIPS_CPU_ISA_M32R6 283 MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { 291 if (c->fpu_id & MIPS_FPIR_3D) 284 if (c->fpu_id & MIPS_FPIR_3D) 292 c->ases |= MIPS_ASE_MI 285 c->ases |= MIPS_ASE_MIPS3D; 293 if (c->fpu_id & MIPS_FPIR_UFRP 286 if (c->fpu_id & MIPS_FPIR_UFRP) 294 c->options |= MIPS_CPU 287 c->options |= MIPS_CPU_UFR; 295 if (c->fpu_id & MIPS_FPIR_FREP 288 if (c->fpu_id & MIPS_FPIR_FREP) 296 c->options |= MIPS_CPU 289 c->options |= MIPS_CPU_FRE; 297 } 290 } 298 291 299 cpu_set_fpu_fcsr_mask(c); 292 cpu_set_fpu_fcsr_mask(c); 300 cpu_set_fpu_2008(c); 293 cpu_set_fpu_2008(c); 301 cpu_set_nan_2008(c); 294 cpu_set_nan_2008(c); 302 } 295 } 303 296 304 /* 297 /* 305 * Set options for the FPU emulator. 298 * Set options for the FPU emulator. 306 */ 299 */ 307 void cpu_set_nofpu_opts(struct cpuinfo_mips *c 300 void cpu_set_nofpu_opts(struct cpuinfo_mips *c) 308 { 301 { 309 c->options &= ~MIPS_CPU_FPU; 302 c->options &= ~MIPS_CPU_FPU; 310 c->fpu_msk31 = mips_nofpu_msk31; 303 c->fpu_msk31 = mips_nofpu_msk31; 311 304 312 cpu_set_nofpu_2008(c); 305 cpu_set_nofpu_2008(c); 313 cpu_set_nan_2008(c); 306 cpu_set_nan_2008(c); 314 cpu_set_nofpu_id(c); 307 cpu_set_nofpu_id(c); 315 } 308 } 316 309 317 int mips_fpu_disabled; 310 int mips_fpu_disabled; 318 311 319 static int __init fpu_disable(char *s) 312 static int __init fpu_disable(char *s) 320 { 313 { 321 cpu_set_nofpu_opts(&boot_cpu_data); 314 cpu_set_nofpu_opts(&boot_cpu_data); 322 mips_fpu_disabled = 1; 315 mips_fpu_disabled = 1; 323 316 324 return 1; 317 return 1; 325 } 318 } 326 319 327 __setup("nofpu", fpu_disable); 320 __setup("nofpu", fpu_disable); 328 321 329 322
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.