1 // SPDX-License-Identifier: GPL-2.0 2 /* cpu.c: Dinky routines to look for the kind of Sparc cpu 3 * we are on. 4 * 5 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 6 */ 7 8 #include <linux/seq_file.h> 9 #include <linux/kernel.h> 10 #include <linux/export.h> 11 #include <linux/init.h> 12 #include <linux/smp.h> 13 #include <linux/threads.h> 14 #include <linux/pgtable.h> 15 16 #include <asm/spitfire.h> 17 #include <asm/oplib.h> 18 #include <asm/setup.h> 19 #include <asm/page.h> 20 #include <asm/head.h> 21 #include <asm/psr.h> 22 #include <asm/mbus.h> 23 #include <asm/cpudata.h> 24 25 #include "kernel.h" 26 #include "entry.h" 27 28 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; 29 EXPORT_PER_CPU_SYMBOL(__cpu_data); 30 31 int ncpus_probed; 32 unsigned int fsr_storage; 33 34 struct cpu_info { 35 int psr_vers; 36 const char *name; 37 const char *pmu_name; 38 }; 39 40 struct fpu_info { 41 int fp_vers; 42 const char *name; 43 }; 44 45 #define NOCPU 8 46 #define NOFPU 8 47 48 struct manufacturer_info { 49 int psr_impl; 50 struct cpu_info cpu_info[NOCPU]; 51 struct fpu_info fpu_info[NOFPU]; 52 }; 53 54 #define CPU(ver, _name) \ 55 { .psr_vers = ver, .name = _name } 56 57 #define CPU_PMU(ver, _name, _pmu_name) \ 58 { .psr_vers = ver, .name = _name, .pmu_name = _pmu_name } 59 60 #define FPU(ver, _name) \ 61 { .fp_vers = ver, .name = _name } 62 63 static const struct manufacturer_info __initconst manufacturer_info[] = { 64 { 65 0, 66 /* Sun4/100, 4/200, SLC */ 67 .cpu_info = { 68 CPU(0, "Fujitsu MB86900/1A or LSI L64831 SparcKIT-40"), 69 /* borned STP1012PGA */ 70 CPU(4, "Fujitsu MB86904"), 71 CPU(5, "Fujitsu TurboSparc MB86907"), 72 CPU(-1, NULL) 73 }, 74 .fpu_info = { 75 FPU(0, "Fujitsu MB86910 or Weitek WTL1164/5"), 76 FPU(1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"), 77 FPU(2, "LSI Logic L64802 or Texas Instruments ACT8847"), 78 /* SparcStation SLC, SparcStation1 */ 79 FPU(3, "Weitek WTL3170/2"), 80 /* SPARCstation-5 */ 81 FPU(4, "Lsi Logic/Meiko L64804 or compatible"), 82 FPU(-1, NULL) 83 } 84 },{ 85 1, 86 .cpu_info = { 87 /* SparcStation2, SparcServer 490 & 690 */ 88 CPU(0, "LSI Logic Corporation - L64811"), 89 /* SparcStation2 */ 90 CPU(1, "Cypress/ROSS CY7C601"), 91 /* Embedded controller */ 92 CPU(3, "Cypress/ROSS CY7C611"), 93 /* Ross Technologies HyperSparc */ 94 CPU(0xf, "ROSS HyperSparc RT620"), 95 CPU(0xe, "ROSS HyperSparc RT625 or RT626"), 96 CPU(-1, NULL) 97 }, 98 .fpu_info = { 99 FPU(0, "ROSS HyperSparc combined IU/FPU"), 100 FPU(1, "Lsi Logic L64814"), 101 FPU(2, "Texas Instruments TMS390-C602A"), 102 FPU(3, "Cypress CY7C602 FPU"), 103 FPU(-1, NULL) 104 } 105 },{ 106 2, 107 .cpu_info = { 108 /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */ 109 /* Someone please write the code to support this beast! ;) */ 110 CPU(0, "Bipolar Integrated Technology - B5010"), 111 CPU(-1, NULL) 112 }, 113 .fpu_info = { 114 FPU(-1, NULL) 115 } 116 },{ 117 3, 118 .cpu_info = { 119 CPU(0, "LSI Logic Corporation - unknown-type"), 120 CPU(-1, NULL) 121 }, 122 .fpu_info = { 123 FPU(-1, NULL) 124 } 125 },{ 126 PSR_IMPL_TI, 127 .cpu_info = { 128 CPU(0, "Texas Instruments, Inc. - SuperSparc-(II)"), 129 /* SparcClassic -- borned STP1010TAB-50*/ 130 CPU(1, "Texas Instruments, Inc. - MicroSparc"), 131 CPU(2, "Texas Instruments, Inc. - MicroSparc II"), 132 CPU(3, "Texas Instruments, Inc. - SuperSparc 51"), 133 CPU(4, "Texas Instruments, Inc. - SuperSparc 61"), 134 CPU(5, "Texas Instruments, Inc. - unknown"), 135 CPU(-1, NULL) 136 }, 137 .fpu_info = { 138 /* SuperSparc 50 module */ 139 FPU(0, "SuperSparc on-chip FPU"), 140 /* SparcClassic */ 141 FPU(4, "TI MicroSparc on chip FPU"), 142 FPU(-1, NULL) 143 } 144 },{ 145 5, 146 .cpu_info = { 147 CPU(0, "Matsushita - MN10501"), 148 CPU(-1, NULL) 149 }, 150 .fpu_info = { 151 FPU(0, "Matsushita MN10501"), 152 FPU(-1, NULL) 153 } 154 },{ 155 6, 156 .cpu_info = { 157 CPU(0, "Philips Corporation - unknown"), 158 CPU(-1, NULL) 159 }, 160 .fpu_info = { 161 FPU(-1, NULL) 162 } 163 },{ 164 7, 165 .cpu_info = { 166 CPU(0, "Harvest VLSI Design Center, Inc. - unknown"), 167 CPU(-1, NULL) 168 }, 169 .fpu_info = { 170 FPU(-1, NULL) 171 } 172 },{ 173 8, 174 .cpu_info = { 175 CPU(0, "Systems and Processes Engineering Corporation (SPEC)"), 176 CPU(-1, NULL) 177 }, 178 .fpu_info = { 179 FPU(-1, NULL) 180 } 181 },{ 182 9, 183 .cpu_info = { 184 /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */ 185 CPU(0, "Fujitsu or Weitek Power-UP"), 186 CPU(1, "Fujitsu or Weitek Power-UP"), 187 CPU(2, "Fujitsu or Weitek Power-UP"), 188 CPU(3, "Fujitsu or Weitek Power-UP"), 189 CPU(-1, NULL) 190 }, 191 .fpu_info = { 192 FPU(3, "Fujitsu or Weitek on-chip FPU"), 193 FPU(-1, NULL) 194 } 195 },{ 196 PSR_IMPL_LEON, /* Aeroflex Gaisler */ 197 .cpu_info = { 198 CPU(3, "LEON"), 199 CPU(-1, NULL) 200 }, 201 .fpu_info = { 202 FPU(2, "GRFPU"), 203 FPU(3, "GRFPU-Lite"), 204 FPU(-1, NULL) 205 } 206 },{ 207 0x17, 208 .cpu_info = { 209 CPU_PMU(0x10, "TI UltraSparc I (SpitFire)", "ultra12"), 210 CPU_PMU(0x11, "TI UltraSparc II (BlackBird)", "ultra12"), 211 CPU_PMU(0x12, "TI UltraSparc IIi (Sabre)", "ultra12"), 212 CPU_PMU(0x13, "TI UltraSparc IIe (Hummingbird)", "ultra12"), 213 CPU(-1, NULL) 214 }, 215 .fpu_info = { 216 FPU(0x10, "UltraSparc I integrated FPU"), 217 FPU(0x11, "UltraSparc II integrated FPU"), 218 FPU(0x12, "UltraSparc IIi integrated FPU"), 219 FPU(0x13, "UltraSparc IIe integrated FPU"), 220 FPU(-1, NULL) 221 } 222 },{ 223 0x22, 224 .cpu_info = { 225 CPU_PMU(0x10, "TI UltraSparc I (SpitFire)", "ultra12"), 226 CPU(-1, NULL) 227 }, 228 .fpu_info = { 229 FPU(0x10, "UltraSparc I integrated FPU"), 230 FPU(-1, NULL) 231 } 232 },{ 233 0x3e, 234 .cpu_info = { 235 CPU_PMU(0x14, "TI UltraSparc III (Cheetah)", "ultra3"), 236 CPU_PMU(0x15, "TI UltraSparc III+ (Cheetah+)", "ultra3+"), 237 CPU_PMU(0x16, "TI UltraSparc IIIi (Jalapeno)", "ultra3i"), 238 CPU_PMU(0x18, "TI UltraSparc IV (Jaguar)", "ultra3+"), 239 CPU_PMU(0x19, "TI UltraSparc IV+ (Panther)", "ultra4+"), 240 CPU_PMU(0x22, "TI UltraSparc IIIi+ (Serrano)", "ultra3i"), 241 CPU(-1, NULL) 242 }, 243 .fpu_info = { 244 FPU(0x14, "UltraSparc III integrated FPU"), 245 FPU(0x15, "UltraSparc III+ integrated FPU"), 246 FPU(0x16, "UltraSparc IIIi integrated FPU"), 247 FPU(0x18, "UltraSparc IV integrated FPU"), 248 FPU(0x19, "UltraSparc IV+ integrated FPU"), 249 FPU(0x22, "UltraSparc IIIi+ integrated FPU"), 250 FPU(-1, NULL) 251 } 252 }}; 253 254 /* In order to get the fpu type correct, you need to take the IDPROM's 255 * machine type value into consideration too. I will fix this. 256 */ 257 258 static const char *sparc_cpu_type; 259 static const char *sparc_fpu_type; 260 const char *sparc_pmu_type; 261 262 263 static void __init set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers) 264 { 265 const struct manufacturer_info *manuf; 266 int i; 267 268 sparc_cpu_type = NULL; 269 sparc_fpu_type = NULL; 270 sparc_pmu_type = NULL; 271 manuf = NULL; 272 273 for (i = 0; i < ARRAY_SIZE(manufacturer_info); i++) 274 { 275 if (psr_impl == manufacturer_info[i].psr_impl) { 276 manuf = &manufacturer_info[i]; 277 break; 278 } 279 } 280 if (manuf != NULL) 281 { 282 const struct cpu_info *cpu; 283 const struct fpu_info *fpu; 284 285 cpu = &manuf->cpu_info[0]; 286 while (cpu->psr_vers != -1) 287 { 288 if (cpu->psr_vers == psr_vers) { 289 sparc_cpu_type = cpu->name; 290 sparc_pmu_type = cpu->pmu_name; 291 sparc_fpu_type = "No FPU"; 292 break; 293 } 294 cpu++; 295 } 296 fpu = &manuf->fpu_info[0]; 297 while (fpu->fp_vers != -1) 298 { 299 if (fpu->fp_vers == fpu_vers) { 300 sparc_fpu_type = fpu->name; 301 break; 302 } 303 fpu++; 304 } 305 } 306 if (sparc_cpu_type == NULL) 307 { 308 printk(KERN_ERR "CPU: Unknown chip, impl[0x%x] vers[0x%x]\n", 309 psr_impl, psr_vers); 310 sparc_cpu_type = "Unknown CPU"; 311 } 312 if (sparc_fpu_type == NULL) 313 { 314 printk(KERN_ERR "FPU: Unknown chip, impl[0x%x] vers[0x%x]\n", 315 psr_impl, fpu_vers); 316 sparc_fpu_type = "Unknown FPU"; 317 } 318 if (sparc_pmu_type == NULL) 319 sparc_pmu_type = "Unknown PMU"; 320 } 321 322 #ifdef CONFIG_SPARC32 323 static int show_cpuinfo(struct seq_file *m, void *__unused) 324 { 325 seq_printf(m, 326 "cpu\t\t: %s\n" 327 "fpu\t\t: %s\n" 328 "promlib\t\t: Version %d Revision %d\n" 329 "prom\t\t: %d.%d\n" 330 "type\t\t: %s\n" 331 "ncpus probed\t: %d\n" 332 "ncpus active\t: %d\n" 333 #ifndef CONFIG_SMP 334 "CPU0Bogo\t: %lu.%02lu\n" 335 "CPU0ClkTck\t: %ld\n" 336 #endif 337 , 338 sparc_cpu_type, 339 sparc_fpu_type , 340 romvec->pv_romvers, 341 prom_rev, 342 romvec->pv_printrev >> 16, 343 romvec->pv_printrev & 0xffff, 344 &cputypval[0], 345 ncpus_probed, 346 num_online_cpus() 347 #ifndef CONFIG_SMP 348 , cpu_data(0).udelay_val/(500000/HZ), 349 (cpu_data(0).udelay_val/(5000/HZ)) % 100, 350 cpu_data(0).clock_tick 351 #endif 352 ); 353 354 #ifdef CONFIG_SMP 355 smp_bogo(m); 356 #endif 357 mmu_info(m); 358 #ifdef CONFIG_SMP 359 smp_info(m); 360 #endif 361 return 0; 362 } 363 #endif /* CONFIG_SPARC32 */ 364 365 #ifdef CONFIG_SPARC64 366 unsigned int dcache_parity_tl1_occurred; 367 unsigned int icache_parity_tl1_occurred; 368 369 370 static int show_cpuinfo(struct seq_file *m, void *__unused) 371 { 372 seq_printf(m, 373 "cpu\t\t: %s\n" 374 "fpu\t\t: %s\n" 375 "pmu\t\t: %s\n" 376 "prom\t\t: %s\n" 377 "type\t\t: %s\n" 378 "ncpus probed\t: %d\n" 379 "ncpus active\t: %d\n" 380 "D$ parity tl1\t: %u\n" 381 "I$ parity tl1\t: %u\n" 382 #ifndef CONFIG_SMP 383 "Cpu0ClkTck\t: %016lx\n" 384 #endif 385 , 386 sparc_cpu_type, 387 sparc_fpu_type, 388 sparc_pmu_type, 389 prom_version, 390 ((tlb_type == hypervisor) ? 391 "sun4v" : 392 "sun4u"), 393 ncpus_probed, 394 num_online_cpus(), 395 dcache_parity_tl1_occurred, 396 icache_parity_tl1_occurred 397 #ifndef CONFIG_SMP 398 , cpu_data(0).clock_tick 399 #endif 400 ); 401 cpucap_info(m); 402 #ifdef CONFIG_SMP 403 smp_bogo(m); 404 #endif 405 mmu_info(m); 406 #ifdef CONFIG_SMP 407 smp_info(m); 408 #endif 409 return 0; 410 } 411 #endif /* CONFIG_SPARC64 */ 412 413 static void *c_start(struct seq_file *m, loff_t *pos) 414 { 415 /* The pointer we are returning is arbitrary, 416 * it just has to be non-NULL and not IS_ERR 417 * in the success case. 418 */ 419 return *pos == 0 ? &c_start : NULL; 420 } 421 422 static void *c_next(struct seq_file *m, void *v, loff_t *pos) 423 { 424 ++*pos; 425 return c_start(m, pos); 426 } 427 428 static void c_stop(struct seq_file *m, void *v) 429 { 430 } 431 432 const struct seq_operations cpuinfo_op = { 433 .start =c_start, 434 .next = c_next, 435 .stop = c_stop, 436 .show = show_cpuinfo, 437 }; 438 439 #ifdef CONFIG_SPARC32 440 static int __init cpu_type_probe(void) 441 { 442 int psr_impl, psr_vers, fpu_vers; 443 int psr; 444 445 psr_impl = ((get_psr() >> PSR_IMPL_SHIFT) & PSR_IMPL_SHIFTED_MASK); 446 psr_vers = ((get_psr() >> PSR_VERS_SHIFT) & PSR_VERS_SHIFTED_MASK); 447 448 psr = get_psr(); 449 put_psr(psr | PSR_EF); 450 451 if (psr_impl == PSR_IMPL_LEON) 452 fpu_vers = get_psr() & PSR_EF ? ((get_fsr() >> 17) & 0x7) : 7; 453 else 454 fpu_vers = ((get_fsr() >> 17) & 0x7); 455 456 put_psr(psr); 457 458 set_cpu_and_fpu(psr_impl, psr_vers, fpu_vers); 459 460 return 0; 461 } 462 #endif /* CONFIG_SPARC32 */ 463 464 #ifdef CONFIG_SPARC64 465 static void __init sun4v_cpu_probe(void) 466 { 467 switch (sun4v_chip_type) { 468 case SUN4V_CHIP_NIAGARA1: 469 sparc_cpu_type = "UltraSparc T1 (Niagara)"; 470 sparc_fpu_type = "UltraSparc T1 integrated FPU"; 471 sparc_pmu_type = "niagara"; 472 break; 473 474 case SUN4V_CHIP_NIAGARA2: 475 sparc_cpu_type = "UltraSparc T2 (Niagara2)"; 476 sparc_fpu_type = "UltraSparc T2 integrated FPU"; 477 sparc_pmu_type = "niagara2"; 478 break; 479 480 case SUN4V_CHIP_NIAGARA3: 481 sparc_cpu_type = "UltraSparc T3 (Niagara3)"; 482 sparc_fpu_type = "UltraSparc T3 integrated FPU"; 483 sparc_pmu_type = "niagara3"; 484 break; 485 486 case SUN4V_CHIP_NIAGARA4: 487 sparc_cpu_type = "UltraSparc T4 (Niagara4)"; 488 sparc_fpu_type = "UltraSparc T4 integrated FPU"; 489 sparc_pmu_type = "niagara4"; 490 break; 491 492 case SUN4V_CHIP_NIAGARA5: 493 sparc_cpu_type = "UltraSparc T5 (Niagara5)"; 494 sparc_fpu_type = "UltraSparc T5 integrated FPU"; 495 sparc_pmu_type = "niagara5"; 496 break; 497 498 case SUN4V_CHIP_SPARC_M6: 499 sparc_cpu_type = "SPARC-M6"; 500 sparc_fpu_type = "SPARC-M6 integrated FPU"; 501 sparc_pmu_type = "sparc-m6"; 502 break; 503 504 case SUN4V_CHIP_SPARC_M7: 505 sparc_cpu_type = "SPARC-M7"; 506 sparc_fpu_type = "SPARC-M7 integrated FPU"; 507 sparc_pmu_type = "sparc-m7"; 508 break; 509 510 case SUN4V_CHIP_SPARC_M8: 511 sparc_cpu_type = "SPARC-M8"; 512 sparc_fpu_type = "SPARC-M8 integrated FPU"; 513 sparc_pmu_type = "sparc-m8"; 514 break; 515 516 case SUN4V_CHIP_SPARC_SN: 517 sparc_cpu_type = "SPARC-SN"; 518 sparc_fpu_type = "SPARC-SN integrated FPU"; 519 sparc_pmu_type = "sparc-sn"; 520 break; 521 522 case SUN4V_CHIP_SPARC64X: 523 sparc_cpu_type = "SPARC64-X"; 524 sparc_fpu_type = "SPARC64-X integrated FPU"; 525 sparc_pmu_type = "sparc64-x"; 526 break; 527 528 default: 529 printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n", 530 prom_cpu_compatible); 531 sparc_cpu_type = "Unknown SUN4V CPU"; 532 sparc_fpu_type = "Unknown SUN4V FPU"; 533 sparc_pmu_type = "Unknown SUN4V PMU"; 534 break; 535 } 536 } 537 538 static int __init cpu_type_probe(void) 539 { 540 if (tlb_type == hypervisor) { 541 sun4v_cpu_probe(); 542 } else { 543 unsigned long ver; 544 int manuf, impl; 545 546 __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver)); 547 548 manuf = ((ver >> 48) & 0xffff); 549 impl = ((ver >> 32) & 0xffff); 550 set_cpu_and_fpu(manuf, impl, impl); 551 } 552 return 0; 553 } 554 #endif /* CONFIG_SPARC64 */ 555 556 early_initcall(cpu_type_probe); 557
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.