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 }