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