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 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 */
28
29 /*
30 * Portions Copyright 2009 Advanced Micro Devices, Inc.
31 */
32
33 /*
34 * Copyright 2012 Jens Elkner <jel+illumos@cs.uni-magdeburg.de>
35 * Copyright 2012 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
36 */
37
38 /*
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.
43 *
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.
47 *
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.
56 */
57
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>
63 #ifdef __xpv
64 #include <sys/hypervisor.h>
65 #endif
66
67 /*
68 * AMD socket types.
69 * First index :
70 * 0 for family 0xf, revs B thru E
71 * 1 for family 0xf, revs F and G
72 * 2 for family 0x10
73 * 3 for family 0x11
74 * 4 for family 0x12
75 * 5 for family 0x14
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.
80 */
81 static uint32_t amd_skts[8][8] = {
82 /*
83 * Family 0xf revisions B through E
84 */
85 #define A_SKTS_0 0
86 {
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 */
95 },
96 /*
97 * Family 0xf revisions F and G
98 */
99 #define A_SKTS_1 1
100 {
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 */
109 },
110 /*
111 * Family 0x10
112 */
113 #define A_SKTS_2 2
114 {
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 */
123 },
124
125 /*
126 * Family 0x11
127 */
128 #define A_SKTS_3 3
129 {
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 */
138 },
139
140 /*
141 * Family 0x12
142 */
143 #define A_SKTS_4 4
144 {
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 */
153 },
154
155 /*
156 * Family 0x14
157 */
158 #define A_SKTS_5 5
159 {
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 */
168 },
169
170 /*
171 * Family 0x15 models 00 - 0f
172 */
173 #define A_SKTS_6 6
174 {
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 */
183 },
184
185 /*
186 * Family 0x15 models 10 - 1f
187 */
188 #define A_SKTS_7 7
189 {
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 */
198 },
199
200 };
201
202 struct amd_sktmap_s {
203 uint32_t skt_code;
204 char sktstr[16];
205 };
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" }
229 };
230
231 /*
232 * Table for mapping AMD Family 0xf and AMD Family 0x10 model/stepping
233 * combination to chip "revision" and socket type.
234 *
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.
237 */
238 static const struct amd_rev_mapent {
239 uint_t rm_family;
240 uint_t rm_modello;
241 uint_t rm_modelhi;
242 uint_t rm_steplo;
243 uint_t rm_stephi;
244 uint32_t rm_chiprev;
245 const char *rm_chiprevstr;
246 int rm_sktidx;
247 } amd_revmap[] = {
248 /*
249 * =============== AuthenticAMD Family 0xf ===============
250 */
251
252 /*
253 * Rev B includes model 0x4 stepping 0 and model 0x5 stepping 0 and 1.
254 */
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 },
257 /*
258 * Rev C0 includes model 0x4 stepping 8 and model 0x5 stepping 8
259 */
260 { 0xf, 0x04, 0x05, 0x8, 0x8, X86_CHIPREV_AMD_F_REV_C0, "C0", A_SKTS_0 },
261 /*
262 * Rev CG is the rest of extended model 0x0 - i.e., everything
263 * but the rev B and C0 combinations covered above.
264 */
265 { 0xf, 0x00, 0x0f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_CG, "CG", A_SKTS_0 },
266 /*
267 * Rev D has extended model 0x1.
268 */
269 { 0xf, 0x10, 0x1f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_D, "D", A_SKTS_0 },
270 /*
271 * Rev E has extended model 0x2.
272 * Extended model 0x3 is unused but available to grow into.
273 */
274 { 0xf, 0x20, 0x3f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_E, "E", A_SKTS_0 },
275 /*
276 * Rev F has extended models 0x4 and 0x5.
277 */
278 { 0xf, 0x40, 0x5f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_F, "F", A_SKTS_1 },
279 /*
280 * Rev G has extended model 0x6.
281 */
282 { 0xf, 0x60, 0x6f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_G, "G", A_SKTS_1 },
283
284 /*
285 * =============== AuthenticAMD Family 0x10 ===============
286 */
287
288 /*
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.
291 */
292 { 0x10, 0x00, 0x00, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_A, "A", A_SKTS_2 },
293
294 /*
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.
297 */
298 { 0x10, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_B, "B", A_SKTS_2 },
299
300 /*
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.
303 */
304 { 0x10, 0x4, 0x6, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_C2, "C2", A_SKTS_2 },
305
306 /*
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.
309 */
310 { 0x10, 0x4, 0x6, 0x3, 0xf, X86_CHIPREV_AMD_10_REV_C3, "C3", A_SKTS_2 },
311
312 /*
313 * Rev D has models 8 and 9
314 * Give all of model 8 and 9 stepping 0 to rev D0.
315 */
316 { 0x10, 0x8, 0x9, 0x0, 0x0, X86_CHIPREV_AMD_10_REV_D0, "D0", A_SKTS_2 },
317
318 /*
319 * Rev D has models 8 and 9
320 * Give all of model 8 and 9 stepping range >= 1 to rev D1.
321 */
322 { 0x10, 0x8, 0x9, 0x1, 0xf, X86_CHIPREV_AMD_10_REV_D1, "D1", A_SKTS_2 },
323
324 /*
325 * Rev E has models A and stepping 0
326 * Give all of model A stepping range to rev E.
327 */
328 { 0x10, 0xA, 0xA, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_E, "E", A_SKTS_2 },
329
330 /*
331 * =============== AuthenticAMD Family 0x11 ===============
332 */
333 { 0x11, 0x03, 0x03, 0x0, 0xf, X86_CHIPREV_AMD_11_REV_B, "B", A_SKTS_3 },
334
335 /*
336 * =============== AuthenticAMD Family 0x12 ===============
337 */
338 { 0x12, 0x01, 0x01, 0x0, 0xf, X86_CHIPREV_AMD_12_REV_B, "B", A_SKTS_4 },
339
340 /*
341 * =============== AuthenticAMD Family 0x14 ===============
342 */
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 },
345
346 /*
347 * =============== AuthenticAMD Family 0x15 ===============
348 */
349 { 0x15, 0x01, 0x01, 0x2, 0x2, X86_CHIPREV_AMD_15OR_REV_B2, "B2",
350 A_SKTS_6 },
351 { 0x15, 0x10, 0x10, 0x1, 0x1, X86_CHIPREV_AMD_15TN_REV_A1, "A1",
352 A_SKTS_7 },
353 };
354
355 static void
synth_amd_info(uint_t family,uint_t model,uint_t step,uint32_t * skt_p,uint32_t * chiprev_p,const char ** chiprevstr_p)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)
358 {
359 const struct amd_rev_mapent *rmp;
360 int found = 0;
361 int i;
362
363 if (family < 0xf)
364 return;
365
366 for (i = 0, rmp = amd_revmap; i < sizeof (amd_revmap) / sizeof (*rmp);
367 i++, 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) {
371 found = 1;
372 break;
373 }
374 }
375
376 if (!found)
377 return;
378
379 if (chiprev_p != NULL)
380 *chiprev_p = rmp->rm_chiprev;
381 if (chiprevstr_p != NULL)
382 *chiprevstr_p = rmp->rm_chiprevstr;
383
384 if (skt_p != NULL) {
385 int platform;
386
387 #ifdef __xpv
388 /* PV guest */
389 if (!is_controldom()) {
390 *skt_p = X86_SOCKET_UNKNOWN;
391 return;
392 }
393 #endif
394 platform = get_hwenv();
395
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];
400 } else {
401 /*
402 * Starting with family 10h, socket type is stored in
403 * CPUID Fn8000_0001_EBX
404 */
405 struct cpuid_regs cp;
406 int idx;
407
408 cp.cp_eax = 0x80000001;
409 (void) __cpuid_insn(&cp);
410
411 /* PkgType bits */
412 idx = BITX(cp.cp_ebx, 31, 28);
413
414 if (idx > 7) {
415 /* Reserved bits */
416 *skt_p = X86_SOCKET_UNKNOWN;
417 } else {
418 *skt_p = amd_skts[rmp->rm_sktidx][idx];
419 }
420 if (family == 0x10) {
421 /*
422 * Look at Ddr3Mode bit of DRAM Configuration
423 * High Register to decide whether this is
424 * actually AM3 or S1g4.
425 */
426 uint32_t val;
427
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;
434 }
435 }
436 }
437 }
438 }
439
440 uint32_t
_cpuid_skt(uint_t vendor,uint_t family,uint_t model,uint_t step)441 _cpuid_skt(uint_t vendor, uint_t family, uint_t model, uint_t step)
442 {
443 uint32_t skt = X86_SOCKET_UNKNOWN;
444
445 switch (vendor) {
446 case X86_VENDOR_AMD:
447 synth_amd_info(family, model, step, &skt, NULL, NULL);
448 break;
449
450 default:
451 break;
452
453 }
454
455 return (skt);
456 }
457
458 const char *
_cpuid_sktstr(uint_t vendor,uint_t family,uint_t model,uint_t step)459 _cpuid_sktstr(uint_t vendor, uint_t family, uint_t model, uint_t step)
460 {
461 const char *sktstr = "Unknown";
462 struct amd_sktmap_s *sktmapp;
463 uint32_t skt = X86_SOCKET_UNKNOWN;
464
465 switch (vendor) {
466 case X86_VENDOR_AMD:
467 synth_amd_info(family, model, step, &skt, NULL, NULL);
468
469 sktmapp = amd_sktmap;
470 while (sktmapp->skt_code != X86_SOCKET_UNKNOWN) {
471 if (sktmapp->skt_code == skt)
472 break;
473 sktmapp++;
474 }
475 sktstr = sktmapp->sktstr;
476 break;
477
478 default:
479 break;
480
481 }
482
483 return (sktstr);
484 }
485
486 uint32_t
_cpuid_chiprev(uint_t vendor,uint_t family,uint_t model,uint_t step)487 _cpuid_chiprev(uint_t vendor, uint_t family, uint_t model, uint_t step)
488 {
489 uint32_t chiprev = X86_CHIPREV_UNKNOWN;
490
491 switch (vendor) {
492 case X86_VENDOR_AMD:
493 synth_amd_info(family, model, step, NULL, &chiprev, NULL);
494 break;
495
496 default:
497 break;
498
499 }
500
501 return (chiprev);
502 }
503
504 const char *
_cpuid_chiprevstr(uint_t vendor,uint_t family,uint_t model,uint_t step)505 _cpuid_chiprevstr(uint_t vendor, uint_t family, uint_t model, uint_t step)
506 {
507 const char *revstr = "Unknown";
508
509 switch (vendor) {
510 case X86_VENDOR_AMD:
511 synth_amd_info(family, model, step, NULL, NULL, &revstr);
512 break;
513
514 default:
515 break;
516
517 }
518
519 return (revstr);
520
521 }
522
523 /*
524 * CyrixInstead is a variable used by the Cyrix detection code
525 * in locore.
526 */
527 const char CyrixInstead[] = X86_VENDORSTR_CYRIX;
528
529 /*
530 * Map the vendor string to a type code
531 */
532 uint_t
_cpuid_vendorstr_to_vendorcode(char * vendorstr)533 _cpuid_vendorstr_to_vendorcode(char *vendorstr)
534 {
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);
555 else
556 return (X86_VENDOR_IntelClone);
557 }
558