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 */
70static 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
130struct amd_sktmap_s {
131	uint32_t	skt_code;
132	char		sktstr[16];
133};
134static 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 */
159static 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
239static void
240synth_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
323uint32_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
341const 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
369uint32_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
387const 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 */
410const char CyrixInstead[] = X86_VENDORSTR_CYRIX;
411
412/*
413 * Map the vendor string to a type code
414 */
415uint_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