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