xref: /titanic_50/usr/src/uts/i86pc/os/cpuid_subr.c (revision 79ec9da85c2648e2e165ce68612ad0cb6e185618)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27  */
28 
29 /*
30  * Portions Copyright 2009 Advanced Micro Devices, Inc.
31  */
32 
33 /*
34  * Copyright 2012 Jens Elkner <jel+illumos@cs.uni-magdeburg.de>
35  * Copyright 2012 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
36  */
37 
38 /*
39  * Support functions that interpret CPUID and similar information.
40  * These should not be used from anywhere other than cpuid.c and
41  * cmi_hw.c - as such we will not list them in any header file
42  * such as x86_archext.h.
43  *
44  * In cpuid.c we process CPUID information for each cpu_t instance
45  * we're presented with, and stash this raw information and material
46  * derived from it in per-cpu_t structures.
47  *
48  * If we are virtualized then the CPUID information derived from CPUID
49  * instructions executed in the guest is based on whatever the hypervisor
50  * wanted to make things look like, and the cpu_t are not necessarily in 1:1
51  * or fixed correspondence with real processor execution resources.  In cmi_hw.c
52  * we are interested in the native properties of a processor - for fault
53  * management (and potentially other, such as power management) purposes;
54  * it will tunnel through to real hardware information, and use the
55  * functionality provided in this file to process it.
56  */
57 
58 #include <sys/types.h>
59 #include <sys/systm.h>
60 #include <sys/bitmap.h>
61 #include <sys/x86_archext.h>
62 #include <sys/pci_cfgspace.h>
63 #ifdef __xpv
64 #include <sys/hypervisor.h>
65 #endif
66 
67 /*
68  * AMD socket types.
69  * First index :
70  *		0 for family 0xf, revs B thru E
71  *		1 for family 0xf, revs F and G
72  *		2 for family 0x10
73  *		3 for family 0x11
74  *		4 for family 0x12
75  *		5 for family 0x14
76  *		6 for family 0x15, models 00 - 0f
77  *		7 for family 0x15, models 10 - 1f
78  * Second index by (model & 0x3) for family 0fh,
79  * CPUID pkg bits (Fn8000_0001_EBX[31:28]) for later families.
80  */
81 static uint32_t amd_skts[8][8] = {
82 	/*
83 	 * Family 0xf revisions B through E
84 	 */
85 #define	A_SKTS_0			0
86 	{
87 		X86_SOCKET_754,		/* 0b000 */
88 		X86_SOCKET_940,		/* 0b001 */
89 		X86_SOCKET_754,		/* 0b010 */
90 		X86_SOCKET_939,		/* 0b011 */
91 		X86_SOCKET_UNKNOWN,	/* 0b100 */
92 		X86_SOCKET_UNKNOWN,	/* 0b101 */
93 		X86_SOCKET_UNKNOWN,	/* 0b110 */
94 		X86_SOCKET_UNKNOWN	/* 0b111 */
95 	},
96 	/*
97 	 * Family 0xf revisions F and G
98 	 */
99 #define	A_SKTS_1			1
100 	{
101 		X86_SOCKET_S1g1,	/* 0b000 */
102 		X86_SOCKET_F1207,	/* 0b001 */
103 		X86_SOCKET_UNKNOWN,	/* 0b010 */
104 		X86_SOCKET_AM2,		/* 0b011 */
105 		X86_SOCKET_UNKNOWN,	/* 0b100 */
106 		X86_SOCKET_UNKNOWN,	/* 0b101 */
107 		X86_SOCKET_UNKNOWN,	/* 0b110 */
108 		X86_SOCKET_UNKNOWN	/* 0b111 */
109 	},
110 	/*
111 	 * Family 0x10
112 	 */
113 #define	A_SKTS_2			2
114 	{
115 		X86_SOCKET_F1207,	/* 0b000 */
116 		X86_SOCKET_AM2R2,	/* 0b001 */
117 		X86_SOCKET_S1g3,	/* 0b010 */
118 		X86_SOCKET_G34,		/* 0b011 */
119 		X86_SOCKET_ASB2,	/* 0b100 */
120 		X86_SOCKET_C32,		/* 0b101 */
121 		X86_SOCKET_UNKNOWN,	/* 0b110 */
122 		X86_SOCKET_UNKNOWN	/* 0b111 */
123 	},
124 
125 	/*
126 	 * Family 0x11
127 	 */
128 #define	A_SKTS_3			3
129 	{
130 		X86_SOCKET_UNKNOWN,	/* 0b000 */
131 		X86_SOCKET_UNKNOWN,	/* 0b001 */
132 		X86_SOCKET_S1g2,	/* 0b010 */
133 		X86_SOCKET_UNKNOWN,	/* 0b011 */
134 		X86_SOCKET_UNKNOWN,	/* 0b100 */
135 		X86_SOCKET_UNKNOWN,	/* 0b101 */
136 		X86_SOCKET_UNKNOWN,	/* 0b110 */
137 		X86_SOCKET_UNKNOWN	/* 0b111 */
138 	},
139 
140 	/*
141 	 * Family 0x12
142 	 */
143 #define	A_SKTS_4			4
144 	{
145 		X86_SOCKET_UNKNOWN,	/* 0b000 */
146 		X86_SOCKET_FS1,		/* 0b001 */
147 		X86_SOCKET_FM1,		/* 0b010 */
148 		X86_SOCKET_UNKNOWN,	/* 0b011 */
149 		X86_SOCKET_UNKNOWN,	/* 0b100 */
150 		X86_SOCKET_UNKNOWN,	/* 0b101 */
151 		X86_SOCKET_UNKNOWN,	/* 0b110 */
152 		X86_SOCKET_UNKNOWN	/* 0b111 */
153 	},
154 
155 	/*
156 	 * Family 0x14
157 	 */
158 #define	A_SKTS_5			5
159 	{
160 		X86_SOCKET_FT1,		/* 0b000 */
161 		X86_SOCKET_UNKNOWN,	/* 0b001 */
162 		X86_SOCKET_UNKNOWN,	/* 0b010 */
163 		X86_SOCKET_UNKNOWN,	/* 0b011 */
164 		X86_SOCKET_UNKNOWN,	/* 0b100 */
165 		X86_SOCKET_UNKNOWN,	/* 0b101 */
166 		X86_SOCKET_UNKNOWN,	/* 0b110 */
167 		X86_SOCKET_UNKNOWN	/* 0b111 */
168 	},
169 
170 	/*
171 	 * Family 0x15 models 00 - 0f
172 	 */
173 #define	A_SKTS_6			6
174 	{
175 		X86_SOCKET_UNKNOWN,	/* 0b000 */
176 		X86_SOCKET_AM3R2,	/* 0b001 */
177 		X86_SOCKET_UNKNOWN,	/* 0b010 */
178 		X86_SOCKET_G34,		/* 0b011 */
179 		X86_SOCKET_UNKNOWN,	/* 0b100 */
180 		X86_SOCKET_C32,		/* 0b101 */
181 		X86_SOCKET_UNKNOWN,	/* 0b110 */
182 		X86_SOCKET_UNKNOWN	/* 0b111 */
183 	},
184 
185 	/*
186 	 * Family 0x15 models 10 - 1f
187 	 */
188 #define	A_SKTS_7			7
189 	{
190 		X86_SOCKET_FP2,		/* 0b000 */
191 		X86_SOCKET_FS1R2,	/* 0b001 */
192 		X86_SOCKET_FM2,		/* 0b010 */
193 		X86_SOCKET_UNKNOWN,	/* 0b011 */
194 		X86_SOCKET_UNKNOWN,	/* 0b100 */
195 		X86_SOCKET_UNKNOWN,	/* 0b101 */
196 		X86_SOCKET_UNKNOWN,	/* 0b110 */
197 		X86_SOCKET_UNKNOWN	/* 0b111 */
198 	},
199 
200 };
201 
202 struct amd_sktmap_s {
203 	uint32_t	skt_code;
204 	char		sktstr[16];
205 };
206 static struct amd_sktmap_s amd_sktmap[23] = {
207 	{ X86_SOCKET_754,	"754" },
208 	{ X86_SOCKET_939,	"939" },
209 	{ X86_SOCKET_940,	"940" },
210 	{ X86_SOCKET_S1g1,	"S1g1" },
211 	{ X86_SOCKET_AM2,	"AM2" },
212 	{ X86_SOCKET_F1207,	"F(1207)" },
213 	{ X86_SOCKET_S1g2,	"S1g2" },
214 	{ X86_SOCKET_S1g3,	"S1g3" },
215 	{ X86_SOCKET_AM,	"AM" },
216 	{ X86_SOCKET_AM2R2,	"AM2r2" },
217 	{ X86_SOCKET_AM3,	"AM3" },
218 	{ X86_SOCKET_G34,	"G34" },
219 	{ X86_SOCKET_ASB2,	"ASB2" },
220 	{ X86_SOCKET_C32,	"C32" },
221 	{ X86_SOCKET_FT1,	"FT1" },
222 	{ X86_SOCKET_FM1,	"FM1" },
223 	{ X86_SOCKET_FS1,	"FS1" },
224 	{ X86_SOCKET_AM3R2,	"AM3r2" },
225 	{ X86_SOCKET_FP2,	"FP2" },
226 	{ X86_SOCKET_FS1R2,	"FS1r2" },
227 	{ X86_SOCKET_FM2,	"FM2" },
228 	{ X86_SOCKET_UNKNOWN,	"Unknown" }
229 };
230 
231 /*
232  * Table for mapping AMD Family 0xf and AMD Family 0x10 model/stepping
233  * combination to chip "revision" and socket type.
234  *
235  * The first member of this array that matches a given family, extended model
236  * plus model range, and stepping range will be considered a match.
237  */
238 static const struct amd_rev_mapent {
239 	uint_t rm_family;
240 	uint_t rm_modello;
241 	uint_t rm_modelhi;
242 	uint_t rm_steplo;
243 	uint_t rm_stephi;
244 	uint32_t rm_chiprev;
245 	const char *rm_chiprevstr;
246 	int rm_sktidx;
247 } amd_revmap[] = {
248 	/*
249 	 * =============== AuthenticAMD Family 0xf ===============
250 	 */
251 
252 	/*
253 	 * Rev B includes model 0x4 stepping 0 and model 0x5 stepping 0 and 1.
254 	 */
255 	{ 0xf, 0x04, 0x04, 0x0, 0x0, X86_CHIPREV_AMD_F_REV_B, "B", A_SKTS_0 },
256 	{ 0xf, 0x05, 0x05, 0x0, 0x1, X86_CHIPREV_AMD_F_REV_B, "B", A_SKTS_0 },
257 	/*
258 	 * Rev C0 includes model 0x4 stepping 8 and model 0x5 stepping 8
259 	 */
260 	{ 0xf, 0x04, 0x05, 0x8, 0x8, X86_CHIPREV_AMD_F_REV_C0, "C0", A_SKTS_0 },
261 	/*
262 	 * Rev CG is the rest of extended model 0x0 - i.e., everything
263 	 * but the rev B and C0 combinations covered above.
264 	 */
265 	{ 0xf, 0x00, 0x0f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_CG, "CG", A_SKTS_0 },
266 	/*
267 	 * Rev D has extended model 0x1.
268 	 */
269 	{ 0xf, 0x10, 0x1f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_D, "D", A_SKTS_0 },
270 	/*
271 	 * Rev E has extended model 0x2.
272 	 * Extended model 0x3 is unused but available to grow into.
273 	 */
274 	{ 0xf, 0x20, 0x3f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_E, "E", A_SKTS_0 },
275 	/*
276 	 * Rev F has extended models 0x4 and 0x5.
277 	 */
278 	{ 0xf, 0x40, 0x5f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_F, "F", A_SKTS_1 },
279 	/*
280 	 * Rev G has extended model 0x6.
281 	 */
282 	{ 0xf, 0x60, 0x6f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_G, "G", A_SKTS_1 },
283 
284 	/*
285 	 * =============== AuthenticAMD Family 0x10 ===============
286 	 */
287 
288 	/*
289 	 * Rev A has model 0 and stepping 0/1/2 for DR-{A0,A1,A2}.
290 	 * Give all of model 0 stepping range to rev A.
291 	 */
292 	{ 0x10, 0x00, 0x00, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_A, "A", A_SKTS_2 },
293 
294 	/*
295 	 * Rev B has model 2 and steppings 0/1/0xa/2 for DR-{B0,B1,BA,B2}.
296 	 * Give all of model 2 stepping range to rev B.
297 	 */
298 	{ 0x10, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_B, "B", A_SKTS_2 },
299 
300 	/*
301 	 * Rev C has models 4-6 (depending on L3 cache configuration)
302 	 * Give all of models 4-6 stepping range 0-2 to rev C2.
303 	 */
304 	{ 0x10, 0x4, 0x6, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_C2, "C2", A_SKTS_2 },
305 
306 	/*
307 	 * Rev C has models 4-6 (depending on L3 cache configuration)
308 	 * Give all of models 4-6 stepping range >= 3 to rev C3.
309 	 */
310 	{ 0x10, 0x4, 0x6, 0x3, 0xf, X86_CHIPREV_AMD_10_REV_C3, "C3", A_SKTS_2 },
311 
312 	/*
313 	 * Rev D has models 8 and 9
314 	 * Give all of model 8 and 9 stepping 0 to rev D0.
315 	 */
316 	{ 0x10, 0x8, 0x9, 0x0, 0x0, X86_CHIPREV_AMD_10_REV_D0, "D0", A_SKTS_2 },
317 
318 	/*
319 	 * Rev D has models 8 and 9
320 	 * Give all of model 8 and 9 stepping range >= 1 to rev D1.
321 	 */
322 	{ 0x10, 0x8, 0x9, 0x1, 0xf, X86_CHIPREV_AMD_10_REV_D1, "D1", A_SKTS_2 },
323 
324 	/*
325 	 * Rev E has models A and stepping 0
326 	 * Give all of model A stepping range to rev E.
327 	 */
328 	{ 0x10, 0xA, 0xA, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_E, "E", A_SKTS_2 },
329 
330 	/*
331 	 * =============== AuthenticAMD Family 0x11 ===============
332 	 */
333 	{ 0x11, 0x03, 0x03, 0x0, 0xf, X86_CHIPREV_AMD_11_REV_B, "B", A_SKTS_3 },
334 
335 	/*
336 	 * =============== AuthenticAMD Family 0x12 ===============
337 	 */
338 	{ 0x12, 0x01, 0x01, 0x0, 0xf, X86_CHIPREV_AMD_12_REV_B, "B", A_SKTS_4 },
339 
340 	/*
341 	 * =============== AuthenticAMD Family 0x14 ===============
342 	 */
343 	{ 0x14, 0x01, 0x01, 0x0, 0xf, X86_CHIPREV_AMD_14_REV_B, "B", A_SKTS_5 },
344 	{ 0x14, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_14_REV_C, "C", A_SKTS_5 },
345 
346 	/*
347 	 * =============== AuthenticAMD Family 0x15 ===============
348 	 */
349 	{ 0x15, 0x01, 0x01, 0x2, 0x2, X86_CHIPREV_AMD_15OR_REV_B2, "B2",
350 	    A_SKTS_6 },
351 	{ 0x15, 0x10, 0x10, 0x1, 0x1, X86_CHIPREV_AMD_15TN_REV_A1, "A1",
352 	    A_SKTS_7 },
353 };
354 
355 static void
synth_amd_info(uint_t family,uint_t model,uint_t step,uint32_t * skt_p,uint32_t * chiprev_p,const char ** chiprevstr_p)356 synth_amd_info(uint_t family, uint_t model, uint_t step,
357     uint32_t *skt_p, uint32_t *chiprev_p, const char **chiprevstr_p)
358 {
359 	const struct amd_rev_mapent *rmp;
360 	int found = 0;
361 	int i;
362 
363 	if (family < 0xf)
364 		return;
365 
366 	for (i = 0, rmp = amd_revmap; i < sizeof (amd_revmap) / sizeof (*rmp);
367 	    i++, rmp++) {
368 		if (family == rmp->rm_family &&
369 		    model >= rmp->rm_modello && model <= rmp->rm_modelhi &&
370 		    step >= rmp->rm_steplo && step <= rmp->rm_stephi) {
371 			found = 1;
372 			break;
373 		}
374 	}
375 
376 	if (!found)
377 		return;
378 
379 	if (chiprev_p != NULL)
380 		*chiprev_p = rmp->rm_chiprev;
381 	if (chiprevstr_p != NULL)
382 		*chiprevstr_p = rmp->rm_chiprevstr;
383 
384 	if (skt_p != NULL) {
385 		int platform;
386 
387 #ifdef __xpv
388 		/* PV guest */
389 		if (!is_controldom()) {
390 			*skt_p = X86_SOCKET_UNKNOWN;
391 			return;
392 		}
393 #endif
394 		platform = get_hwenv();
395 
396 		if ((platform & HW_VIRTUAL) != 0) {
397 			*skt_p = X86_SOCKET_UNKNOWN;
398 		} else if (family == 0xf) {
399 			*skt_p = amd_skts[rmp->rm_sktidx][model & 0x3];
400 		} else {
401 			/*
402 			 * Starting with family 10h, socket type is stored in
403 			 * CPUID Fn8000_0001_EBX
404 			 */
405 			struct cpuid_regs cp;
406 			int idx;
407 
408 			cp.cp_eax = 0x80000001;
409 			(void) __cpuid_insn(&cp);
410 
411 			/* PkgType bits */
412 			idx = BITX(cp.cp_ebx, 31, 28);
413 
414 			if (idx > 7) {
415 				/* Reserved bits */
416 				*skt_p = X86_SOCKET_UNKNOWN;
417 			} else {
418 				*skt_p = amd_skts[rmp->rm_sktidx][idx];
419 			}
420 			if (family == 0x10) {
421 				/*
422 				 * Look at Ddr3Mode bit of DRAM Configuration
423 				 * High Register to decide whether this is
424 				 * actually AM3 or S1g4.
425 				 */
426 				uint32_t val;
427 
428 				val = pci_getl_func(0, 24, 2, 0x94);
429 				if (BITX(val, 8, 8)) {
430 					if (*skt_p == X86_SOCKET_AM2R2)
431 						*skt_p = X86_SOCKET_AM3;
432 					else if (*skt_p == X86_SOCKET_S1g3)
433 						*skt_p = X86_SOCKET_S1g4;
434 				}
435 			}
436 		}
437 	}
438 }
439 
440 uint32_t
_cpuid_skt(uint_t vendor,uint_t family,uint_t model,uint_t step)441 _cpuid_skt(uint_t vendor, uint_t family, uint_t model, uint_t step)
442 {
443 	uint32_t skt = X86_SOCKET_UNKNOWN;
444 
445 	switch (vendor) {
446 	case X86_VENDOR_AMD:
447 		synth_amd_info(family, model, step, &skt, NULL, NULL);
448 		break;
449 
450 	default:
451 		break;
452 
453 	}
454 
455 	return (skt);
456 }
457 
458 const char *
_cpuid_sktstr(uint_t vendor,uint_t family,uint_t model,uint_t step)459 _cpuid_sktstr(uint_t vendor, uint_t family, uint_t model, uint_t step)
460 {
461 	const char *sktstr = "Unknown";
462 	struct amd_sktmap_s *sktmapp;
463 	uint32_t skt = X86_SOCKET_UNKNOWN;
464 
465 	switch (vendor) {
466 	case X86_VENDOR_AMD:
467 		synth_amd_info(family, model, step, &skt, NULL, NULL);
468 
469 		sktmapp = amd_sktmap;
470 		while (sktmapp->skt_code != X86_SOCKET_UNKNOWN) {
471 			if (sktmapp->skt_code == skt)
472 				break;
473 			sktmapp++;
474 		}
475 		sktstr = sktmapp->sktstr;
476 		break;
477 
478 	default:
479 		break;
480 
481 	}
482 
483 	return (sktstr);
484 }
485 
486 uint32_t
_cpuid_chiprev(uint_t vendor,uint_t family,uint_t model,uint_t step)487 _cpuid_chiprev(uint_t vendor, uint_t family, uint_t model, uint_t step)
488 {
489 	uint32_t chiprev = X86_CHIPREV_UNKNOWN;
490 
491 	switch (vendor) {
492 	case X86_VENDOR_AMD:
493 		synth_amd_info(family, model, step, NULL, &chiprev, NULL);
494 		break;
495 
496 	default:
497 		break;
498 
499 	}
500 
501 	return (chiprev);
502 }
503 
504 const char *
_cpuid_chiprevstr(uint_t vendor,uint_t family,uint_t model,uint_t step)505 _cpuid_chiprevstr(uint_t vendor, uint_t family, uint_t model, uint_t step)
506 {
507 	const char *revstr = "Unknown";
508 
509 	switch (vendor) {
510 	case X86_VENDOR_AMD:
511 		synth_amd_info(family, model, step, NULL, NULL, &revstr);
512 		break;
513 
514 	default:
515 		break;
516 
517 	}
518 
519 	return (revstr);
520 
521 }
522 
523 /*
524  * CyrixInstead is a variable used by the Cyrix detection code
525  * in locore.
526  */
527 const char CyrixInstead[] = X86_VENDORSTR_CYRIX;
528 
529 /*
530  * Map the vendor string to a type code
531  */
532 uint_t
_cpuid_vendorstr_to_vendorcode(char * vendorstr)533 _cpuid_vendorstr_to_vendorcode(char *vendorstr)
534 {
535 	if (strcmp(vendorstr, X86_VENDORSTR_Intel) == 0)
536 		return (X86_VENDOR_Intel);
537 	else if (strcmp(vendorstr, X86_VENDORSTR_AMD) == 0)
538 		return (X86_VENDOR_AMD);
539 	else if (strcmp(vendorstr, X86_VENDORSTR_TM) == 0)
540 		return (X86_VENDOR_TM);
541 	else if (strcmp(vendorstr, CyrixInstead) == 0)
542 		return (X86_VENDOR_Cyrix);
543 	else if (strcmp(vendorstr, X86_VENDORSTR_UMC) == 0)
544 		return (X86_VENDOR_UMC);
545 	else if (strcmp(vendorstr, X86_VENDORSTR_NexGen) == 0)
546 		return (X86_VENDOR_NexGen);
547 	else if (strcmp(vendorstr, X86_VENDORSTR_Centaur) == 0)
548 		return (X86_VENDOR_Centaur);
549 	else if (strcmp(vendorstr, X86_VENDORSTR_Rise) == 0)
550 		return (X86_VENDOR_Rise);
551 	else if (strcmp(vendorstr, X86_VENDORSTR_SiS) == 0)
552 		return (X86_VENDOR_SiS);
553 	else if (strcmp(vendorstr, X86_VENDORSTR_NSC) == 0)
554 		return (X86_VENDOR_NSC);
555 	else
556 		return (X86_VENDOR_IntelClone);
557 }
558