xref: /freebsd/sys/powerpc/powerpc/cpu.c (revision 6f0c2938e895bd3ddb14f44acf36dba3c6156a3f)
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