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