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 * Copyright 2012 Jens Elkner <jel+illumos@cs.uni-magdeburg.de> 33 * Copyright 2012 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> 34 */ 35 36 /* 37 * Support functions that interpret CPUID and similar information. 38 * These should not be used from anywhere other than cpuid.c and 39 * cmi_hw.c - as such we will not list them in any header file 40 * such as x86_archext.h. 41 * 42 * In cpuid.c we process CPUID information for each cpu_t instance 43 * we're presented with, and stash this raw information and material 44 * derived from it in per-cpu_t structures. 45 * 46 * If we are virtualized then the CPUID information derived from CPUID 47 * instructions executed in the guest is based on whatever the hypervisor 48 * wanted to make things look like, and the cpu_t are not necessarily in 1:1 49 * or fixed correspondence with real processor execution resources. In cmi_hw.c 50 * we are interested in the native properties of a processor - for fault 51 * management (and potentially other, such as power management) purposes; 52 * it will tunnel through to real hardware information, and use the 53 * functionality provided in this file to process it. 54 */ 55 56 #include <sys/types.h> 57 #include <sys/systm.h> 58 #include <sys/bitmap.h> 59 #include <sys/x86_archext.h> 60 #include <sys/pci_cfgspace.h> 61 #ifdef __xpv 62 #include <sys/hypervisor.h> 63 #endif 64 65 /* 66 * AMD socket types. 67 * First index : 68 * 0 for family 0xf, revs B thru E 69 * 1 for family 0xf, revs F and G 70 * 2 for family 0x10 71 * 3 for family 0x11 72 * 4 for family 0x12 73 * 5 for family 0x14 74 * 6 for family 0x15, models 00 - 0f 75 * 7 for family 0x15, models 10 - 1f 76 * Second index by (model & 0x3) for family 0fh, 77 * CPUID pkg bits (Fn8000_0001_EBX[31:28]) for later families. 78 */ 79 static uint32_t amd_skts[8][8] = { 80 /* 81 * Family 0xf revisions B through E 82 */ 83 #define A_SKTS_0 0 84 { 85 X86_SOCKET_754, /* 0b000 */ 86 X86_SOCKET_940, /* 0b001 */ 87 X86_SOCKET_754, /* 0b010 */ 88 X86_SOCKET_939, /* 0b011 */ 89 X86_SOCKET_UNKNOWN, /* 0b100 */ 90 X86_SOCKET_UNKNOWN, /* 0b101 */ 91 X86_SOCKET_UNKNOWN, /* 0b110 */ 92 X86_SOCKET_UNKNOWN /* 0b111 */ 93 }, 94 /* 95 * Family 0xf revisions F and G 96 */ 97 #define A_SKTS_1 1 98 { 99 X86_SOCKET_S1g1, /* 0b000 */ 100 X86_SOCKET_F1207, /* 0b001 */ 101 X86_SOCKET_UNKNOWN, /* 0b010 */ 102 X86_SOCKET_AM2, /* 0b011 */ 103 X86_SOCKET_UNKNOWN, /* 0b100 */ 104 X86_SOCKET_UNKNOWN, /* 0b101 */ 105 X86_SOCKET_UNKNOWN, /* 0b110 */ 106 X86_SOCKET_UNKNOWN /* 0b111 */ 107 }, 108 /* 109 * Family 0x10 110 */ 111 #define A_SKTS_2 2 112 { 113 X86_SOCKET_F1207, /* 0b000 */ 114 X86_SOCKET_AM2R2, /* 0b001 */ 115 X86_SOCKET_S1g3, /* 0b010 */ 116 X86_SOCKET_G34, /* 0b011 */ 117 X86_SOCKET_ASB2, /* 0b100 */ 118 X86_SOCKET_C32, /* 0b101 */ 119 X86_SOCKET_UNKNOWN, /* 0b110 */ 120 X86_SOCKET_UNKNOWN /* 0b111 */ 121 }, 122 123 /* 124 * Family 0x11 125 */ 126 #define A_SKTS_3 3 127 { 128 X86_SOCKET_UNKNOWN, /* 0b000 */ 129 X86_SOCKET_UNKNOWN, /* 0b001 */ 130 X86_SOCKET_S1g2, /* 0b010 */ 131 X86_SOCKET_UNKNOWN, /* 0b011 */ 132 X86_SOCKET_UNKNOWN, /* 0b100 */ 133 X86_SOCKET_UNKNOWN, /* 0b101 */ 134 X86_SOCKET_UNKNOWN, /* 0b110 */ 135 X86_SOCKET_UNKNOWN /* 0b111 */ 136 }, 137 138 /* 139 * Family 0x12 140 */ 141 #define A_SKTS_4 4 142 { 143 X86_SOCKET_UNKNOWN, /* 0b000 */ 144 X86_SOCKET_FS1, /* 0b001 */ 145 X86_SOCKET_FM1, /* 0b010 */ 146 X86_SOCKET_UNKNOWN, /* 0b011 */ 147 X86_SOCKET_UNKNOWN, /* 0b100 */ 148 X86_SOCKET_UNKNOWN, /* 0b101 */ 149 X86_SOCKET_UNKNOWN, /* 0b110 */ 150 X86_SOCKET_UNKNOWN /* 0b111 */ 151 }, 152 153 /* 154 * Family 0x14 155 */ 156 #define A_SKTS_5 5 157 { 158 X86_SOCKET_FT1, /* 0b000 */ 159 X86_SOCKET_UNKNOWN, /* 0b001 */ 160 X86_SOCKET_UNKNOWN, /* 0b010 */ 161 X86_SOCKET_UNKNOWN, /* 0b011 */ 162 X86_SOCKET_UNKNOWN, /* 0b100 */ 163 X86_SOCKET_UNKNOWN, /* 0b101 */ 164 X86_SOCKET_UNKNOWN, /* 0b110 */ 165 X86_SOCKET_UNKNOWN /* 0b111 */ 166 }, 167 168 /* 169 * Family 0x15 models 00 - 0f 170 */ 171 #define A_SKTS_6 6 172 { 173 X86_SOCKET_UNKNOWN, /* 0b000 */ 174 X86_SOCKET_AM3R2, /* 0b001 */ 175 X86_SOCKET_UNKNOWN, /* 0b010 */ 176 X86_SOCKET_G34, /* 0b011 */ 177 X86_SOCKET_UNKNOWN, /* 0b100 */ 178 X86_SOCKET_C32, /* 0b101 */ 179 X86_SOCKET_UNKNOWN, /* 0b110 */ 180 X86_SOCKET_UNKNOWN /* 0b111 */ 181 }, 182 183 /* 184 * Family 0x15 models 10 - 1f 185 */ 186 #define A_SKTS_7 7 187 { 188 X86_SOCKET_FP2, /* 0b000 */ 189 X86_SOCKET_FS1R2, /* 0b001 */ 190 X86_SOCKET_FM2, /* 0b010 */ 191 X86_SOCKET_UNKNOWN, /* 0b011 */ 192 X86_SOCKET_UNKNOWN, /* 0b100 */ 193 X86_SOCKET_UNKNOWN, /* 0b101 */ 194 X86_SOCKET_UNKNOWN, /* 0b110 */ 195 X86_SOCKET_UNKNOWN /* 0b111 */ 196 }, 197 198 }; 199 200 struct amd_sktmap_s { 201 uint32_t skt_code; 202 char sktstr[16]; 203 }; 204 static struct amd_sktmap_s amd_sktmap[23] = { 205 { X86_SOCKET_754, "754" }, 206 { X86_SOCKET_939, "939" }, 207 { X86_SOCKET_940, "940" }, 208 { X86_SOCKET_S1g1, "S1g1" }, 209 { X86_SOCKET_AM2, "AM2" }, 210 { X86_SOCKET_F1207, "F(1207)" }, 211 { X86_SOCKET_S1g2, "S1g2" }, 212 { X86_SOCKET_S1g3, "S1g3" }, 213 { X86_SOCKET_AM, "AM" }, 214 { X86_SOCKET_AM2R2, "AM2r2" }, 215 { X86_SOCKET_AM3, "AM3" }, 216 { X86_SOCKET_G34, "G34" }, 217 { X86_SOCKET_ASB2, "ASB2" }, 218 { X86_SOCKET_C32, "C32" }, 219 { X86_SOCKET_FT1, "FT1" }, 220 { X86_SOCKET_FM1, "FM1" }, 221 { X86_SOCKET_FS1, "FS1" }, 222 { X86_SOCKET_AM3R2, "AM3r2" }, 223 { X86_SOCKET_FP2, "FP2" }, 224 { X86_SOCKET_FS1R2, "FS1r2" }, 225 { X86_SOCKET_FM2, "FM2" }, 226 { X86_SOCKET_UNKNOWN, "Unknown" } 227 }; 228 229 /* 230 * Table for mapping AMD Family 0xf and AMD Family 0x10 model/stepping 231 * combination to chip "revision" and socket type. 232 * 233 * The first member of this array that matches a given family, extended model 234 * plus model range, and stepping range will be considered a match. 235 */ 236 static const struct amd_rev_mapent { 237 uint_t rm_family; 238 uint_t rm_modello; 239 uint_t rm_modelhi; 240 uint_t rm_steplo; 241 uint_t rm_stephi; 242 uint32_t rm_chiprev; 243 const char *rm_chiprevstr; 244 int rm_sktidx; 245 } amd_revmap[] = { 246 /* 247 * =============== AuthenticAMD Family 0xf =============== 248 */ 249 250 /* 251 * Rev B includes model 0x4 stepping 0 and model 0x5 stepping 0 and 1. 252 */ 253 { 0xf, 0x04, 0x04, 0x0, 0x0, X86_CHIPREV_AMD_F_REV_B, "B", A_SKTS_0 }, 254 { 0xf, 0x05, 0x05, 0x0, 0x1, X86_CHIPREV_AMD_F_REV_B, "B", A_SKTS_0 }, 255 /* 256 * Rev C0 includes model 0x4 stepping 8 and model 0x5 stepping 8 257 */ 258 { 0xf, 0x04, 0x05, 0x8, 0x8, X86_CHIPREV_AMD_F_REV_C0, "C0", A_SKTS_0 }, 259 /* 260 * Rev CG is the rest of extended model 0x0 - i.e., everything 261 * but the rev B and C0 combinations covered above. 262 */ 263 { 0xf, 0x00, 0x0f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_CG, "CG", A_SKTS_0 }, 264 /* 265 * Rev D has extended model 0x1. 266 */ 267 { 0xf, 0x10, 0x1f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_D, "D", A_SKTS_0 }, 268 /* 269 * Rev E has extended model 0x2. 270 * Extended model 0x3 is unused but available to grow into. 271 */ 272 { 0xf, 0x20, 0x3f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_E, "E", A_SKTS_0 }, 273 /* 274 * Rev F has extended models 0x4 and 0x5. 275 */ 276 { 0xf, 0x40, 0x5f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_F, "F", A_SKTS_1 }, 277 /* 278 * Rev G has extended model 0x6. 279 */ 280 { 0xf, 0x60, 0x6f, 0x0, 0xf, X86_CHIPREV_AMD_F_REV_G, "G", A_SKTS_1 }, 281 282 /* 283 * =============== AuthenticAMD Family 0x10 =============== 284 */ 285 286 /* 287 * Rev A has model 0 and stepping 0/1/2 for DR-{A0,A1,A2}. 288 * Give all of model 0 stepping range to rev A. 289 */ 290 { 0x10, 0x00, 0x00, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_A, "A", A_SKTS_2 }, 291 292 /* 293 * Rev B has model 2 and steppings 0/1/0xa/2 for DR-{B0,B1,BA,B2}. 294 * Give all of model 2 stepping range to rev B. 295 */ 296 { 0x10, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_B, "B", A_SKTS_2 }, 297 298 /* 299 * Rev C has models 4-6 (depending on L3 cache configuration) 300 * Give all of models 4-6 stepping range 0-2 to rev C2. 301 */ 302 { 0x10, 0x4, 0x6, 0x0, 0x2, X86_CHIPREV_AMD_10_REV_C2, "C2", A_SKTS_2 }, 303 304 /* 305 * Rev C has models 4-6 (depending on L3 cache configuration) 306 * Give all of models 4-6 stepping range >= 3 to rev C3. 307 */ 308 { 0x10, 0x4, 0x6, 0x3, 0xf, X86_CHIPREV_AMD_10_REV_C3, "C3", A_SKTS_2 }, 309 310 /* 311 * Rev D has models 8 and 9 312 * Give all of model 8 and 9 stepping 0 to rev D0. 313 */ 314 { 0x10, 0x8, 0x9, 0x0, 0x0, X86_CHIPREV_AMD_10_REV_D0, "D0", A_SKTS_2 }, 315 316 /* 317 * Rev D has models 8 and 9 318 * Give all of model 8 and 9 stepping range >= 1 to rev D1. 319 */ 320 { 0x10, 0x8, 0x9, 0x1, 0xf, X86_CHIPREV_AMD_10_REV_D1, "D1", A_SKTS_2 }, 321 322 /* 323 * Rev E has models A and stepping 0 324 * Give all of model A stepping range to rev E. 325 */ 326 { 0x10, 0xA, 0xA, 0x0, 0xf, X86_CHIPREV_AMD_10_REV_E, "E", A_SKTS_2 }, 327 328 /* 329 * =============== AuthenticAMD Family 0x11 =============== 330 */ 331 { 0x11, 0x03, 0x03, 0x0, 0xf, X86_CHIPREV_AMD_11_REV_B, "B", A_SKTS_3 }, 332 333 /* 334 * =============== AuthenticAMD Family 0x12 =============== 335 */ 336 { 0x12, 0x01, 0x01, 0x0, 0xf, X86_CHIPREV_AMD_12_REV_B, "B", A_SKTS_4 }, 337 338 /* 339 * =============== AuthenticAMD Family 0x14 =============== 340 */ 341 { 0x14, 0x01, 0x01, 0x0, 0xf, X86_CHIPREV_AMD_14_REV_B, "B", A_SKTS_5 }, 342 { 0x14, 0x02, 0x02, 0x0, 0xf, X86_CHIPREV_AMD_14_REV_C, "C", A_SKTS_5 }, 343 344 /* 345 * =============== AuthenticAMD Family 0x15 =============== 346 */ 347 { 0x15, 0x01, 0x01, 0x2, 0x2, X86_CHIPREV_AMD_15OR_REV_B2, "B2", 348 A_SKTS_6 }, 349 { 0x15, 0x10, 0x10, 0x1, 0x1, X86_CHIPREV_AMD_15TN_REV_A1, "A1", 350 A_SKTS_7 }, 351 }; 352 353 static void 354 synth_amd_info(uint_t family, uint_t model, uint_t step, 355 uint32_t *skt_p, uint32_t *chiprev_p, const char **chiprevstr_p) 356 { 357 const struct amd_rev_mapent *rmp; 358 int found = 0; 359 int i; 360 361 if (family < 0xf) 362 return; 363 364 for (i = 0, rmp = amd_revmap; i < sizeof (amd_revmap) / sizeof (*rmp); 365 i++, rmp++) { 366 if (family == rmp->rm_family && 367 model >= rmp->rm_modello && model <= rmp->rm_modelhi && 368 step >= rmp->rm_steplo && step <= rmp->rm_stephi) { 369 found = 1; 370 break; 371 } 372 } 373 374 if (!found) 375 return; 376 377 if (chiprev_p != NULL) 378 *chiprev_p = rmp->rm_chiprev; 379 if (chiprevstr_p != NULL) 380 *chiprevstr_p = rmp->rm_chiprevstr; 381 382 if (skt_p != NULL) { 383 int platform; 384 385 #ifdef __xpv 386 /* PV guest */ 387 if (!is_controldom()) { 388 *skt_p = X86_SOCKET_UNKNOWN; 389 return; 390 } 391 #endif 392 platform = get_hwenv(); 393 394 if ((platform == HW_XEN_HVM) || (platform == HW_VMWARE)) { 395 *skt_p = X86_SOCKET_UNKNOWN; 396 } else if (family == 0xf) { 397 *skt_p = amd_skts[rmp->rm_sktidx][model & 0x3]; 398 } else { 399 /* 400 * Starting with family 10h, socket type is stored in 401 * CPUID Fn8000_0001_EBX 402 */ 403 struct cpuid_regs cp; 404 int idx; 405 406 cp.cp_eax = 0x80000001; 407 (void) __cpuid_insn(&cp); 408 409 /* PkgType bits */ 410 idx = BITX(cp.cp_ebx, 31, 28); 411 412 if (idx > 7) { 413 /* Reserved bits */ 414 *skt_p = X86_SOCKET_UNKNOWN; 415 } else { 416 *skt_p = amd_skts[rmp->rm_sktidx][idx]; 417 } 418 if (family == 0x10) { 419 /* 420 * Look at Ddr3Mode bit of DRAM Configuration 421 * High Register to decide whether this is 422 * actually AM3 or S1g4. 423 */ 424 uint32_t val; 425 426 val = pci_getl_func(0, 24, 2, 0x94); 427 if (BITX(val, 8, 8)) { 428 if (*skt_p == X86_SOCKET_AM2R2) 429 *skt_p = X86_SOCKET_AM3; 430 else if (*skt_p == X86_SOCKET_S1g3) 431 *skt_p = X86_SOCKET_S1g4; 432 } 433 } 434 } 435 } 436 } 437 438 uint32_t 439 _cpuid_skt(uint_t vendor, uint_t family, uint_t model, uint_t step) 440 { 441 uint32_t skt = X86_SOCKET_UNKNOWN; 442 443 switch (vendor) { 444 case X86_VENDOR_AMD: 445 synth_amd_info(family, model, step, &skt, NULL, NULL); 446 break; 447 448 default: 449 break; 450 451 } 452 453 return (skt); 454 } 455 456 const char * 457 _cpuid_sktstr(uint_t vendor, uint_t family, uint_t model, uint_t step) 458 { 459 const char *sktstr = "Unknown"; 460 struct amd_sktmap_s *sktmapp; 461 uint32_t skt = X86_SOCKET_UNKNOWN; 462 463 switch (vendor) { 464 case X86_VENDOR_AMD: 465 synth_amd_info(family, model, step, &skt, NULL, NULL); 466 467 sktmapp = amd_sktmap; 468 while (sktmapp->skt_code != X86_SOCKET_UNKNOWN) { 469 if (sktmapp->skt_code == skt) 470 break; 471 sktmapp++; 472 } 473 sktstr = sktmapp->sktstr; 474 break; 475 476 default: 477 break; 478 479 } 480 481 return (sktstr); 482 } 483 484 uint32_t 485 _cpuid_chiprev(uint_t vendor, uint_t family, uint_t model, uint_t step) 486 { 487 uint32_t chiprev = X86_CHIPREV_UNKNOWN; 488 489 switch (vendor) { 490 case X86_VENDOR_AMD: 491 synth_amd_info(family, model, step, NULL, &chiprev, NULL); 492 break; 493 494 default: 495 break; 496 497 } 498 499 return (chiprev); 500 } 501 502 const char * 503 _cpuid_chiprevstr(uint_t vendor, uint_t family, uint_t model, uint_t step) 504 { 505 const char *revstr = "Unknown"; 506 507 switch (vendor) { 508 case X86_VENDOR_AMD: 509 synth_amd_info(family, model, step, NULL, NULL, &revstr); 510 break; 511 512 default: 513 break; 514 515 } 516 517 return (revstr); 518 519 } 520 521 /* 522 * CyrixInstead is a variable used by the Cyrix detection code 523 * in locore. 524 */ 525 const char CyrixInstead[] = X86_VENDORSTR_CYRIX; 526 527 /* 528 * Map the vendor string to a type code 529 */ 530 uint_t 531 _cpuid_vendorstr_to_vendorcode(char *vendorstr) 532 { 533 if (strcmp(vendorstr, X86_VENDORSTR_Intel) == 0) 534 return (X86_VENDOR_Intel); 535 else if (strcmp(vendorstr, X86_VENDORSTR_AMD) == 0) 536 return (X86_VENDOR_AMD); 537 else if (strcmp(vendorstr, X86_VENDORSTR_TM) == 0) 538 return (X86_VENDOR_TM); 539 else if (strcmp(vendorstr, CyrixInstead) == 0) 540 return (X86_VENDOR_Cyrix); 541 else if (strcmp(vendorstr, X86_VENDORSTR_UMC) == 0) 542 return (X86_VENDOR_UMC); 543 else if (strcmp(vendorstr, X86_VENDORSTR_NexGen) == 0) 544 return (X86_VENDOR_NexGen); 545 else if (strcmp(vendorstr, X86_VENDORSTR_Centaur) == 0) 546 return (X86_VENDOR_Centaur); 547 else if (strcmp(vendorstr, X86_VENDORSTR_Rise) == 0) 548 return (X86_VENDOR_Rise); 549 else if (strcmp(vendorstr, X86_VENDORSTR_SiS) == 0) 550 return (X86_VENDOR_SiS); 551 else if (strcmp(vendorstr, X86_VENDORSTR_NSC) == 0) 552 return (X86_VENDOR_NSC); 553 else 554 return (X86_VENDOR_IntelClone); 555 }