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 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 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 * 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 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 * 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 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