cpuid_subr.c revision 64452efd23bde8f59916acb588864db270793fc0
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 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Support functions that interpret CPUID and similar information.
29 * These should not be used from anywhere other than cpuid.c and
30 * cmi_hw.c - as such we will not list them in any header file
31 * such as x86_archext.h.
32 *
33 * In cpuid.c we process CPUID information for each cpu_t instance
34 * we're presented with, and stash this raw information and material
35 * derived from it in per-cpu_t structures.
36 *
37 * If we are virtualized then the CPUID information derived from CPUID
38 * instructions executed in the guest is based on whatever the hypervisor
39 * wanted to make things look like, and the cpu_t are not necessarily in 1:1
40 * or fixed correspondence with real processor execution resources.  In cmi_hw.c
41 * we are interested in the native properties of a processor - for fault
42 * management (and potentially other, such as power management) purposes;
43 * it will tunnel through to real hardware information, and use the
44 * functionality provided in this file to process it.
45 */
46
47#include <sys/types.h>
48#include <sys/systm.h>
49#include <sys/x86_archext.h>
50
51/*
52 * AMD family 0xf and family 0x10 socket types.
53 * First index :
54 *		0 for family 0xf, revs B thru E
55 *		1 for family 0xf, revs F and G
56 *		2 for family 0x10, rev B
57 * Second index by (model & 0x3)
58 */
59static uint32_t amd_skts[3][4] = {
60	/*
61	 * Family 0xf revisions B through E
62	 */
63#define	A_SKTS_0			0
64	{
65		X86_SOCKET_754,		/* 0b00 */
66		X86_SOCKET_940,		/* 0b01 */
67		X86_SOCKET_754,		/* 0b10 */
68		X86_SOCKET_939		/* 0b11 */
69	},
70	/*
71	 * Family 0xf revisions F and G
72	 */
73#define	A_SKTS_1			1
74	{
75		X86_SOCKET_S1g1,	/* 0b00 */
76		X86_SOCKET_F1207,	/* 0b01 */
77		X86_SOCKET_UNKNOWN,	/* 0b10 */
78		X86_SOCKET_AM2		/* 0b11 */
79	},
80	/*
81	 * Family 0x10 revisions A and B
82	 * It is not clear whether, as new sockets release, that
83	 * model & 0x3 will id socket for this family
84	 */
85#define	A_SKTS_2			2
86	{
87		X86_SOCKET_F1207,	/* 0b00 */
88		X86_SOCKET_F1207,	/* 0b01 */
89		X86_SOCKET_F1207,	/* 0b10 */
90		X86_SOCKET_F1207,	/* 0b11 */
91	}
92};
93
94/*
95 * Table for mapping AMD Family 0xf and AMD Family 0x10 model/stepping
96 * combination to chip "revision" and socket type.
97 *
98 * The first member of this array that matches a given family, extended model
99 * plus model range, and stepping range will be considered a match.
100 */
101static const struct amd_rev_mapent {
102	uint_t rm_family;
103	uint_t rm_modello;
104	uint_t rm_modelhi;
105	uint_t rm_steplo;
106	uint_t rm_stephi;
107	uint32_t rm_chiprev;
108	const char *rm_chiprevstr;
109	int rm_sktidx;
110} amd_revmap[] = {
111	/*
112	 * =============== AuthenticAMD Family 0xf ===============
113	 */
114
115	/*
116	 * Rev B includes model 0x4 stepping 0 and model 0x5 stepping 0 and 1.
117	 */
118	{ 0xf, 0x04, 0x04, 0x0, 0x0, X86_CHIPREV_AMD_F_REV_B, "B", A_SKTS_0 },
119	{ 0xf, 0x05, 0x05, 0x0, 0x1, X86_CHIPREV_AMD_F_REV_B, "B", A_SKTS_0 },
120	/*
121	 * Rev C0 includes model 0x4 stepping 8 and model 0x5 stepping 8
122	 */
123	{ 0xf, 0x04, 0x05, 0x8, 0x8, X86_CHIPREV_AMD_F_REV_C0, "C0", A_SKTS_0 },
124	/*
125	 * Rev CG is the rest of extended model 0x0 - i.e., everything
126	 * but the rev B and C0 combinations covered above.
127	 */
128	{ 0xf, 0x00, 0x0f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_CG, "CG", A_SKTS_0 },
129	/*
130	 * Rev D has extended model 0x1.
131	 */
132	{ 0xf, 0x10, 0x1f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_D, "D", A_SKTS_0 },
133	/*
134	 * Rev E has extended model 0x2.
135	 * Extended model 0x3 is unused but available to grow into.
136	 */
137	{ 0xf, 0x20, 0x3f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_E, "E", A_SKTS_0 },
138	/*
139	 * Rev F has extended models 0x4 and 0x5.
140	 */
141	{ 0xf, 0x40, 0x5f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_F, "F", A_SKTS_1 },
142	/*
143	 * Rev G has extended model 0x6.
144	 */
145	{ 0xf, 0x60, 0x6f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_G, "G", A_SKTS_1 },
146
147	/*
148	 * =============== AuthenticAMD Family 0x10 ===============
149	 */
150
151	/*
152	 * Rev A has model 0 and stepping 0/1/2 for DR-{A0,A1,A2}.
153	 * Give all of model 0 stepping range to rev A.
154	 */
155	{ 0x10, 0x00, 0x00, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_A, "A", A_SKTS_2 },
156
157	/*
158	 * Rev B has model 2 and steppings 0/1/0xa/2 for DR-{B0,B1,BA,B2}.
159	 * Give all of model 2 stepping range to rev B.
160	 */
161	{ 0x10, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_B, "B", A_SKTS_2 },
162
163	/*
164	 * Rev C has models 4-6 (depending on L3 cache configuration)
165	 * Give all of model 2 stepping range to rev c.
166	 */
167	{ 0x10, 0x04, 0x06, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_C, "C", A_SKTS_2 },
168};
169
170static void
171synth_amd_info(uint_t family, uint_t model, uint_t step,
172    uint32_t *skt_p, uint32_t *chiprev_p, const char **chiprevstr_p)
173{
174	const struct amd_rev_mapent *rmp;
175	int found = 0;
176	int i;
177
178	/*
179	 * Currently only AMD family 0xf and family 0x10 use these fields.
180	 */
181	if (family != 0xf && family != 0x10)
182		return;
183
184	for (i = 0, rmp = amd_revmap; i < sizeof (amd_revmap) / sizeof (*rmp);
185	    i++, rmp++) {
186		if (family == rmp->rm_family &&
187		    model >= rmp->rm_modello && model <= rmp->rm_modelhi &&
188		    step >= rmp->rm_steplo && step <= rmp->rm_stephi) {
189			found = 1;
190			break;
191		}
192	}
193
194	if (found) {
195		if (skt_p != NULL)
196			*skt_p = amd_skts[rmp->rm_sktidx][model & 0x3];
197		if (chiprev_p != NULL)
198			*chiprev_p = rmp->rm_chiprev;
199		if (chiprevstr_p != NULL)
200			*chiprevstr_p = rmp->rm_chiprevstr;
201	}
202}
203
204uint32_t
205_cpuid_skt(uint_t vendor, uint_t family, uint_t model, uint_t step)
206{
207	uint32_t skt = X86_SOCKET_UNKNOWN;
208
209	switch (vendor) {
210	case X86_VENDOR_AMD:
211		synth_amd_info(family, model, step, &skt, NULL, NULL);
212		break;
213
214	default:
215		break;
216
217	}
218
219	return (skt);
220}
221
222uint32_t
223_cpuid_chiprev(uint_t vendor, uint_t family, uint_t model, uint_t step)
224{
225	uint32_t chiprev = X86_CHIPREV_UNKNOWN;
226
227	switch (vendor) {
228	case X86_VENDOR_AMD:
229		synth_amd_info(family, model, step, NULL, &chiprev, NULL);
230		break;
231
232	default:
233		break;
234
235	}
236
237	return (chiprev);
238}
239
240const char *
241_cpuid_chiprevstr(uint_t vendor, uint_t family, uint_t model, uint_t step)
242{
243	const char *revstr = "Unknown";
244
245	switch (vendor) {
246	case X86_VENDOR_AMD:
247		synth_amd_info(family, model, step, NULL, NULL, &revstr);
248		break;
249
250	default:
251		break;
252
253	}
254
255	return (revstr);
256
257}
258
259/*
260 * CyrixInstead is a variable used by the Cyrix detection code
261 * in locore.
262 */
263const char CyrixInstead[] = X86_VENDORSTR_CYRIX;
264
265/*
266 * Map the vendor string to a type code
267 */
268uint_t
269_cpuid_vendorstr_to_vendorcode(char *vendorstr)
270{
271	if (strcmp(vendorstr, X86_VENDORSTR_Intel) == 0)
272		return (X86_VENDOR_Intel);
273	else if (strcmp(vendorstr, X86_VENDORSTR_AMD) == 0)
274		return (X86_VENDOR_AMD);
275	else if (strcmp(vendorstr, X86_VENDORSTR_TM) == 0)
276		return (X86_VENDOR_TM);
277	else if (strcmp(vendorstr, CyrixInstead) == 0)
278		return (X86_VENDOR_Cyrix);
279	else if (strcmp(vendorstr, X86_VENDORSTR_UMC) == 0)
280		return (X86_VENDOR_UMC);
281	else if (strcmp(vendorstr, X86_VENDORSTR_NexGen) == 0)
282		return (X86_VENDOR_NexGen);
283	else if (strcmp(vendorstr, X86_VENDORSTR_Centaur) == 0)
284		return (X86_VENDOR_Centaur);
285	else if (strcmp(vendorstr, X86_VENDORSTR_Rise) == 0)
286		return (X86_VENDOR_Rise);
287	else if (strcmp(vendorstr, X86_VENDORSTR_SiS) == 0)
288		return (X86_VENDOR_SiS);
289	else if (strcmp(vendorstr, X86_VENDORSTR_NSC) == 0)
290		return (X86_VENDOR_NSC);
291	else
292		return (X86_VENDOR_IntelClone);
293}
294