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