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