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 */
81static 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
202struct amd_sktmap_s {
203	uint32_t	skt_code;
204	char		sktstr[16];
205};
206static 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 */
238static 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
355static void
356synth_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
440uint32_t
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
458const char *
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
486uint32_t
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
504const char *
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 */
527const char CyrixInstead[] = X86_VENDORSTR_CYRIX;
528
529/*
530 * Map the vendor string to a type code
531 */
532uint_t
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