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
cpu_feature_setup(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
cpu_setup(u_int cpuid)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
cpu_est_clockrate(int cpu_id,uint64_t * cps)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
cpu_6xx_setup(int cpuid,uint16_t vers)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
cpu_6xx_print_cacheinfo(u_int cpuid,uint16_t vers)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
cpu_booke_setup(int cpuid,uint16_t vers)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
cpu_970_setup(int cpuid,uint16_t vers)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
cpu_powerx_setup(int cpuid,uint16_t vers)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
cpu_feature_bit(SYSCTL_HANDLER_ARGS)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
cpu_idle(int busy)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
cpu_idle_60x(sbintime_t sbt)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
cpu_idle_e500mc(sbintime_t sbt)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
cpu_idle_booke(sbintime_t sbt)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
cpu_idle_powerx(sbintime_t sbt)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
cpu_idle_power9(sbintime_t sbt)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
cpu_idle_wakeup(int cpu)907 cpu_idle_wakeup(int cpu)
908 {
909
910 return (0);
911 }
912