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 } 441