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