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