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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Portions Copyright 2009 Advanced Micro Devices, Inc.
34 * Copyright 2012 Jens Elkner <jel+illumos@cs.uni-magdeburg.de>
35 * Copyright 2012 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
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.
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.
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.
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>
64 #include <sys/hypervisor.h>
70 * 0 for family 0xf, revs B thru E
71 * 1 for family 0xf, revs F and G
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.
81 static uint32_t amd_skts
[8][8] = {
83 * Family 0xf revisions B through E
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 */
97 * Family 0xf revisions F and G
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 */
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 */
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 */
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 */
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 */
171 * Family 0x15 models 00 - 0f
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 */
186 * Family 0x15 models 10 - 1f
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 */
202 struct amd_sktmap_s
{
206 static 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" }
232 * Table for mapping AMD Family 0xf and AMD Family 0x10 model/stepping
233 * combination to chip "revision" and socket type.
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.
238 static const struct amd_rev_mapent
{
245 const char *rm_chiprevstr
;
249 * =============== AuthenticAMD Family 0xf ===============
253 * Rev B includes model 0x4 stepping 0 and model 0x5 stepping 0 and 1.
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
},
258 * Rev C0 includes model 0x4 stepping 8 and model 0x5 stepping 8
260 { 0xf, 0x04, 0x05, 0x8, 0x8, X86_CHIPREV_AMD_F_REV_C0
, "C0", A_SKTS_0
},
262 * Rev CG is the rest of extended model 0x0 - i.e., everything
263 * but the rev B and C0 combinations covered above.
265 { 0xf, 0x00, 0x0f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_CG
, "CG", A_SKTS_0
},
267 * Rev D has extended model 0x1.
269 { 0xf, 0x10, 0x1f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_D
, "D", A_SKTS_0
},
271 * Rev E has extended model 0x2.
272 * Extended model 0x3 is unused but available to grow into.
274 { 0xf, 0x20, 0x3f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_E
, "E", A_SKTS_0
},
276 * Rev F has extended models 0x4 and 0x5.
278 { 0xf, 0x40, 0x5f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_F
, "F", A_SKTS_1
},
280 * Rev G has extended model 0x6.
282 { 0xf, 0x60, 0x6f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_G
, "G", A_SKTS_1
},
285 * =============== AuthenticAMD Family 0x10 ===============
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.
292 { 0x10, 0x00, 0x00, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_A
, "A", A_SKTS_2
},
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.
298 { 0x10, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_B
, "B", A_SKTS_2
},
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.
304 { 0x10, 0x4, 0x6, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_C2
, "C2", A_SKTS_2
},
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.
310 { 0x10, 0x4, 0x6, 0x3, 0xf, X86_CHIPREV_AMD_10_REV_C3
, "C3", A_SKTS_2
},
313 * Rev D has models 8 and 9
314 * Give all of model 8 and 9 stepping 0 to rev D0.
316 { 0x10, 0x8, 0x9, 0x0, 0x0, X86_CHIPREV_AMD_10_REV_D0
, "D0", A_SKTS_2
},
319 * Rev D has models 8 and 9
320 * Give all of model 8 and 9 stepping range >= 1 to rev D1.
322 { 0x10, 0x8, 0x9, 0x1, 0xf, X86_CHIPREV_AMD_10_REV_D1
, "D1", A_SKTS_2
},
325 * Rev E has models A and stepping 0
326 * Give all of model A stepping range to rev E.
328 { 0x10, 0xA, 0xA, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_E
, "E", A_SKTS_2
},
331 * =============== AuthenticAMD Family 0x11 ===============
333 { 0x11, 0x03, 0x03, 0x0, 0xf, X86_CHIPREV_AMD_11_REV_B
, "B", A_SKTS_3
},
336 * =============== AuthenticAMD Family 0x12 ===============
338 { 0x12, 0x01, 0x01, 0x0, 0xf, X86_CHIPREV_AMD_12_REV_B
, "B", A_SKTS_4
},
341 * =============== AuthenticAMD Family 0x14 ===============
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
},
347 * =============== AuthenticAMD Family 0x15 ===============
349 { 0x15, 0x01, 0x01, 0x2, 0x2, X86_CHIPREV_AMD_15OR_REV_B2
, "B2",
351 { 0x15, 0x10, 0x10, 0x1, 0x1, X86_CHIPREV_AMD_15TN_REV_A1
, "A1",
356 synth_amd_info(uint_t family
, uint_t model
, uint_t step
,
357 uint32_t *skt_p
, uint32_t *chiprev_p
, const char **chiprevstr_p
)
359 const struct amd_rev_mapent
*rmp
;
366 for (i
= 0, rmp
= amd_revmap
; i
< sizeof (amd_revmap
) / sizeof (*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
) {
379 if (chiprev_p
!= NULL
)
380 *chiprev_p
= rmp
->rm_chiprev
;
381 if (chiprevstr_p
!= NULL
)
382 *chiprevstr_p
= rmp
->rm_chiprevstr
;
389 if (!is_controldom()) {
390 *skt_p
= X86_SOCKET_UNKNOWN
;
394 platform
= get_hwenv();
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];
402 * Starting with family 10h, socket type is stored in
403 * CPUID Fn8000_0001_EBX
405 struct cpuid_regs cp
;
408 cp
.cp_eax
= 0x80000001;
409 (void) __cpuid_insn(&cp
);
412 idx
= BITX(cp
.cp_ebx
, 31, 28);
416 *skt_p
= X86_SOCKET_UNKNOWN
;
418 *skt_p
= amd_skts
[rmp
->rm_sktidx
][idx
];
420 if (family
== 0x10) {
422 * Look at Ddr3Mode bit of DRAM Configuration
423 * High Register to decide whether this is
424 * actually AM3 or S1g4.
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
;
441 _cpuid_skt(uint_t vendor
, uint_t family
, uint_t model
, uint_t step
)
443 uint32_t skt
= X86_SOCKET_UNKNOWN
;
447 synth_amd_info(family
, model
, step
, &skt
, NULL
, NULL
);
459 _cpuid_sktstr(uint_t vendor
, uint_t family
, uint_t model
, uint_t step
)
461 const char *sktstr
= "Unknown";
462 struct amd_sktmap_s
*sktmapp
;
463 uint32_t skt
= X86_SOCKET_UNKNOWN
;
467 synth_amd_info(family
, model
, step
, &skt
, NULL
, NULL
);
469 sktmapp
= amd_sktmap
;
470 while (sktmapp
->skt_code
!= X86_SOCKET_UNKNOWN
) {
471 if (sktmapp
->skt_code
== skt
)
475 sktstr
= sktmapp
->sktstr
;
487 _cpuid_chiprev(uint_t vendor
, uint_t family
, uint_t model
, uint_t step
)
489 uint32_t chiprev
= X86_CHIPREV_UNKNOWN
;
493 synth_amd_info(family
, model
, step
, NULL
, &chiprev
, NULL
);
505 _cpuid_chiprevstr(uint_t vendor
, uint_t family
, uint_t model
, uint_t step
)
507 const char *revstr
= "Unknown";
511 synth_amd_info(family
, model
, step
, NULL
, NULL
, &revstr
);
524 * CyrixInstead is a variable used by the Cyrix detection code
527 const char CyrixInstead
[] = X86_VENDORSTR_CYRIX
;
530 * Map the vendor string to a type code
533 _cpuid_vendorstr_to_vendorcode(char *vendorstr
)
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
);
556 return (X86_VENDOR_IntelClone
);