1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD 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 * Copyright (C) 2003 Benno Rice. 37 * All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 * 59 * from $NetBSD: cpu_subr.c,v 1.1 2003/02/03 17:10:09 matt Exp $ 60 * $FreeBSD$ 61 */ 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/bus.h> 66 #include <sys/conf.h> 67 #include <sys/cpu.h> 68 #include <sys/kernel.h> 69 #include <sys/proc.h> 70 #include <sys/sysctl.h> 71 #include <sys/sched.h> 72 #include <sys/smp.h> 73 74 #include <machine/bus.h> 75 #include <machine/cpu.h> 76 #include <machine/hid.h> 77 #include <machine/md_var.h> 78 #include <machine/smp.h> 79 #include <machine/spr.h> 80 81 #include <dev/ofw/openfirm.h> 82 83 static void cpu_6xx_setup(int cpuid, uint16_t vers); 84 static void cpu_970_setup(int cpuid, uint16_t vers); 85 static void cpu_booke_setup(int cpuid, uint16_t vers); 86 static void cpu_powerx_setup(int cpuid, uint16_t vers); 87 88 int powerpc_pow_enabled; 89 void (*cpu_idle_hook)(sbintime_t) = NULL; 90 static void cpu_idle_60x(sbintime_t); 91 static void cpu_idle_booke(sbintime_t); 92 #ifdef BOOKE_E500 93 static void cpu_idle_e500mc(sbintime_t sbt); 94 #endif 95 #if defined(__powerpc64__) && defined(AIM) 96 static void cpu_idle_powerx(sbintime_t); 97 static void cpu_idle_power9(sbintime_t); 98 #endif 99 100 struct cputab { 101 const char *name; 102 uint16_t version; 103 uint16_t revfmt; 104 int features; /* Do not include PPC_FEATURE_32 or 105 * PPC_FEATURE_HAS_MMU */ 106 int features2; 107 void (*cpu_setup)(int cpuid, uint16_t vers); 108 }; 109 #define REVFMT_MAJMIN 1 /* %u.%u */ 110 #define REVFMT_HEX 2 /* 0x%04x */ 111 #define REVFMT_DEC 3 /* %u */ 112 static const struct cputab models[] = { 113 { "Motorola PowerPC 601", MPC601, REVFMT_DEC, 114 PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, 0, cpu_6xx_setup }, 115 { "Motorola PowerPC 602", MPC602, REVFMT_DEC, 116 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 117 { "Motorola PowerPC 603", MPC603, REVFMT_MAJMIN, 118 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 119 { "Motorola PowerPC 603e", MPC603e, REVFMT_MAJMIN, 120 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 121 { "Motorola PowerPC 603ev", MPC603ev, REVFMT_MAJMIN, 122 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 123 { "Motorola PowerPC 604", MPC604, REVFMT_MAJMIN, 124 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 125 { "Motorola PowerPC 604ev", MPC604ev, REVFMT_MAJMIN, 126 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 127 { "Motorola PowerPC 620", MPC620, REVFMT_HEX, 128 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0, NULL }, 129 { "Motorola PowerPC 750", MPC750, REVFMT_MAJMIN, 130 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 131 { "IBM PowerPC 750FX", IBM750FX, REVFMT_MAJMIN, 132 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 133 { "IBM PowerPC 970", IBM970, REVFMT_MAJMIN, 134 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 135 0, cpu_970_setup }, 136 { "IBM PowerPC 970FX", IBM970FX, REVFMT_MAJMIN, 137 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 138 0, cpu_970_setup }, 139 { "IBM PowerPC 970GX", IBM970GX, REVFMT_MAJMIN, 140 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 141 0, cpu_970_setup }, 142 { "IBM PowerPC 970MP", IBM970MP, REVFMT_MAJMIN, 143 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 144 0, cpu_970_setup }, 145 { "IBM POWER4", IBMPOWER4, REVFMT_MAJMIN, 146 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4, 0, NULL }, 147 { "IBM POWER4+", IBMPOWER4PLUS, REVFMT_MAJMIN, 148 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4, 0, NULL }, 149 { "IBM POWER5", IBMPOWER5, REVFMT_MAJMIN, 150 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4 | 151 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP, 0, NULL }, 152 { "IBM POWER5+", IBMPOWER5PLUS, REVFMT_MAJMIN, 153 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER5_PLUS | 154 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP, 0, NULL }, 155 { "IBM POWER6", IBMPOWER6, REVFMT_MAJMIN, 156 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 157 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 158 PPC_FEATURE_TRUE_LE, 0, NULL }, 159 { "IBM POWER7", IBMPOWER7, REVFMT_MAJMIN, 160 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 161 PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 | 162 PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, PPC_FEATURE2_DSCR, NULL }, 163 { "IBM POWER7+", IBMPOWER7PLUS, REVFMT_MAJMIN, 164 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 165 PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 | 166 PPC_FEATURE_HAS_VSX, PPC_FEATURE2_DSCR, NULL }, 167 { "IBM POWER8E", IBMPOWER8E, REVFMT_MAJMIN, 168 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 169 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 170 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 171 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HTM | PPC_FEATURE2_DSCR | 172 PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO | 173 PPC_FEATURE2_HTM_NOSC, cpu_powerx_setup }, 174 { "IBM POWER8", IBMPOWER8, REVFMT_MAJMIN, 175 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 176 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 177 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 178 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HTM | PPC_FEATURE2_DSCR | 179 PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO | 180 PPC_FEATURE2_HTM_NOSC, cpu_powerx_setup }, 181 { "IBM POWER9", IBMPOWER9, REVFMT_MAJMIN, 182 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 183 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 | 184 PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, 185 PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HTM | PPC_FEATURE2_DSCR | 186 PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO | 187 PPC_FEATURE2_ARCH_3_00 | PPC_FEATURE2_HAS_IEEE128 | 188 PPC_FEATURE2_DARN, cpu_powerx_setup }, 189 { "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN, 190 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 191 { "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN, 192 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 193 { "Motorola PowerPC 7450", MPC7450, REVFMT_MAJMIN, 194 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 195 { "Motorola PowerPC 7455", MPC7455, REVFMT_MAJMIN, 196 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 197 { "Motorola PowerPC 7457", MPC7457, REVFMT_MAJMIN, 198 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 199 { "Motorola PowerPC 7447A", MPC7447A, REVFMT_MAJMIN, 200 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 201 { "Motorola PowerPC 7448", MPC7448, REVFMT_MAJMIN, 202 PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 203 { "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN, 204 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 205 { "Motorola PowerPC 8245", MPC8245, REVFMT_MAJMIN, 206 PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup }, 207 { "Freescale e500v1 core", FSL_E500v1, REVFMT_MAJMIN, 208 PPC_FEATURE_HAS_SPE | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_BOOKE, 209 PPC_FEATURE2_ISEL, cpu_booke_setup }, 210 { "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN, 211 PPC_FEATURE_HAS_SPE | PPC_FEATURE_BOOKE | 212 PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE, 213 PPC_FEATURE2_ISEL, cpu_booke_setup }, 214 { "Freescale e500mc core", FSL_E500mc, REVFMT_MAJMIN, 215 PPC_FEATURE_HAS_FPU | PPC_FEATURE_BOOKE | PPC_FEATURE_ARCH_2_05 | 216 PPC_FEATURE_ARCH_2_06, PPC_FEATURE2_ISEL, 217 cpu_booke_setup }, 218 { "Freescale e5500 core", FSL_E5500, REVFMT_MAJMIN, 219 PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_BOOKE | 220 PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06, 221 PPC_FEATURE2_ISEL, cpu_booke_setup }, 222 { "Freescale e6500 core", FSL_E6500, REVFMT_MAJMIN, 223 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 224 PPC_FEATURE_BOOKE | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06, 225 PPC_FEATURE2_ISEL, cpu_booke_setup }, 226 { "IBM Cell Broadband Engine", IBMCELLBE, REVFMT_MAJMIN, 227 PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU | 228 PPC_FEATURE_CELL | PPC_FEATURE_SMT, 0, NULL}, 229 { "Unknown PowerPC CPU", 0, REVFMT_HEX, 0, 0, NULL }, 230 }; 231 232 static void cpu_6xx_print_cacheinfo(u_int, uint16_t); 233 static int cpu_feature_bit(SYSCTL_HANDLER_ARGS); 234 235 static char model[64]; 236 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, ""); 237 238 static const struct cputab *cput; 239 240 u_long cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU; 241 u_long cpu_features2 = 0; 242 SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLFLAG_RD, 243 &cpu_features, sizeof(cpu_features), "LX", "PowerPC CPU features"); 244 SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features2, CTLFLAG_RD, 245 &cpu_features2, sizeof(cpu_features2), "LX", "PowerPC CPU features 2"); 246 247 #ifdef __powerpc64__ 248 register_t lpcr = LPCR_LPES; 249 #endif 250 251 /* Provide some user-friendly aliases for bits in cpu_features */ 252 SYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD, 253 0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I", 254 "Floating point instructions executed in hardware"); 255 SYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD, 256 0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec"); 257 258 /* 259 * Phase 1 (early) CPU setup. Setup the cpu_features/cpu_features2 variables, 260 * so they can be used during platform and MMU bringup. 261 */ 262 void 263 cpu_feature_setup() 264 { 265 u_int pvr; 266 uint16_t vers; 267 const struct cputab *cp; 268 269 pvr = mfpvr(); 270 vers = pvr >> 16; 271 for (cp = models; cp->version != 0; cp++) { 272 if (cp->version == vers) 273 break; 274 } 275 276 cput = cp; 277 cpu_features |= cp->features; 278 cpu_features2 |= cp->features2; 279 } 280 281 282 void 283 cpu_setup(u_int cpuid) 284 { 285 uint64_t cps; 286 const char *name; 287 u_int maj, min, pvr; 288 uint16_t rev, revfmt, vers; 289 290 pvr = mfpvr(); 291 vers = pvr >> 16; 292 rev = pvr; 293 switch (vers) { 294 case MPC7410: 295 min = (pvr >> 0) & 0xff; 296 maj = min <= 4 ? 1 : 2; 297 break; 298 case FSL_E500v1: 299 case FSL_E500v2: 300 case FSL_E500mc: 301 case FSL_E5500: 302 maj = (pvr >> 4) & 0xf; 303 min = (pvr >> 0) & 0xf; 304 break; 305 default: 306 maj = (pvr >> 8) & 0xf; 307 min = (pvr >> 0) & 0xf; 308 } 309 310 revfmt = cput->revfmt; 311 name = cput->name; 312 if (rev == MPC750 && pvr == 15) { 313 name = "Motorola MPC755"; 314 revfmt = REVFMT_HEX; 315 } 316 strncpy(model, name, sizeof(model) - 1); 317 318 printf("cpu%d: %s revision ", cpuid, name); 319 320 switch (revfmt) { 321 case REVFMT_MAJMIN: 322 printf("%u.%u", maj, min); 323 break; 324 case REVFMT_HEX: 325 printf("0x%04x", rev); 326 break; 327 case REVFMT_DEC: 328 printf("%u", rev); 329 break; 330 } 331 332 if (cpu_est_clockrate(0, &cps) == 0) 333 printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100); 334 printf("\n"); 335 336 printf("cpu%d: Features %b\n", cpuid, (int)cpu_features, 337 PPC_FEATURE_BITMASK); 338 if (cpu_features2 != 0) 339 printf("cpu%d: Features2 %b\n", cpuid, (int)cpu_features2, 340 PPC_FEATURE2_BITMASK); 341 342 /* 343 * Configure CPU 344 */ 345 if (cput->cpu_setup != NULL) 346 cput->cpu_setup(cpuid, vers); 347 } 348 349 /* Get current clock frequency for the given cpu id. */ 350 int 351 cpu_est_clockrate(int cpu_id, uint64_t *cps) 352 { 353 uint16_t vers; 354 register_t msr; 355 phandle_t cpu, dev, root; 356 int res = 0; 357 char buf[8]; 358 359 vers = mfpvr() >> 16; 360 msr = mfmsr(); 361 mtmsr(msr & ~PSL_EE); 362 363 switch (vers) { 364 case MPC7450: 365 case MPC7455: 366 case MPC7457: 367 case MPC750: 368 case IBM750FX: 369 case MPC7400: 370 case MPC7410: 371 case MPC7447A: 372 case MPC7448: 373 mtspr(SPR_MMCR0, SPR_MMCR0_FC); 374 mtspr(SPR_PMC1, 0); 375 mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMCN_CYCLES)); 376 DELAY(1000); 377 *cps = (mfspr(SPR_PMC1) * 1000) + 4999; 378 mtspr(SPR_MMCR0, SPR_MMCR0_FC); 379 380 mtmsr(msr); 381 return (0); 382 case IBM970: 383 case IBM970FX: 384 case IBM970MP: 385 isync(); 386 mtspr(SPR_970MMCR0, SPR_MMCR0_FC); 387 isync(); 388 mtspr(SPR_970MMCR1, 0); 389 mtspr(SPR_970MMCRA, 0); 390 mtspr(SPR_970PMC1, 0); 391 mtspr(SPR_970MMCR0, 392 SPR_970MMCR0_PMC1SEL(PMC970N_CYCLES)); 393 isync(); 394 DELAY(1000); 395 powerpc_sync(); 396 mtspr(SPR_970MMCR0, SPR_MMCR0_FC); 397 *cps = (mfspr(SPR_970PMC1) * 1000) + 4999; 398 399 mtmsr(msr); 400 return (0); 401 402 default: 403 root = OF_peer(0); 404 if (root == 0) 405 return (ENXIO); 406 407 dev = OF_child(root); 408 while (dev != 0) { 409 res = OF_getprop(dev, "name", buf, sizeof(buf)); 410 if (res > 0 && strcmp(buf, "cpus") == 0) 411 break; 412 dev = OF_peer(dev); 413 } 414 cpu = OF_child(dev); 415 while (cpu != 0) { 416 res = OF_getprop(cpu, "device_type", buf, 417 sizeof(buf)); 418 if (res > 0 && strcmp(buf, "cpu") == 0) 419 break; 420 cpu = OF_peer(cpu); 421 } 422 if (cpu == 0) 423 return (ENOENT); 424 if (OF_getprop(cpu, "ibm,extended-clock-frequency", 425 cps, sizeof(*cps)) >= 0) { 426 return (0); 427 } else if (OF_getprop(cpu, "clock-frequency", cps, 428 sizeof(cell_t)) >= 0) { 429 *cps >>= 32; 430 return (0); 431 } else { 432 return (ENOENT); 433 } 434 } 435 } 436 437 void 438 cpu_6xx_setup(int cpuid, uint16_t vers) 439 { 440 register_t hid0, pvr; 441 const char *bitmask; 442 443 hid0 = mfspr(SPR_HID0); 444 pvr = mfpvr(); 445 446 /* 447 * Configure power-saving mode. 448 */ 449 switch (vers) { 450 case MPC603: 451 case MPC603e: 452 case MPC603ev: 453 case MPC604ev: 454 case MPC750: 455 case IBM750FX: 456 case MPC7400: 457 case MPC7410: 458 case MPC8240: 459 case MPC8245: 460 /* Select DOZE mode. */ 461 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 462 hid0 |= HID0_DOZE | HID0_DPM; 463 powerpc_pow_enabled = 1; 464 break; 465 466 case MPC7448: 467 case MPC7447A: 468 case MPC7457: 469 case MPC7455: 470 case MPC7450: 471 /* Enable the 7450 branch caches */ 472 hid0 |= HID0_SGE | HID0_BTIC; 473 hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT; 474 /* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */ 475 if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200) 476 || (pvr >> 16) == MPC7457) 477 hid0 &= ~HID0_BTIC; 478 /* Select NAP mode. */ 479 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 480 hid0 |= HID0_NAP | HID0_DPM; 481 powerpc_pow_enabled = 1; 482 break; 483 484 default: 485 /* No power-saving mode is available. */ ; 486 } 487 488 switch (vers) { 489 case IBM750FX: 490 case MPC750: 491 hid0 &= ~HID0_DBP; /* XXX correct? */ 492 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 493 break; 494 495 case MPC7400: 496 case MPC7410: 497 hid0 &= ~HID0_SPD; 498 hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; 499 hid0 |= HID0_EIEC; 500 break; 501 502 } 503 504 mtspr(SPR_HID0, hid0); 505 506 if (bootverbose) 507 cpu_6xx_print_cacheinfo(cpuid, vers); 508 509 switch (vers) { 510 case MPC7447A: 511 case MPC7448: 512 case MPC7450: 513 case MPC7455: 514 case MPC7457: 515 bitmask = HID0_7450_BITMASK; 516 break; 517 default: 518 bitmask = HID0_BITMASK; 519 break; 520 } 521 522 printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask); 523 524 if (cpu_idle_hook == NULL) 525 cpu_idle_hook = cpu_idle_60x; 526 } 527 528 529 static void 530 cpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers) 531 { 532 register_t hid; 533 534 hid = mfspr(SPR_HID0); 535 printf("cpu%u: ", cpuid); 536 printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis"); 537 printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis"); 538 539 printf("cpu%u: ", cpuid); 540 if (mfspr(SPR_L2CR) & L2CR_L2E) { 541 switch (vers) { 542 case MPC7450: 543 case MPC7455: 544 case MPC7457: 545 printf("256KB L2 cache, "); 546 if (mfspr(SPR_L3CR) & L3CR_L3E) 547 printf("%cMB L3 backside cache", 548 mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1'); 549 else 550 printf("L3 cache disabled"); 551 printf("\n"); 552 break; 553 case IBM750FX: 554 printf("512KB L2 cache\n"); 555 break; 556 default: 557 switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) { 558 case L2SIZ_256K: 559 printf("256KB "); 560 break; 561 case L2SIZ_512K: 562 printf("512KB "); 563 break; 564 case L2SIZ_1M: 565 printf("1MB "); 566 break; 567 } 568 printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT) 569 ? "through" : "back"); 570 if (mfspr(SPR_L2CR) & L2CR_L2PE) 571 printf(", with parity"); 572 printf(" backside cache\n"); 573 break; 574 } 575 } else 576 printf("L2 cache disabled\n"); 577 } 578 579 static void 580 cpu_booke_setup(int cpuid, uint16_t vers) 581 { 582 #ifdef BOOKE_E500 583 register_t hid0; 584 const char *bitmask; 585 586 hid0 = mfspr(SPR_HID0); 587 588 switch (vers) { 589 case FSL_E500mc: 590 bitmask = HID0_E500MC_BITMASK; 591 cpu_idle_hook = cpu_idle_e500mc; 592 break; 593 case FSL_E5500: 594 case FSL_E6500: 595 bitmask = HID0_E5500_BITMASK; 596 cpu_idle_hook = cpu_idle_e500mc; 597 break; 598 case FSL_E500v1: 599 case FSL_E500v2: 600 /* Only e500v1/v2 support HID0 power management setup. */ 601 602 /* Program power-management mode. */ 603 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 604 hid0 |= HID0_DOZE; 605 606 mtspr(SPR_HID0, hid0); 607 default: 608 bitmask = HID0_E500_BITMASK; 609 break; 610 } 611 printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask); 612 #endif 613 614 if (cpu_idle_hook == NULL) 615 cpu_idle_hook = cpu_idle_booke; 616 } 617 618 static void 619 cpu_970_setup(int cpuid, uint16_t vers) 620 { 621 #ifdef AIM 622 uint32_t hid0_hi, hid0_lo; 623 624 __asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;" 625 : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0)); 626 627 /* Configure power-saving mode */ 628 switch (vers) { 629 case IBM970MP: 630 hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM); 631 hid0_hi &= ~HID0_DOZE; 632 break; 633 default: 634 hid0_hi |= (HID0_NAP | HID0_DPM); 635 hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP); 636 break; 637 } 638 powerpc_pow_enabled = 1; 639 640 __asm __volatile (" \ 641 sync; isync; \ 642 sldi %0,%0,32; or %0,%0,%1; \ 643 mtspr %2, %0; \ 644 mfspr %0, %2; mfspr %0, %2; mfspr %0, %2; \ 645 mfspr %0, %2; mfspr %0, %2; mfspr %0, %2; \ 646 sync; isync" 647 :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0)); 648 649 __asm __volatile ("mfspr %0,%1; srdi %0,%0,32;" 650 : "=r" (hid0_hi) : "K" (SPR_HID0)); 651 printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK); 652 #endif 653 654 cpu_idle_hook = cpu_idle_60x; 655 } 656 657 static void 658 cpu_powerx_setup(int cpuid, uint16_t vers) 659 { 660 661 #if defined(__powerpc64__) && defined(AIM) 662 if ((mfmsr() & PSL_HV) == 0) 663 return; 664 665 /* Configure power-saving */ 666 switch (vers) { 667 case IBMPOWER8: 668 case IBMPOWER8E: 669 cpu_idle_hook = cpu_idle_powerx; 670 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_PECE_WAKESET); 671 isync(); 672 break; 673 case IBMPOWER9: 674 cpu_idle_hook = cpu_idle_power9; 675 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_PECE_WAKESET); 676 isync(); 677 break; 678 default: 679 return; 680 } 681 682 #endif 683 } 684 685 static int 686 cpu_feature_bit(SYSCTL_HANDLER_ARGS) 687 { 688 int result; 689 690 result = (cpu_features & arg2) ? 1 : 0; 691 692 return (sysctl_handle_int(oidp, &result, 0, req)); 693 } 694 695 void 696 cpu_idle(int busy) 697 { 698 sbintime_t sbt = -1; 699 700 #ifdef INVARIANTS 701 if ((mfmsr() & PSL_EE) != PSL_EE) { 702 struct thread *td = curthread; 703 printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr); 704 panic("ints disabled in idleproc!"); 705 } 706 #endif 707 708 CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", 709 busy, curcpu); 710 711 if (cpu_idle_hook != NULL) { 712 if (!busy) { 713 critical_enter(); 714 sbt = cpu_idleclock(); 715 } 716 cpu_idle_hook(sbt); 717 if (!busy) { 718 cpu_activeclock(); 719 critical_exit(); 720 } 721 } 722 723 CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", 724 busy, curcpu); 725 } 726 727 static void 728 cpu_idle_60x(sbintime_t sbt) 729 { 730 register_t msr; 731 uint16_t vers; 732 733 if (!powerpc_pow_enabled) 734 return; 735 736 msr = mfmsr(); 737 vers = mfpvr() >> 16; 738 739 #ifdef AIM 740 switch (vers) { 741 case IBM970: 742 case IBM970FX: 743 case IBM970MP: 744 case MPC7447A: 745 case MPC7448: 746 case MPC7450: 747 case MPC7455: 748 case MPC7457: 749 __asm __volatile("\ 750 dssall; sync; mtmsr %0; isync" 751 :: "r"(msr | PSL_POW)); 752 break; 753 default: 754 powerpc_sync(); 755 mtmsr(msr | PSL_POW); 756 break; 757 } 758 #endif 759 } 760 761 #ifdef BOOKE_E500 762 static void 763 cpu_idle_e500mc(sbintime_t sbt) 764 { 765 /* 766 * Base binutils doesn't know what the 'wait' instruction is, so 767 * use the opcode encoding here. 768 */ 769 __asm __volatile(".long 0x7c00007c"); 770 } 771 #endif 772 773 static void 774 cpu_idle_booke(sbintime_t sbt) 775 { 776 register_t msr; 777 778 msr = mfmsr(); 779 780 #ifdef BOOKE_E500 781 powerpc_sync(); 782 mtmsr(msr | PSL_WE); 783 #endif 784 } 785 786 #if defined(__powerpc64__) && defined(AIM) 787 static void 788 cpu_idle_powerx(sbintime_t sbt) 789 { 790 791 /* Sleeping when running on one cpu gives no advantages - avoid it */ 792 if (smp_started == 0) 793 return; 794 795 spinlock_enter(); 796 if (sched_runnable()) { 797 spinlock_exit(); 798 return; 799 } 800 801 if (can_wakeup == 0) 802 can_wakeup = 1; 803 mb(); 804 805 enter_idle_powerx(); 806 spinlock_exit(); 807 } 808 809 static void 810 cpu_idle_power9(sbintime_t sbt) 811 { 812 register_t msr; 813 814 msr = mfmsr(); 815 816 /* Suspend external interrupts until stop instruction completes. */ 817 mtmsr(msr & ~PSL_EE); 818 /* Set the stop state to lowest latency, wake up to next instruction */ 819 mtspr(SPR_PSSCR, 0); 820 /* "stop" instruction (PowerISA 3.0) */ 821 __asm __volatile (".long 0x4c0002e4"); 822 /* 823 * Re-enable external interrupts to capture the interrupt that caused 824 * the wake up. 825 */ 826 mtmsr(msr); 827 828 } 829 #endif 830 831 int 832 cpu_idle_wakeup(int cpu) 833 { 834 835 return (0); 836 } 837