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