1 /* $NetBSD: cpu_subr.c,v 1.8 2003/04/10 16:07:15 scw Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 Matt Thomas. 5 * Copyright (c) 2001 Tsubai Masanari. 6 * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by 20 * Internet Research Institute, Inc. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include "opt_ppcparam.h" 37 #include "opt_multiprocessor.h" 38 #include "opt_altivec.h" 39 #include "sysmon_envsys.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 45 #include <uvm/uvm_extern.h> 46 47 #include <powerpc/oea/hid.h> 48 #include <powerpc/oea/hid_601.h> 49 #include <powerpc/spr.h> 50 51 #include <dev/sysmon/sysmonvar.h> 52 53 static void cpu_enable_l2cr(register_t); 54 static void cpu_enable_l3cr(register_t); 55 static void cpu_config_l2cr(int); 56 static void cpu_config_l3cr(int); 57 static void cpu_print_speed(void); 58 #if NSYSMON_ENVSYS > 0 59 static void cpu_tau_setup(struct cpu_info *); 60 static int cpu_tau_gtredata __P((struct sysmon_envsys *, 61 struct envsys_tre_data *)); 62 static int cpu_tau_streinfo __P((struct sysmon_envsys *, 63 struct envsys_basic_info *)); 64 #endif 65 66 int cpu; 67 int ncpus; 68 69 struct fmttab { 70 register_t fmt_mask; 71 register_t fmt_value; 72 const char *fmt_string; 73 }; 74 75 static const struct fmttab cpu_7450_l2cr_formats[] = { 76 { L2CR_L2E, 0, " disabled" }, 77 { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, 78 { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, 79 { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, 80 { L2CR_L2E, ~0, " 256KB L2 cache" }, 81 { 0 } 82 }; 83 84 static const struct fmttab cpu_7450_l3cr_formats[] = { 85 { L3CR_L3DO|L3CR_L3IO, L3CR_L3DO, " data-only" }, 86 { L3CR_L3DO|L3CR_L3IO, L3CR_L3IO, " instruction-only" }, 87 { L3CR_L3DO|L3CR_L3IO, L3CR_L3DO|L3CR_L3IO, " locked" }, 88 { L3CR_L3SIZ, L3SIZ_2M, " 2MB" }, 89 { L3CR_L3SIZ, L3SIZ_1M, " 1MB" }, 90 { L3CR_L3PE|L3CR_L3APE, L3CR_L3PE|L3CR_L3APE, " parity" }, 91 { L3CR_L3PE|L3CR_L3APE, L3CR_L3PE, " data-parity" }, 92 { L3CR_L3PE|L3CR_L3APE, L3CR_L3APE, " address-parity" }, 93 { L3CR_L3PE|L3CR_L3APE, 0, " no-parity" }, 94 { L3CR_L3SIZ, ~0, " L3 cache" }, 95 { L3CR_L3RT, L3RT_MSUG2_DDR, " (DDR SRAM)" }, 96 { L3CR_L3RT, L3RT_PIPELINE_LATE, " (LW SRAM)" }, 97 { L3CR_L3RT, L3RT_PB2_SRAM, " (PB2 SRAM)" }, 98 { L3CR_L3CLK, ~0, " at" }, 99 { L3CR_L3CLK, L3CLK_20, " 2:1" }, 100 { L3CR_L3CLK, L3CLK_25, " 2.5:1" }, 101 { L3CR_L3CLK, L3CLK_30, " 3:1" }, 102 { L3CR_L3CLK, L3CLK_35, " 3.5:1" }, 103 { L3CR_L3CLK, L3CLK_40, " 4:1" }, 104 { L3CR_L3CLK, L3CLK_50, " 5:1" }, 105 { L3CR_L3CLK, L3CLK_60, " 6:1" }, 106 { L3CR_L3CLK, ~0, " ratio" }, 107 { 0, 0 }, 108 }; 109 110 static const struct fmttab cpu_ibm750_l2cr_formats[] = { 111 { L2CR_L2E, 0, " disabled" }, 112 { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, 113 { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, 114 { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, 115 { 0, ~0, " 512KB" }, 116 { L2CR_L2WT, L2CR_L2WT, " WT" }, 117 { L2CR_L2WT, 0, " WB" }, 118 { L2CR_L2PE, L2CR_L2PE, " with ECC" }, 119 { 0, ~0, " L2 cache" }, 120 { 0 } 121 }; 122 123 static const struct fmttab cpu_l2cr_formats[] = { 124 { L2CR_L2E, 0, " disabled" }, 125 { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, 126 { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, 127 { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, 128 { L2CR_L2PE, L2CR_L2PE, " parity" }, 129 { L2CR_L2PE, 0, " no-parity" }, 130 { L2CR_L2SIZ, L2SIZ_2M, " 2MB" }, 131 { L2CR_L2SIZ, L2SIZ_1M, " 1MB" }, 132 { L2CR_L2SIZ, L2SIZ_512K, " 512KB" }, 133 { L2CR_L2SIZ, L2SIZ_256K, " 256KB" }, 134 { L2CR_L2WT, L2CR_L2WT, " WT" }, 135 { L2CR_L2WT, 0, " WB" }, 136 { L2CR_L2E, ~0, " L2 cache" }, 137 { L2CR_L2RAM, L2RAM_FLOWTHRU_BURST, " (FB SRAM)" }, 138 { L2CR_L2RAM, L2RAM_PIPELINE_LATE, " (LW SRAM)" }, 139 { L2CR_L2RAM, L2RAM_PIPELINE_BURST, " (PB SRAM)" }, 140 { L2CR_L2CLK, ~0, " at" }, 141 { L2CR_L2CLK, L2CLK_10, " 1:1" }, 142 { L2CR_L2CLK, L2CLK_15, " 1.5:1" }, 143 { L2CR_L2CLK, L2CLK_20, " 2:1" }, 144 { L2CR_L2CLK, L2CLK_25, " 2.5:1" }, 145 { L2CR_L2CLK, L2CLK_30, " 3:1" }, 146 { L2CR_L2CLK, L2CLK_35, " 3.5:1" }, 147 { L2CR_L2CLK, L2CLK_40, " 4:1" }, 148 { L2CR_L2CLK, ~0, " ratio" }, 149 { 0 } 150 }; 151 152 static void cpu_fmttab_print(const struct fmttab *, register_t); 153 154 struct cputab { 155 const char name[8]; 156 uint16_t version; 157 uint16_t revfmt; 158 }; 159 #define REVFMT_MAJMIN 1 /* %u.%u */ 160 #define REVFMT_HEX 2 /* 0x%04x */ 161 #define REVFMT_DEC 3 /* %u */ 162 static const struct cputab models[] = { 163 { "601", MPC601, REVFMT_DEC }, 164 { "602", MPC602, REVFMT_DEC }, 165 { "603", MPC603, REVFMT_MAJMIN }, 166 { "603e", MPC603e, REVFMT_MAJMIN }, 167 { "603ev", MPC603ev, REVFMT_MAJMIN }, 168 { "604", MPC604, REVFMT_MAJMIN }, 169 { "604ev", MPC604ev, REVFMT_MAJMIN }, 170 { "620", MPC620, REVFMT_HEX }, 171 { "750", MPC750, REVFMT_MAJMIN }, 172 { "750FX", IBM750FX, REVFMT_MAJMIN }, 173 { "7400", MPC7400, REVFMT_MAJMIN }, 174 { "7410", MPC7410, REVFMT_MAJMIN }, 175 { "7450", MPC7450, REVFMT_MAJMIN }, 176 { "7455", MPC7455, REVFMT_MAJMIN }, 177 { "8240", MPC8240, REVFMT_MAJMIN }, 178 { "", 0, REVFMT_HEX } 179 }; 180 181 182 #ifdef MULTIPROCESSOR 183 struct cpu_info cpu_info[CPU_MAXNUM]; 184 #else 185 struct cpu_info cpu_info[1]; 186 #endif 187 188 int cpu_altivec; 189 char cpu_model[80]; 190 191 void 192 cpu_fmttab_print(const struct fmttab *fmt, register_t data) 193 { 194 for (; fmt->fmt_mask != 0 || fmt->fmt_value != 0; fmt++) { 195 if ((~fmt->fmt_mask & fmt->fmt_value) != 0 || 196 (data & fmt->fmt_mask) == fmt->fmt_value) 197 aprint_normal("%s", fmt->fmt_string); 198 } 199 } 200 201 void 202 cpu_probe_cache(void) 203 { 204 u_int assoc, pvr, vers; 205 206 pvr = mfpvr(); 207 vers = pvr >> 16; 208 209 switch (vers) { 210 #define K *1024 211 case IBM750FX: 212 case MPC601: 213 case MPC750: 214 case MPC7450: 215 case MPC7455: 216 curcpu()->ci_ci.dcache_size = 32 K; 217 curcpu()->ci_ci.icache_size = 32 K; 218 assoc = 8; 219 break; 220 case MPC603: 221 curcpu()->ci_ci.dcache_size = 8 K; 222 curcpu()->ci_ci.icache_size = 8 K; 223 assoc = 2; 224 break; 225 case MPC603e: 226 case MPC603ev: 227 case MPC604: 228 case MPC8240: 229 case MPC8245: 230 curcpu()->ci_ci.dcache_size = 16 K; 231 curcpu()->ci_ci.icache_size = 16 K; 232 assoc = 4; 233 break; 234 case MPC604ev: 235 curcpu()->ci_ci.dcache_size = 32 K; 236 curcpu()->ci_ci.icache_size = 32 K; 237 assoc = 4; 238 break; 239 default: 240 curcpu()->ci_ci.dcache_size = PAGE_SIZE; 241 curcpu()->ci_ci.icache_size = PAGE_SIZE; 242 assoc = 1; 243 #undef K 244 } 245 246 /* Presently common across all implementations. */ 247 curcpu()->ci_ci.dcache_line_size = CACHELINESIZE; 248 curcpu()->ci_ci.icache_line_size = CACHELINESIZE; 249 250 /* 251 * Possibly recolor. 252 */ 253 uvm_page_recolor(atop(curcpu()->ci_ci.dcache_size / assoc)); 254 } 255 256 struct cpu_info * 257 cpu_attach_common(struct device *self, int id) 258 { 259 struct cpu_info *ci; 260 u_int pvr, vers; 261 262 ncpus++; 263 ci = &cpu_info[id]; 264 #ifndef MULTIPROCESSOR 265 /* 266 * If this isn't the primary CPU, print an error message 267 * and just bail out. 268 */ 269 if (id != 0) { 270 aprint_normal(": ID %d\n", id); 271 aprint_normal("%s: processor off-line; multiprocessor support " 272 "not present in kernel\n", self->dv_xname); 273 return (NULL); 274 } 275 #endif 276 277 ci->ci_cpuid = id; 278 ci->ci_intrdepth = -1; 279 ci->ci_dev = self; 280 281 pvr = mfpvr(); 282 vers = (pvr >> 16) & 0xffff; 283 284 switch (id) { 285 case 0: 286 /* load my cpu_number to PIR */ 287 switch (vers) { 288 case MPC601: 289 case MPC604: 290 case MPC604ev: 291 case MPC7400: 292 case MPC7410: 293 case MPC7450: 294 case MPC7455: 295 mtspr(SPR_PIR, id); 296 } 297 cpu_setup(self, ci); 298 break; 299 default: 300 if (id >= CPU_MAXNUM) { 301 aprint_normal(": more than %d cpus?\n", CPU_MAXNUM); 302 panic("cpuattach"); 303 } 304 #ifndef MULTIPROCESSOR 305 aprint_normal(" not configured\n"); 306 return NULL; 307 #endif 308 } 309 return (ci); 310 } 311 312 void 313 cpu_setup(self, ci) 314 struct device *self; 315 struct cpu_info *ci; 316 { 317 u_int hid0, pvr, vers; 318 char *bitmask, hidbuf[128]; 319 char model[80]; 320 321 pvr = mfpvr(); 322 vers = (pvr >> 16) & 0xffff; 323 324 cpu_identify(model, sizeof(model)); 325 aprint_normal(": %s, ID %d%s\n", model, cpu_number(), 326 cpu_number() == 0 ? " (primary)" : ""); 327 328 hid0 = mfspr(SPR_HID0); 329 cpu_probe_cache(); 330 331 /* 332 * Configure power-saving mode. 333 */ 334 switch (vers) { 335 case MPC603: 336 case MPC603e: 337 case MPC603ev: 338 case MPC604ev: 339 case MPC750: 340 case IBM750FX: 341 case MPC7400: 342 case MPC7410: 343 case MPC8240: 344 case MPC8245: 345 /* Select DOZE mode. */ 346 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 347 hid0 |= HID0_DOZE | HID0_DPM; 348 powersave = 1; 349 break; 350 351 case MPC7455: 352 case MPC7450: 353 /* Enable the 7450 branch caches */ 354 hid0 |= HID0_SGE | HID0_BTIC; 355 hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT; 356 /* Disable BTIC on 7450 Rev 2.0 or earlier */ 357 if (vers == MPC7450 && (pvr & 0xFFFF) <= 0x0200) 358 hid0 &= ~HID0_BTIC; 359 /* Select NAP mode. */ 360 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 361 hid0 |= HID0_NAP | HID0_DPM; 362 powersave = 0; /* but don't use it */ 363 break; 364 365 default: 366 /* No power-saving mode is available. */ ; 367 } 368 369 #ifdef NAPMODE 370 switch (vers) { 371 case IBM750FX: 372 case MPC750: 373 case MPC7400: 374 /* Select NAP mode. */ 375 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 376 hid0 |= HID0_NAP; 377 break; 378 } 379 #endif 380 381 switch (vers) { 382 case IBM750FX: 383 case MPC750: 384 hid0 &= ~HID0_DBP; /* XXX correct? */ 385 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 386 break; 387 388 case MPC7400: 389 case MPC7410: 390 hid0 &= ~HID0_SPD; 391 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 392 hid0 |= HID0_EIEC; 393 break; 394 } 395 396 mtspr(SPR_HID0, hid0); 397 398 switch (vers) { 399 case MPC601: 400 bitmask = HID0_601_BITMASK; 401 break; 402 case MPC7450: 403 case MPC7455: 404 bitmask = HID0_7450_BITMASK; 405 break; 406 default: 407 bitmask = HID0_BITMASK; 408 break; 409 } 410 bitmask_snprintf(hid0, bitmask, hidbuf, sizeof hidbuf); 411 aprint_normal("%s: HID0 %s\n", self->dv_xname, hidbuf); 412 413 /* 414 * Display speed and cache configuration. 415 */ 416 if (vers == MPC750 || vers == MPC7400 || vers == IBM750FX || 417 vers == MPC7410 || vers == MPC7450 || vers == MPC7455) { 418 aprint_normal("%s: ", self->dv_xname); 419 cpu_print_speed(); 420 if (vers == MPC7450 || vers == MPC7455) { 421 cpu_config_l3cr(vers); 422 } else { 423 cpu_config_l2cr(pvr); 424 } 425 aprint_normal("\n"); 426 } 427 428 #if NSYSMON_ENVSYS > 0 429 /* 430 * Attach MPC750 temperature sensor to the envsys subsystem. 431 * XXX the 74xx series also has this sensor, but it is not 432 * XXX supported by Motorola and may return values that are off by 433 * XXX 35-55 degrees C. 434 */ 435 if (vers == MPC750 || vers == IBM750FX) 436 cpu_tau_setup(ci); 437 #endif 438 439 evcnt_attach_dynamic(&ci->ci_ev_clock, EVCNT_TYPE_INTR, 440 NULL, self->dv_xname, "clock"); 441 evcnt_attach_dynamic(&ci->ci_ev_softclock, EVCNT_TYPE_INTR, 442 NULL, self->dv_xname, "soft clock"); 443 evcnt_attach_dynamic(&ci->ci_ev_softnet, EVCNT_TYPE_INTR, 444 NULL, self->dv_xname, "soft net"); 445 evcnt_attach_dynamic(&ci->ci_ev_softserial, EVCNT_TYPE_INTR, 446 NULL, self->dv_xname, "soft serial"); 447 evcnt_attach_dynamic(&ci->ci_ev_traps, EVCNT_TYPE_TRAP, 448 NULL, self->dv_xname, "traps"); 449 evcnt_attach_dynamic(&ci->ci_ev_kdsi, EVCNT_TYPE_TRAP, 450 &ci->ci_ev_traps, self->dv_xname, "kernel DSI traps"); 451 evcnt_attach_dynamic(&ci->ci_ev_udsi, EVCNT_TYPE_TRAP, 452 &ci->ci_ev_traps, self->dv_xname, "user DSI traps"); 453 evcnt_attach_dynamic(&ci->ci_ev_udsi_fatal, EVCNT_TYPE_TRAP, 454 &ci->ci_ev_udsi, self->dv_xname, "user DSI failures"); 455 evcnt_attach_dynamic(&ci->ci_ev_isi, EVCNT_TYPE_TRAP, 456 &ci->ci_ev_traps, self->dv_xname, "user ISI traps"); 457 evcnt_attach_dynamic(&ci->ci_ev_isi_fatal, EVCNT_TYPE_TRAP, 458 &ci->ci_ev_isi, self->dv_xname, "user ISI failures"); 459 evcnt_attach_dynamic(&ci->ci_ev_scalls, EVCNT_TYPE_TRAP, 460 &ci->ci_ev_traps, self->dv_xname, "system call traps"); 461 evcnt_attach_dynamic(&ci->ci_ev_pgm, EVCNT_TYPE_TRAP, 462 &ci->ci_ev_traps, self->dv_xname, "PGM traps"); 463 evcnt_attach_dynamic(&ci->ci_ev_fpu, EVCNT_TYPE_TRAP, 464 &ci->ci_ev_traps, self->dv_xname, "FPU unavailable traps"); 465 evcnt_attach_dynamic(&ci->ci_ev_fpusw, EVCNT_TYPE_TRAP, 466 &ci->ci_ev_fpu, self->dv_xname, "FPU context switches"); 467 evcnt_attach_dynamic(&ci->ci_ev_ali, EVCNT_TYPE_TRAP, 468 &ci->ci_ev_traps, self->dv_xname, "user alignment traps"); 469 evcnt_attach_dynamic(&ci->ci_ev_ali_fatal, EVCNT_TYPE_TRAP, 470 &ci->ci_ev_ali, self->dv_xname, "user alignment traps"); 471 evcnt_attach_dynamic(&ci->ci_ev_umchk, EVCNT_TYPE_TRAP, 472 &ci->ci_ev_umchk, self->dv_xname, "user MCHK failures"); 473 evcnt_attach_dynamic(&ci->ci_ev_vec, EVCNT_TYPE_TRAP, 474 &ci->ci_ev_traps, self->dv_xname, "AltiVec unavailable"); 475 #ifdef ALTIVEC 476 if (cpu_altivec) { 477 evcnt_attach_dynamic(&ci->ci_ev_vecsw, EVCNT_TYPE_TRAP, 478 &ci->ci_ev_vec, self->dv_xname, "AltiVec context switches"); 479 } 480 #endif 481 } 482 483 void 484 cpu_identify(char *str, size_t len) 485 { 486 u_int pvr, maj, min; 487 uint16_t vers, rev, revfmt; 488 const struct cputab *cp; 489 const char *name; 490 size_t n; 491 492 pvr = mfpvr(); 493 vers = pvr >> 16; 494 rev = pvr; 495 switch (vers) { 496 case MPC7410: 497 min = (pvr >> 0) & 0xff; 498 maj = min <= 4 ? 1 : 2; 499 break; 500 default: 501 maj = (pvr >> 8) & 0xf; 502 min = (pvr >> 0) & 0xf; 503 } 504 505 for (cp = models; cp->name[0] != '\0'; cp++) { 506 if (cp->version == vers) 507 break; 508 } 509 510 if (str == NULL) { 511 str = cpu_model; 512 len = sizeof(cpu_model); 513 cpu = vers; 514 } 515 516 revfmt = cp->revfmt; 517 name = cp->name; 518 if (rev == MPC750 && pvr == 15) { 519 name = "755"; 520 revfmt = REVFMT_HEX; 521 } 522 523 if (cp->name[0] != '\0') { 524 n = snprintf(str, len, "%s (Revision ", cp->name); 525 } else { 526 n = snprintf(str, len, "Version %#x (Revision ", vers); 527 } 528 if (len > n) { 529 switch (revfmt) { 530 case REVFMT_MAJMIN: 531 snprintf(str + n, len - n, "%u.%u)", maj, min); 532 break; 533 case REVFMT_HEX: 534 snprintf(str + n, len - n, "0x%04x)", rev); 535 break; 536 case REVFMT_DEC: 537 snprintf(str + n, len - n, "%u)", rev); 538 break; 539 } 540 } 541 } 542 543 #ifdef L2CR_CONFIG 544 u_int l2cr_config = L2CR_CONFIG; 545 #else 546 u_int l2cr_config = 0; 547 #endif 548 549 #ifdef L3CR_CONFIG 550 u_int l3cr_config = L3CR_CONFIG; 551 #else 552 u_int l3cr_config = 0; 553 #endif 554 555 void 556 cpu_enable_l2cr(register_t l2cr) 557 { 558 register_t msr, x; 559 560 /* Disable interrupts and set the cache config bits. */ 561 msr = mfmsr(); 562 mtmsr(msr & ~PSL_EE); 563 #ifdef ALTIVEC 564 if (cpu_altivec) 565 __asm __volatile("dssall"); 566 #endif 567 __asm __volatile("sync"); 568 mtspr(SPR_L2CR, l2cr & ~L2CR_L2E); 569 __asm __volatile("sync"); 570 571 /* Wait for L2 clock to be stable (640 L2 clocks). */ 572 delay(100); 573 574 /* Invalidate all L2 contents. */ 575 mtspr(SPR_L2CR, l2cr | L2CR_L2I); 576 do { 577 x = mfspr(SPR_L2CR); 578 } while (x & L2CR_L2IP); 579 580 /* Enable L2 cache. */ 581 l2cr |= L2CR_L2E; 582 mtspr(SPR_L2CR, l2cr); 583 mtmsr(msr); 584 } 585 586 void 587 cpu_enable_l3cr(register_t l3cr) 588 { 589 register_t x; 590 591 /* By The Book (numbered steps from section 3.7.1.3 of MPC7450UM) */ 592 593 /* 594 * 1: Set all L3CR bits for final config except L3E, L3I, L3PE, and 595 * L3CLKEN. (also mask off reserved bits in case they were included 596 * in L3CR_CONFIG) 597 */ 598 l3cr &= ~(L3CR_L3E|L3CR_L3I|L3CR_L3PE|L3CR_L3CLKEN|L3CR_RESERVED); 599 mtspr(SPR_L3CR, l3cr); 600 601 /* 2: Set L3CR[5] (otherwise reserved bit) to 1 */ 602 l3cr |= 0x04000000; 603 mtspr(SPR_L3CR, l3cr); 604 605 /* 3: Set L3CLKEN to 1*/ 606 l3cr |= L3CR_L3CLKEN; 607 mtspr(SPR_L3CR, l3cr); 608 609 /* 4/5: Perform a global cache invalidate (ref section 3.7.3.6) */ 610 __asm __volatile("dssall;sync"); 611 /* L3 cache is already disabled, no need to clear L3E */ 612 mtspr(SPR_L3CR, l3cr|L3CR_L3I); 613 do { 614 x = mfspr(SPR_L3CR); 615 } while (x & L3CR_L3I); 616 617 /* 6: Clear L3CLKEN to 0 */ 618 l3cr &= ~L3CR_L3CLKEN; 619 mtspr(SPR_L3CR, l3cr); 620 621 /* 7: Perform a 'sync' and wait at least 100 CPU cycles */ 622 __asm __volatile("sync"); 623 delay(100); 624 625 /* 8: Set L3E and L3CLKEN */ 626 l3cr |= (L3CR_L3E|L3CR_L3CLKEN); 627 mtspr(SPR_L3CR, l3cr); 628 629 /* 9: Perform a 'sync' and wait at least 100 CPU cycles */ 630 __asm __volatile("sync"); 631 delay(100); 632 } 633 634 void 635 cpu_config_l2cr(int pvr) 636 { 637 register_t l2cr; 638 639 l2cr = mfspr(SPR_L2CR); 640 641 /* 642 * For MP systems, the firmware may only configure the L2 cache 643 * on the first CPU. In this case, assume that the other CPUs 644 * should use the same value for L2CR. 645 */ 646 if ((l2cr & L2CR_L2E) != 0 && l2cr_config == 0) { 647 l2cr_config = l2cr; 648 } 649 650 /* 651 * Configure L2 cache if not enabled. 652 */ 653 if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { 654 cpu_enable_l2cr(l2cr_config); 655 l2cr = mfspr(SPR_L2CR); 656 } 657 658 if ((l2cr & L2CR_L2E) == 0) 659 return; 660 661 aprint_normal(","); 662 if ((pvr >> 16) == IBM750FX || 663 (pvr & 0xffffff00) == 0x00082200 /* IBM750CX */ || 664 (pvr & 0xffffef00) == 0x00082300 /* IBM750CXe */) { 665 cpu_fmttab_print(cpu_ibm750_l2cr_formats, l2cr); 666 } else { 667 cpu_fmttab_print(cpu_l2cr_formats, l2cr); 668 } 669 } 670 671 void 672 cpu_config_l3cr(int vers) 673 { 674 register_t l2cr; 675 register_t l3cr; 676 677 l2cr = mfspr(SPR_L2CR); 678 679 /* 680 * For MP systems, the firmware may only configure the L2 cache 681 * on the first CPU. In this case, assume that the other CPUs 682 * should use the same value for L2CR. 683 */ 684 if ((l2cr & L2CR_L2E) != 0 && l2cr_config == 0) { 685 l2cr_config = l2cr; 686 } 687 688 /* 689 * Configure L2 cache if not enabled. 690 */ 691 if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { 692 cpu_enable_l2cr(l2cr_config); 693 l2cr = mfspr(SPR_L2CR); 694 } 695 696 aprint_normal(","); 697 cpu_fmttab_print(cpu_7450_l2cr_formats, l2cr); 698 699 l3cr = mfspr(SPR_L3CR); 700 701 /* 702 * For MP systems, the firmware may only configure the L3 cache 703 * on the first CPU. In this case, assume that the other CPUs 704 * should use the same value for L3CR. 705 */ 706 if ((l3cr & L3CR_L3E) != 0 && l3cr_config == 0) { 707 l3cr_config = l3cr; 708 } 709 710 /* 711 * Configure L3 cache if not enabled. 712 */ 713 if ((l3cr & L3CR_L3E) == 0 && l3cr_config != 0) { 714 cpu_enable_l3cr(l3cr_config); 715 l3cr = mfspr(SPR_L3CR); 716 } 717 718 if (l3cr & L3CR_L3E) { 719 aprint_normal(","); 720 cpu_fmttab_print(cpu_7450_l3cr_formats, l3cr); 721 } 722 } 723 724 void 725 cpu_print_speed(void) 726 { 727 uint64_t cps; 728 729 mtspr(SPR_MMCR0, MMCR0_FC); 730 mtspr(SPR_PMC1, 0); 731 mtspr(SPR_MMCR0, MMCR0_PMC1SEL(PMCN_CYCLES)); 732 delay(100000); 733 cps = (mfspr(SPR_PMC1) * 10) + 4999; 734 735 aprint_normal("%lld.%02lld MHz", cps / 1000000, (cps / 10000) % 100); 736 } 737 738 #if NSYSMON_ENVSYS > 0 739 const struct envsys_range cpu_tau_ranges[] = { 740 { 0, 0, ENVSYS_STEMP} 741 }; 742 743 struct envsys_basic_info cpu_tau_info[] = { 744 { 0, ENVSYS_STEMP, "CPU temp", 0, 0, ENVSYS_FVALID} 745 }; 746 747 void 748 cpu_tau_setup(struct cpu_info *ci) 749 { 750 struct sysmon_envsys *sme; 751 int error; 752 753 sme = &ci->ci_sysmon; 754 sme->sme_nsensors = 1; 755 sme->sme_envsys_version = 1000; 756 sme->sme_ranges = cpu_tau_ranges; 757 sme->sme_sensor_info = cpu_tau_info; 758 sme->sme_sensor_data = &ci->ci_tau_info; 759 760 sme->sme_sensor_data->sensor = 0; 761 sme->sme_sensor_data->warnflags = ENVSYS_WARN_OK; 762 sme->sme_sensor_data->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 763 sme->sme_cookie = ci; 764 sme->sme_gtredata = cpu_tau_gtredata; 765 sme->sme_streinfo = cpu_tau_streinfo; 766 767 if ((error = sysmon_envsys_register(sme)) != 0) 768 aprint_error("%s: unable to register with sysmon (%d)\n", 769 ci->ci_dev->dv_xname, error); 770 } 771 772 773 /* Find the temperature of the CPU. */ 774 int 775 cpu_tau_gtredata(sme, tred) 776 struct sysmon_envsys *sme; 777 struct envsys_tre_data *tred; 778 { 779 struct cpu_info *ci; 780 int i, threshold, count; 781 782 if (tred->sensor != 0) { 783 tred->validflags = 0; 784 return 0; 785 } 786 787 threshold = 64; /* Half of the 7-bit sensor range */ 788 mtspr(SPR_THRM1, 0); 789 mtspr(SPR_THRM2, 0); 790 /* XXX This counter is supposed to be "at least 20 microseonds, in 791 * XXX units of clock cycles". Since we don't have convenient 792 * XXX access to the CPU speed, set it to a conservative value, 793 * XXX that is, assuming a fast (1GHz) G3 CPU (As of February 2002, 794 * XXX the fastest G3 processor is 700MHz) . The cost is that 795 * XXX measuring the temperature takes a bit longer. 796 */ 797 mtspr(SPR_THRM3, SPR_THRM_TIMER(20000) | SPR_THRM_ENABLE); 798 799 /* Successive-approximation code adapted from Motorola 800 * application note AN1800/D, "Programming the Thermal Assist 801 * Unit in the MPC750 Microprocessor". 802 */ 803 for (i = 4; i >= 0 ; i--) { 804 mtspr(SPR_THRM1, 805 SPR_THRM_THRESHOLD(threshold) | SPR_THRM_VALID); 806 count = 0; 807 while ((count < 100) && 808 ((mfspr(SPR_THRM1) & SPR_THRM_TIV) == 0)) { 809 count++; 810 delay(1); 811 } 812 if (mfspr(SPR_THRM1) & SPR_THRM_TIN) { 813 /* The interrupt bit was set, meaning the 814 * temperature was above the threshold 815 */ 816 threshold += 2 << i; 817 } else { 818 /* Temperature was below the threshold */ 819 threshold -= 2 << i; 820 } 821 } 822 threshold += 2; 823 824 ci = (struct cpu_info *)sme->sme_cookie; 825 /* Convert the temperature in degrees C to microkelvin */ 826 ci->ci_tau_info.cur.data_us = (threshold * 1000000) + 273150000; 827 828 *tred = ci->ci_tau_info; 829 830 return 0; 831 } 832 833 int 834 cpu_tau_streinfo(sme, binfo) 835 struct sysmon_envsys *sme; 836 struct envsys_basic_info *binfo; 837 { 838 839 /* There is nothing to set here. */ 840 return (EINVAL); 841 } 842 #endif /* NSYSMON_ENVSYS > 0 */ 843