cpu.c revision 215101
1/*- 2 * Copyright (c) 2001 Matt Thomas. 3 * Copyright (c) 2001 Tsubai Masanari. 4 * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by 18 * Internet Research Institute, Inc. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33/*- 34 * Copyright (C) 2003 Benno Rice. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 * 57 * from $NetBSD: cpu_subr.c,v 1.1 2003/02/03 17:10:09 matt Exp $ 58 * $FreeBSD: head/sys/powerpc/powerpc/cpu.c 215101 2010-11-10 20:28:10Z nwhitehorn $ 59 */ 60 61#include <sys/param.h> 62#include <sys/systm.h> 63#include <sys/bus.h> 64#include <sys/conf.h> 65#include <sys/cpu.h> 66#include <sys/kernel.h> 67#include <sys/sysctl.h> 68 69#include <machine/bus.h> 70#include <machine/cpu.h> 71#include <machine/hid.h> 72#include <machine/md_var.h> 73#include <machine/smp.h> 74#include <machine/spr.h> 75 76int powerpc_pow_enabled; 77 78static void cpu_6xx_setup(int cpuid, uint16_t vers); 79static void cpu_e500_setup(int cpuid, uint16_t vers); 80static void cpu_970_setup(int cpuid, uint16_t vers); 81 82struct cputab { 83 const char *name; 84 uint16_t version; 85 uint16_t revfmt; 86 int features; /* Do not include PPC_FEATURE_32 or 87 * PPC_FEATURE_HAS_MMU */ 88 void (*cpu_setup)(int cpuid, uint16_t vers); 89}; 90#define REVFMT_MAJMIN 1 /* %u.%u */ 91#define REVFMT_HEX 2 /* 0x%04x */ 92#define REVFMT_DEC 3 /* %u */ 93static const struct cputab models[] = { 94 { "Motorola PowerPC 601", MPC601, REVFMT_DEC, 95 PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, cpu_6xx_setup }, 96 { "Motorola PowerPC 602", MPC602, REVFMT_DEC, 97 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 98 { "Motorola PowerPC 603", MPC603, REVFMT_MAJMIN, 99 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 100 { "Motorola PowerPC 603e", MPC603e, REVFMT_MAJMIN, 101 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 102 { "Motorola PowerPC 603ev", MPC603ev, REVFMT_MAJMIN, 103 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 104 { "Motorola PowerPC 604", MPC604, REVFMT_MAJMIN, 105 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 106 { "Motorola PowerPC 604ev", MPC604ev, REVFMT_MAJMIN, 107 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 108 { "Motorola PowerPC 620", MPC620, REVFMT_HEX, 109 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL }, 110 { "Motorola PowerPC 750", MPC750, REVFMT_MAJMIN, 111 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 112 { "IBM PowerPC 750FX", IBM750FX, REVFMT_MAJMIN, 113 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 114 { "IBM PowerPC 970", IBM970, REVFMT_MAJMIN, 115 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 116 cpu_970_setup }, 117 { "IBM PowerPC 970FX", IBM970FX, REVFMT_MAJMIN, 118 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 119 cpu_970_setup }, 120 { "IBM PowerPC 970GX", IBM970GX, REVFMT_MAJMIN, 121 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 122 cpu_970_setup }, 123 { "IBM PowerPC 970MP", IBM970MP, REVFMT_MAJMIN, 124 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 125 cpu_970_setup }, 126 { "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN, 127 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 128 { "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN, 129 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 130 { "Motorola PowerPC 7450", MPC7450, REVFMT_MAJMIN, 131 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 132 { "Motorola PowerPC 7455", MPC7455, REVFMT_MAJMIN, 133 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 134 { "Motorola PowerPC 7457", MPC7457, REVFMT_MAJMIN, 135 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 136 { "Motorola PowerPC 7447A", MPC7447A, REVFMT_MAJMIN, 137 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 138 { "Motorola PowerPC 7448", MPC7448, REVFMT_MAJMIN, 139 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 140 { "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN, 141 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 142 { "Motorola PowerPC 8245", MPC8245, REVFMT_MAJMIN, 143 PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, 144 { "Freescale e500v1 core", FSL_E500v1, REVFMT_MAJMIN, 145 0, cpu_e500_setup }, 146 { "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN, 147 0, cpu_e500_setup }, 148 { "Unknown PowerPC CPU", 0, REVFMT_HEX, 0, NULL }, 149}; 150 151static void cpu_6xx_print_cacheinfo(u_int, uint16_t); 152static int cpu_feature_bit(SYSCTL_HANDLER_ARGS); 153 154static char model[64]; 155SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, ""); 156 157int cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU; 158SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLTYPE_INT | CTLFLAG_RD, 159 &cpu_features, sizeof(cpu_features), "IX", "PowerPC CPU features"); 160 161/* Provide some user-friendly aliases for bits in cpu_features */ 162SYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD, 163 0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I", 164 "Floating point instructions executed in hardware"); 165SYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD, 166 0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec"); 167 168void 169cpu_setup(u_int cpuid) 170{ 171 u_int pvr, maj, min; 172 uint16_t vers, rev, revfmt; 173 uint64_t cps; 174 const struct cputab *cp; 175 const char *name; 176 177 pvr = mfpvr(); 178 vers = pvr >> 16; 179 rev = pvr; 180 switch (vers) { 181 case MPC7410: 182 min = (pvr >> 0) & 0xff; 183 maj = min <= 4 ? 1 : 2; 184 break; 185 case FSL_E500v1: 186 case FSL_E500v2: 187 maj = (pvr >> 4) & 0xf; 188 min = (pvr >> 0) & 0xf; 189 break; 190 default: 191 maj = (pvr >> 8) & 0xf; 192 min = (pvr >> 0) & 0xf; 193 } 194 195 for (cp = models; cp->version != 0; cp++) { 196 if (cp->version == vers) 197 break; 198 } 199 200 revfmt = cp->revfmt; 201 name = cp->name; 202 if (rev == MPC750 && pvr == 15) { 203 name = "Motorola MPC755"; 204 revfmt = REVFMT_HEX; 205 } 206 strncpy(model, name, sizeof(model) - 1); 207 208 printf("cpu%d: %s revision ", cpuid, name); 209 210 switch (revfmt) { 211 case REVFMT_MAJMIN: 212 printf("%u.%u", maj, min); 213 break; 214 case REVFMT_HEX: 215 printf("0x%04x", rev); 216 break; 217 case REVFMT_DEC: 218 printf("%u", rev); 219 break; 220 } 221 222 if (cpu_est_clockrate(0, &cps) == 0) 223 printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100); 224 printf("\n"); 225 226 cpu_features |= cp->features; 227 printf("cpu%d: Features %b\n", cpuid, cpu_features, 228 PPC_FEATURE_BITMASK); 229 230 /* 231 * Configure CPU 232 */ 233 if (cp->cpu_setup != NULL) 234 cp->cpu_setup(cpuid, vers); 235} 236 237/* Get current clock frequency for the given cpu id. */ 238int 239cpu_est_clockrate(int cpu_id, uint64_t *cps) 240{ 241 uint16_t vers; 242 register_t msr; 243 244 vers = mfpvr() >> 16; 245 msr = mfmsr(); 246 mtmsr(msr & ~PSL_EE); 247 248 switch (vers) { 249 case MPC7450: 250 case MPC7455: 251 case MPC7457: 252 case MPC750: 253 case IBM750FX: 254 case MPC7400: 255 case MPC7410: 256 case MPC7447A: 257 case MPC7448: 258 mtspr(SPR_MMCR0, SPR_MMCR0_FC); 259 mtspr(SPR_PMC1, 0); 260 mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMCN_CYCLES)); 261 DELAY(1000); 262 *cps = (mfspr(SPR_PMC1) * 1000) + 4999; 263 mtspr(SPR_MMCR0, SPR_MMCR0_FC); 264 265 mtmsr(msr); 266 return (0); 267 case IBM970: 268 case IBM970FX: 269 case IBM970MP: 270 isync(); 271 mtspr(SPR_970MMCR0, SPR_MMCR0_FC); 272 isync(); 273 mtspr(SPR_970MMCR1, 0); 274 mtspr(SPR_970MMCRA, 0); 275 mtspr(SPR_970PMC1, 0); 276 mtspr(SPR_970MMCR0, 277 SPR_970MMCR0_PMC1SEL(PMC970N_CYCLES)); 278 isync(); 279 DELAY(1000); 280 powerpc_sync(); 281 mtspr(SPR_970MMCR0, SPR_MMCR0_FC); 282 *cps = (mfspr(SPR_970PMC1) * 1000) + 4999; 283 284 mtmsr(msr); 285 return (0); 286 } 287 288 return (ENXIO); 289} 290 291void 292cpu_6xx_setup(int cpuid, uint16_t vers) 293{ 294 register_t hid0, pvr; 295 const char *bitmask; 296 297 hid0 = mfspr(SPR_HID0); 298 pvr = mfpvr(); 299 300 /* 301 * Configure power-saving mode. 302 */ 303 switch (vers) { 304 case MPC603: 305 case MPC603e: 306 case MPC603ev: 307 case MPC604ev: 308 case MPC750: 309 case IBM750FX: 310 case MPC7400: 311 case MPC7410: 312 case MPC8240: 313 case MPC8245: 314 /* Select DOZE mode. */ 315 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 316 hid0 |= HID0_DOZE | HID0_DPM; 317 powerpc_pow_enabled = 1; 318 break; 319 320 case MPC7448: 321 case MPC7447A: 322 case MPC7457: 323 case MPC7455: 324 case MPC7450: 325 /* Enable the 7450 branch caches */ 326 hid0 |= HID0_SGE | HID0_BTIC; 327 hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT; 328 /* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */ 329 if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200) 330 || (pvr >> 16) == MPC7457) 331 hid0 &= ~HID0_BTIC; 332 /* Select NAP mode. */ 333 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 334 hid0 |= HID0_NAP | HID0_DPM; 335 powerpc_pow_enabled = 1; 336 break; 337 338 default: 339 /* No power-saving mode is available. */ ; 340 } 341 342 switch (vers) { 343 case IBM750FX: 344 case MPC750: 345 hid0 &= ~HID0_DBP; /* XXX correct? */ 346 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 347 break; 348 349 case MPC7400: 350 case MPC7410: 351 hid0 &= ~HID0_SPD; 352 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 353 hid0 |= HID0_EIEC; 354 break; 355 356 } 357 358 mtspr(SPR_HID0, hid0); 359 360 if (bootverbose) 361 cpu_6xx_print_cacheinfo(cpuid, vers); 362 363 switch (vers) { 364 case MPC7447A: 365 case MPC7448: 366 case MPC7450: 367 case MPC7455: 368 case MPC7457: 369 bitmask = HID0_7450_BITMASK; 370 break; 371 default: 372 bitmask = HID0_BITMASK; 373 break; 374 } 375 376 printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask); 377} 378 379 380static void 381cpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers) 382{ 383 register_t hid; 384 385 hid = mfspr(SPR_HID0); 386 printf("cpu%u: ", cpuid); 387 printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis"); 388 printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis"); 389 390 printf("cpu%u: ", cpuid); 391 if (mfspr(SPR_L2CR) & L2CR_L2E) { 392 switch (vers) { 393 case MPC7450: 394 case MPC7455: 395 case MPC7457: 396 printf("256KB L2 cache, "); 397 if (mfspr(SPR_L3CR) & L3CR_L3E) 398 printf("%cMB L3 backside cache", 399 mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1'); 400 else 401 printf("L3 cache disabled"); 402 printf("\n"); 403 break; 404 case IBM750FX: 405 printf("512KB L2 cache\n"); 406 break; 407 default: 408 switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) { 409 case L2SIZ_256K: 410 printf("256KB "); 411 break; 412 case L2SIZ_512K: 413 printf("512KB "); 414 break; 415 case L2SIZ_1M: 416 printf("1MB "); 417 break; 418 } 419 printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT) 420 ? "through" : "back"); 421 if (mfspr(SPR_L2CR) & L2CR_L2PE) 422 printf(", with parity"); 423 printf(" backside cache\n"); 424 break; 425 } 426 } else 427 printf("L2 cache disabled\n"); 428} 429 430static void 431cpu_e500_setup(int cpuid, uint16_t vers) 432{ 433 register_t hid0; 434 435 hid0 = mfspr(SPR_HID0); 436 437 /* Programe power-management mode. */ 438 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 439 hid0 |= HID0_DOZE; 440 441 mtspr(SPR_HID0, hid0); 442 443 printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK); 444} 445 446static void 447cpu_970_setup(int cpuid, uint16_t vers) 448{ 449#ifdef AIM 450 uint32_t hid0_hi, hid0_lo; 451 452 __asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;" 453 : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0)); 454 455 /* Configure power-saving mode */ 456 switch (vers) { 457 case IBM970MP: 458 hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM); 459 hid0_hi &= ~HID0_DOZE; 460 break; 461 default: 462 hid0_hi |= (HID0_NAP | HID0_DPM); 463 hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP); 464 break; 465 } 466 powerpc_pow_enabled = 1; 467 468 __asm __volatile (" \ 469 sync; isync; \ 470 sldi %0,%0,32; or %0,%0,%1; \ 471 mtspr %2, %0; \ 472 mfspr %0, %2; mfspr %0, %2; mfspr %0, %2; \ 473 mfspr %0, %2; mfspr %0, %2; mfspr %0, %2; \ 474 sync; isync" 475 :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0)); 476 477 __asm __volatile ("mfspr %0,%1; srdi %0,%0,32;" 478 : "=r" (hid0_hi) : "K" (SPR_HID0)); 479 printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK); 480#endif 481} 482 483static int 484cpu_feature_bit(SYSCTL_HANDLER_ARGS) 485{ 486 int result; 487 488 result = (cpu_features & arg2) ? 1 : 0; 489 490 return (sysctl_handle_int(oidp, &result, 0, req)); 491} 492 493