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