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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <unistd.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <stdarg.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <limits.h> 34 #include <alloca.h> 35 #include <kstat.h> 36 #include <errno.h> 37 #include <libnvpair.h> 38 #include <sys/types.h> 39 #include <sys/bitmap.h> 40 #include <sys/processor.h> 41 #include <sys/param.h> 42 #include <sys/fm/protocol.h> 43 #include <sys/systeminfo.h> 44 #include <sys/mc.h> 45 #include <sys/mc_amd.h> 46 #include <sys/mc_intel.h> 47 #include <fm/topo_mod.h> 48 49 #include "chip.h" 50 51 #define MAX_DIMMNUM 7 52 #define MAX_CSNUM 7 53 54 /* 55 * Enumerates the processing chips, or sockets, (as distinct from cores) in a 56 * system. For each chip found, the necessary nodes (one or more cores, and 57 * possibly a memory controller) are constructed underneath. 58 */ 59 60 static int chip_enum(topo_mod_t *, tnode_t *, const char *, 61 topo_instance_t, topo_instance_t, void *, void *); 62 63 static const topo_modops_t chip_ops = 64 { chip_enum, NULL}; 65 static const topo_modinfo_t chip_info = 66 { CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops }; 67 68 static const topo_pgroup_info_t chip_pgroup = 69 { PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 70 static const topo_pgroup_info_t cpu_pgroup = 71 { PGNAME(CPU), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 72 static const topo_pgroup_info_t cpu_core_pgroup = 73 { PGNAME(CPU_CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 74 static const topo_pgroup_info_t cpu_strand_pgroup = 75 { PGNAME(CPU_STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 76 1 }; 77 78 static const topo_method_t chip_methods[] = { 79 { SIMPLE_CHIP_LBL, "Property method", 0, 80 TOPO_STABILITY_INTERNAL, simple_chip_label}, 81 { G4_CHIP_LBL, "Property method", 0, 82 TOPO_STABILITY_INTERNAL, g4_chip_label}, 83 { A4FPLUS_CHIP_LBL, "Property method", 0, 84 TOPO_STABILITY_INTERNAL, a4fplus_chip_label}, 85 { NULL } 86 }; 87 88 int 89 _topo_init(topo_mod_t *mod) 90 { 91 chip_t *chip; 92 93 if (getenv("TOPOCHIPDBG")) 94 topo_mod_setdebug(mod); 95 topo_mod_dprintf(mod, "initializing chip enumerator\n"); 96 97 if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) 98 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 99 100 if ((chip->chip_kc = kstat_open()) == NULL) { 101 whinge(mod, NULL, "kstat_open failed: %s\n", 102 strerror(errno)); 103 topo_mod_free(mod, chip, sizeof (chip_t)); 104 return (topo_mod_seterrno(mod, errno)); 105 } 106 107 chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); 108 if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( 109 chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { 110 (void) kstat_close(chip->chip_kc); 111 topo_mod_free(mod, chip, sizeof (chip_t)); 112 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 113 } 114 115 if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) { 116 whinge(mod, NULL, "failed to register hc: " 117 "%s\n", topo_mod_errmsg(mod)); 118 topo_mod_free(mod, chip->chip_cpustats, 119 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 120 (void) kstat_close(chip->chip_kc); 121 topo_mod_free(mod, chip, sizeof (chip_t)); 122 return (-1); /* mod errno set */ 123 } 124 topo_mod_setspecific(mod, (void *)chip); 125 126 return (0); 127 } 128 129 void 130 _topo_fini(topo_mod_t *mod) 131 { 132 chip_t *chip = topo_mod_getspecific(mod); 133 134 if (chip->chip_cpustats != NULL) 135 topo_mod_free(mod, chip->chip_cpustats, 136 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 137 138 (void) kstat_close(chip->chip_kc); 139 topo_mod_free(mod, chip, sizeof (chip_t)); 140 141 topo_mod_unregister(mod); 142 } 143 144 static int 145 cpu_strand_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 146 int coreid, chip_t *chip, int nstrand, nvlist_t *auth) 147 { 148 kstat_named_t *k; 149 nvlist_t *fmri, *asru; 150 tnode_t *cnode; 151 int err, nerr = 0; 152 int cpuid, clogid, tcoreid, strandid; 153 154 if (topo_node_range_create(mod, pnode, name, 0, 155 nstrand) < 0) 156 return (-1); 157 158 for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) { 159 if (chip->chip_cpustats[cpuid] == NULL) 160 continue; 161 162 /* 163 * The chip_id in the cpu_info kstat numbers the individual 164 * chips from 0 to #chips - 1. 165 */ 166 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 167 "chip_id")) == NULL) { 168 whinge(mod, &nerr, 169 "cpu_strand_create: chip_id lookup via " 170 "kstats failed\n"); 171 continue; 172 } 173 174 if (k->value.l != chipid) 175 continue; /* not an error */ 176 177 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 178 "clog_id")) == NULL) { 179 whinge(mod, &nerr, 180 "cpu_strand_create: clog_id lookup via " 181 "kstats failed\n"); 182 continue; 183 } 184 clogid = k->value.l; 185 tcoreid = clogid / nstrand; 186 187 if (coreid != tcoreid) 188 continue; 189 190 strandid = clogid % nstrand; 191 192 if (mkrsrc(mod, pnode, name, strandid, auth, &fmri) != 0) { 193 whinge(mod, &nerr, 194 "cpu_strand_create: mkrsrc failed\n"); 195 continue; 196 } 197 198 if ((cnode = topo_node_bind(mod, pnode, name, strandid, fmri)) 199 == NULL) { 200 whinge(mod, &nerr, 201 "cpu_strand_create: node bind failed\n"); 202 nvlist_free(fmri); 203 continue; 204 } 205 nvlist_free(fmri); 206 207 if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) { 208 (void) topo_node_asru_set(cnode, asru, 0, &err); 209 nvlist_free(asru); 210 } else { 211 whinge(mod, &nerr, "cpu_strand_create: cpu_fmri_create " 212 "failed\n"); 213 } 214 (void) topo_node_fru_set(cnode, NULL, 0, &err); 215 216 (void) topo_pgroup_create(cnode, &cpu_strand_pgroup, &err); 217 218 (void) topo_prop_set_uint32(cnode, PGNAME(CPU_STRAND), "cpuid", 219 TOPO_PROP_IMMUTABLE, cpuid, &err); 220 221 if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid], 222 PGNAME(CPU_STRAND), NULL, CPU_CHIP_ID, CPU_CORE_ID, 223 CPU_CLOG_ID, CPU_PKG_CORE_ID, NULL) != 0) 224 nerr++; /* have whinged elsewhere */ 225 } 226 227 return (nerr == 0 ? 0 : -1); 228 } 229 230 static int 231 cpu_core_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 232 chip_t *chip, int ncore, int ncpu, nvlist_t *auth) 233 { 234 kstat_named_t *k; 235 nvlist_t *fmri; 236 tnode_t *cnode; 237 int clogid, cpuid, coreid; 238 int nstrand; 239 int err, nerr = 0; 240 241 if (topo_node_range_create(mod, pnode, name, 0, 242 ncore) < 0) 243 return (-1); 244 245 nstrand = ncpu / ncore; 246 for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) { 247 if (chip->chip_cpustats[cpuid] == NULL) 248 continue; 249 250 /* 251 * The chip_id in the cpu_info kstat numbers the individual 252 * chips from 0 to #chips - 1. 253 */ 254 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 255 "chip_id")) == NULL) { 256 whinge(mod, &nerr, 257 "cpu_core_create: chip_id lookup via " 258 "kstats failed\n"); 259 continue; 260 } 261 262 if (k->value.l != chipid) 263 continue; /* not an error */ 264 265 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 266 "clog_id")) == NULL) { 267 whinge(mod, &nerr, 268 "cpu_core_create: clog_id lookup via " 269 "kstats failed\n"); 270 continue; 271 } 272 clogid = k->value.l; 273 coreid = clogid / nstrand; 274 275 if (mkrsrc(mod, pnode, name, coreid, auth, &fmri) != 0) { 276 whinge(mod, &nerr, "cpu_core_create: mkrsrc failed\n"); 277 continue; 278 } 279 280 if ((cnode = topo_node_bind(mod, pnode, name, coreid, fmri)) 281 == NULL) { 282 whinge(mod, &nerr, 283 "cpu_core_create: node bind failed\n"); 284 nvlist_free(fmri); 285 continue; 286 } 287 nvlist_free(fmri); 288 289 (void) topo_node_fru_set(cnode, NULL, 0, &err); 290 291 (void) topo_pgroup_create(cnode, &cpu_core_pgroup, &err); 292 293 if (cpu_strand_create(mod, cnode, CPU_STRAND_NODE_NAME, chipid, 294 coreid, chip, nstrand, auth) != 0) 295 nerr++; /* have whinged elsewhere */ 296 } 297 298 return (nerr == 0 ? 0 : -1); 299 } 300 301 static int 302 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 303 chip_t *chip, nvlist_t *auth) 304 { 305 kstat_named_t *k; 306 nvlist_t *fmri, *asru; 307 tnode_t *cnode; 308 int err, nerr = 0; 309 int clogid, cpuid; 310 311 if (topo_node_range_create(mod, pnode, name, 0, 312 chip->chip_ncpustats) < 0) 313 return (-1); 314 315 for (cpuid = 0; cpuid <= chip->chip_ncpustats; cpuid++) { 316 if (chip->chip_cpustats[cpuid] == NULL) 317 continue; 318 319 /* 320 * The chip_id in the cpu_info kstat numbers the individual 321 * chips from 0 to #chips - 1. 322 */ 323 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 324 "chip_id")) == NULL) { 325 whinge(mod, &nerr, "cpu_create: chip_id lookup via " 326 "kstats failed\n"); 327 continue; 328 } 329 330 if (k->value.l != chipid) 331 continue; /* not an error */ 332 333 /* 334 * The clog_id in the cpu_info kstat numbers the virtual 335 * processors of a single chip; these may be separate 336 * processor cores, or they may be hardware threads/strands 337 * of individual cores. 338 * 339 * The core_id in the cpu_info kstat tells us which cpus 340 * share the same core - i.e., are hardware strands of the 341 * same core. The core ids do not reset to zero for each 342 * distinct chip - they number across all cores of all chips. 343 * This enumerator does not distinguish stranded 344 * cores so core_id is unused. 345 */ 346 if ((k = kstat_data_lookup(chip->chip_cpustats[cpuid], 347 "clog_id")) == NULL) { 348 whinge(mod, &nerr, "cpu_create: clog_id lookup via " 349 "kstats failed\n"); 350 continue; 351 } 352 clogid = k->value.l; 353 354 if (mkrsrc(mod, pnode, name, clogid, auth, &fmri) != 0) { 355 whinge(mod, &nerr, "cpu_create: mkrsrc failed\n"); 356 continue; 357 } 358 359 if ((cnode = topo_node_bind(mod, pnode, name, clogid, fmri)) 360 == NULL) { 361 whinge(mod, &nerr, "cpu_create: node bind failed\n"); 362 nvlist_free(fmri); 363 continue; 364 } 365 nvlist_free(fmri); 366 367 if ((asru = cpu_fmri_create(mod, cpuid, NULL, 0)) != NULL) { 368 (void) topo_node_asru_set(cnode, asru, 0, &err); 369 nvlist_free(asru); 370 } else { 371 whinge(mod, &nerr, "cpu_create: cpu_fmri_create " 372 "failed\n"); 373 } 374 (void) topo_node_fru_set(cnode, NULL, 0, &err); 375 376 (void) topo_pgroup_create(cnode, &cpu_pgroup, &err); 377 378 (void) topo_prop_set_uint32(cnode, PGNAME(CPU), "cpuid", 379 TOPO_PROP_IMMUTABLE, cpuid, &err); 380 381 if (add_kstat_longprops(mod, cnode, chip->chip_cpustats[cpuid], 382 PGNAME(CPU), NULL, CPU_CHIP_ID, CPU_CORE_ID, CPU_CLOG_ID, 383 CPU_PKG_CORE_ID, NULL) != 0) 384 nerr++; /* have whinged elsewhere */ 385 } 386 387 return (nerr == 0 ? 0 : -1); 388 } 389 390 static int 391 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 392 topo_instance_t min, topo_instance_t max, chip_t *chip, nvlist_t *auth, 393 int mc_offchip) 394 { 395 int i, nerr = 0; 396 kstat_t *ksp; 397 ulong_t *chipmap; 398 tnode_t *cnode; 399 nvlist_t *fmri; 400 int ncore, ncpu; 401 402 if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(max) * 403 sizeof (ulong_t))) == NULL) 404 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 405 406 /* 407 * Read in all cpu_info kstats, for all chip ids. The ks_instance 408 * argument to kstat_lookup is the logical cpu_id - we will use this 409 * in cpu_create. 410 */ 411 for (i = 0; i <= chip->chip_ncpustats; i++) { 412 if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == 413 NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) 414 continue; 415 416 chip->chip_cpustats[i] = ksp; 417 } 418 419 for (i = 0; i <= chip->chip_ncpustats; i++) { 420 const char *vendor; 421 int32_t fms[3]; 422 kstat_named_t *k; 423 int err, chipid; 424 425 if ((ksp = chip->chip_cpustats[i]) == NULL) 426 continue; 427 428 if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) { 429 whinge(mod, &nerr, "chip_create: chip_id lookup " 430 "via kstats failed\n"); 431 continue; 432 } 433 434 chipid = k->value.l; 435 if (BT_TEST(chipmap, chipid)) 436 continue; 437 438 if (chipid < min || chipid > max) 439 continue; 440 441 if (mkrsrc(mod, pnode, name, chipid, auth, &fmri) != 0) { 442 whinge(mod, &nerr, "chip_create: mkrsrc failed\n"); 443 continue; 444 } 445 446 if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri)) 447 == NULL) { 448 nvlist_free(fmri); 449 whinge(mod, &nerr, "chip_create: node bind " 450 "failed for chipid %d\n", chipid); 451 continue; 452 } 453 BT_SET(chipmap, chipid); 454 455 if (topo_method_register(mod, cnode, chip_methods) < 0) 456 whinge(mod, &nerr, "chip_create: " 457 "topo_method_register failed"); 458 459 (void) topo_node_fru_set(cnode, fmri, 0, &err); 460 461 nvlist_free(fmri); 462 463 (void) topo_pgroup_create(cnode, &chip_pgroup, &err); 464 if (add_kstat_strprop(mod, cnode, ksp, PGNAME(CHIP), 465 CHIP_VENDOR_ID, &vendor) != 0) 466 nerr++; /* have whinged elsewhere */ 467 468 if (add_kstat_longprops(mod, cnode, ksp, PGNAME(CHIP), 469 fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL) != 0) 470 nerr++; /* have whinged elsewhere */ 471 472 if ((k = kstat_data_lookup(ksp, "ncore_per_chip")) == NULL) { 473 whinge(mod, &nerr, "chip_create: ncore_per_chip lookup " 474 "via kstats failed\n"); 475 ncore = 0; 476 ncpu = 0; 477 } else { 478 ncore = k->value.l; 479 480 if ((k = kstat_data_lookup(ksp, 481 "ncpu_per_chip")) == NULL) { 482 whinge(mod, &nerr, 483 "chip_create: ncpu_per_chip lookup " 484 "via kstats failed\n"); 485 ncore = 0; 486 ncpu = 0; 487 } else { 488 ncpu = k->value.l; 489 } 490 } 491 492 if (ncore < ncpu) { 493 if (cpu_core_create(mod, cnode, CPU_CORE_NODE_NAME, 494 chipid, chip, ncore, ncpu, auth) != 0) 495 nerr++; /* have whinged elsewhere */ 496 } else if (cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip, 497 auth) != 0) 498 nerr++; /* have whinged elsewhere */ 499 500 /* 501 * Create memory-controller node under a chip for architectures 502 * that may have on-chip memory-controller(s). 503 */ 504 if (strcmp(vendor, "AuthenticAMD") == 0) 505 amd_mc_create(mod, cnode, MCT_NODE_NAME, auth, 506 fms[0], fms[1], fms[2], &nerr); 507 else if (!mc_offchip) 508 onchip_mc_create(mod, cnode, MCT_NODE_NAME, auth); 509 } 510 511 topo_mod_free(mod, chipmap, BT_BITOUL(max) * sizeof (ulong_t)); 512 513 if (nerr == 0) { 514 return (0); 515 } else { 516 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 517 return (-1); 518 } 519 } 520 521 /*ARGSUSED*/ 522 static int 523 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 524 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 525 { 526 int rv = 0; 527 chip_t *chip = (chip_t *)arg; 528 nvlist_t *auth = NULL; 529 int offchip_mc; 530 531 auth = topo_mod_auth(mod, pnode); 532 533 offchip_mc = mc_offchip_open(); 534 if (strcmp(name, CHIP_NODE_NAME) == 0) 535 rv = chip_create(mod, pnode, name, min, max, chip, auth, 536 offchip_mc); 537 538 if (offchip_mc) 539 (void) mc_offchip_create(mod, pnode, "memory-controller", auth); 540 541 nvlist_free(auth); 542 543 return (rv); 544 } 545