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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <limits.h> 35 #include <alloca.h> 36 #include <kstat.h> 37 #include <fcntl.h> 38 #include <errno.h> 39 #include <libnvpair.h> 40 #include <sys/types.h> 41 #include <sys/bitmap.h> 42 #include <sys/processor.h> 43 #include <sys/param.h> 44 #include <sys/fm/protocol.h> 45 #include <sys/systeminfo.h> 46 #include <sys/mc.h> 47 #include <fm/topo_mod.h> 48 49 #include "chip.h" 50 51 #ifndef MAX 52 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 53 #endif 54 55 /* 56 * Enumerates the processing chips, or sockets, (as distinct from cores) in a 57 * system. For each chip found, the necessary nodes (one or more cores, and 58 * possibly a memory controller) are constructed underneath. 59 */ 60 61 static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 62 topo_instance_t, void *); 63 64 const topo_modinfo_t chip_info = 65 { "chip", CHIP_VERSION, chip_enum, NULL}; 66 67 int 68 _topo_init(topo_mod_t *mod) 69 { 70 chip_t *chip; 71 72 topo_mod_setdebug(mod, TOPO_DBG_ALL); 73 topo_mod_dprintf(mod, "initializing chip enumerator\n"); 74 75 if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) 76 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 77 78 if ((chip->chip_kc = kstat_open()) == NULL) { 79 topo_mod_dprintf(mod, "kstat_open failed: %s\n", 80 strerror(errno)); 81 topo_mod_free(mod, chip, sizeof (chip_t)); 82 return (topo_mod_seterrno(mod, errno)); 83 } 84 85 chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); 86 if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( 87 chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { 88 (void) kstat_close(chip->chip_kc); 89 topo_mod_free(mod, chip, sizeof (chip_t)); 90 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 91 } 92 93 if (topo_mod_register(mod, &chip_info, (void *)chip) != 0) { 94 topo_mod_dprintf(mod, "failed to register hc: " 95 "%s\n", topo_mod_errmsg(mod)); 96 topo_mod_free(mod, chip->chip_cpustats, 97 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 98 (void) kstat_close(chip->chip_kc); 99 topo_mod_free(mod, chip, sizeof (chip_t)); 100 return (-1); /* mod errno set */ 101 } 102 103 return (0); 104 } 105 106 void 107 _topo_fini(topo_mod_t *mod) 108 { 109 chip_t *chip = topo_mod_private(mod); 110 111 if (chip->chip_cpustats != NULL) 112 topo_mod_free(mod, chip->chip_cpustats, 113 (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); 114 115 (void) kstat_close(chip->chip_kc); 116 topo_mod_free(mod, chip, sizeof (chip_t)); 117 118 topo_mod_unregister(mod); 119 } 120 121 static int 122 chip_strprop(tnode_t *cnode, kstat_t *ksp, const char *name) 123 { 124 int err; 125 kstat_named_t *k; 126 127 if ((k = kstat_data_lookup(ksp, (char *)name)) == NULL) 128 return (0); 129 130 (void) topo_prop_set_string(cnode, CHIP_PGROUP, name, 131 TOPO_PROP_SET_ONCE, k->value.str.addr.ptr, &err); 132 133 return (-1); 134 } 135 136 static int 137 chip_longprop(tnode_t *cnode, kstat_t *ksp, const char *name) 138 { 139 int err; 140 kstat_named_t *k; 141 142 if ((k = kstat_data_lookup(ksp, (char *)name)) == NULL) 143 return (0); 144 145 (void) topo_prop_set_int32(cnode, CHIP_PGROUP, name, TOPO_PROP_SET_ONCE, 146 k->value.l, &err); 147 148 return (-1); 149 } 150 151 static nvlist_t * 152 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask) 153 { 154 int err; 155 nvlist_t *asru; 156 157 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) 158 return (NULL); 159 160 err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION); 161 err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); 162 err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid); 163 err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask); 164 if (s != NULL) 165 err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s); 166 if (err != 0) { 167 nvlist_free(asru); 168 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 169 return (NULL); 170 } 171 172 return (asru); 173 } 174 175 static int 176 cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, 177 chip_t *chip) 178 { 179 kstat_named_t *k; 180 topo_hdl_t *thp; 181 nvlist_t *fmri, *pfmri, *asru, *args; 182 tnode_t *cnode; 183 int i, err, nerr = 0; 184 185 if (topo_node_range_create(mod, pnode, name, 0, 186 chip->chip_ncpustats) < 0) 187 return (-1); 188 189 thp = topo_mod_handle(mod); 190 191 for (i = 0; i <= chip->chip_ncpustats; i++) { 192 193 if (chip->chip_cpustats[i] == NULL) 194 continue; 195 196 if ((k = kstat_data_lookup(chip->chip_cpustats[i], "chip_id")) 197 == NULL || k->value.l != chipid) { 198 ++nerr; 199 continue; 200 } 201 202 if ((k = kstat_data_lookup(chip->chip_cpustats[i], "clog_id")) 203 == NULL) { 204 ++nerr; 205 continue; 206 } 207 208 args = pfmri = NULL; 209 if (topo_node_resource(pnode, &pfmri, &err) < 0 || 210 topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 211 nvlist_add_nvlist(args, 212 TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 213 nvlist_free(pfmri); 214 nvlist_free(args); 215 ++nerr; 216 continue; 217 } 218 219 fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 220 (topo_instance_t)k->value.l, args, &err); 221 nvlist_free(pfmri); 222 nvlist_free(args); 223 if (fmri == NULL) { 224 ++nerr; 225 continue; 226 } 227 228 if ((cnode = topo_node_bind(mod, pnode, name, i, fmri, 229 NULL)) == NULL) { 230 ++nerr; 231 nvlist_free(fmri); 232 continue; 233 } 234 nvlist_free(fmri); 235 236 if ((asru = cpu_fmri_create(mod, i, NULL, 0)) != NULL) { 237 (void) topo_node_asru_set(cnode, asru, 0, &err); 238 nvlist_free(asru); 239 } else { 240 ++nerr; 241 } 242 (void) topo_node_fru_set(cnode, NULL, 0, &err); 243 } 244 245 if (nerr != 0) 246 return (-1); 247 else 248 return (0); 249 } 250 251 static int 252 nvprop_add(nvpair_t *nvp, const char *pgname, tnode_t *node) 253 { 254 int err; 255 char *pname = nvpair_name(nvp); 256 257 switch (nvpair_type(nvp)) { 258 case DATA_TYPE_BOOLEAN_VALUE: { 259 boolean_t val; 260 261 if (nvpair_value_boolean_value(nvp, &val) == 0) { 262 (void) topo_prop_set_string(node, pgname, pname, 263 TOPO_PROP_SET_ONCE, (val ? "true" : "false"), &err); 264 } 265 return (0); 266 } 267 268 case DATA_TYPE_UINT64: { 269 uint64_t val; 270 271 if (nvpair_value_uint64(nvp, &val) == 0) { 272 (void) topo_prop_set_uint64(node, pgname, pname, 273 TOPO_PROP_SET_ONCE, val, &err); 274 } 275 return (0); 276 } 277 278 case DATA_TYPE_STRING: { 279 char *str; 280 281 if (nvpair_value_string(nvp, &str) == 0) 282 (void) topo_prop_set_string(node, pgname, pname, 283 TOPO_PROP_SET_ONCE, str, &err); 284 return (0); 285 } 286 287 default: 288 return (-1); 289 } 290 } 291 292 nvlist_t * 293 mem_fmri_create(topo_mod_t *mod) 294 { 295 nvlist_t *asru; 296 297 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) 298 return (NULL); 299 300 if (nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0 || 301 nvlist_add_uint8(asru, FM_VERSION, FM_MEM_SCHEME_VERSION) != 0) { 302 nvlist_free(asru); 303 return (NULL); 304 } 305 306 return (asru); 307 } 308 309 static int 310 cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc) 311 { 312 int i, err, nerr = 0; 313 nvpair_t *nvp; 314 tnode_t *csnode; 315 topo_hdl_t *thp; 316 nvlist_t *fmri, **csarr = NULL; 317 nvlist_t *pfmri, *args; 318 uint64_t csnum; 319 uint_t ncs; 320 321 if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0) 322 return (-1); 323 324 if (topo_node_range_create(mod, pnode, name, 0, ncs) < 0) 325 return (-1); 326 327 thp = topo_mod_handle(mod); 328 for (i = 0; i < ncs; i++) { 329 if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) { 330 ++nerr; 331 continue; 332 } 333 334 args = pfmri = NULL; 335 if (topo_node_resource(pnode, &pfmri, &err) < 0 || 336 topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 337 nvlist_add_nvlist(args, 338 TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 339 nvlist_free(pfmri); 340 nvlist_free(args); 341 ++nerr; 342 continue; 343 } 344 fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 345 csnum, args, &err); 346 nvlist_free(pfmri); 347 nvlist_free(args); 348 if (fmri == NULL) { 349 ++nerr; 350 continue; 351 } 352 353 if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri, 354 NULL)) == NULL) { 355 nvlist_free(fmri); 356 ++nerr; 357 continue; 358 } 359 360 nvlist_free(fmri); 361 362 (void) topo_pgroup_create(csnode, CS_PGROUP, 363 TOPO_STABILITY_PRIVATE, &err); 364 365 for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL; 366 nvp = nvlist_next_nvpair(csarr[i], nvp)) { 367 (void) nvprop_add(nvp, CS_PGROUP, csnode); 368 } 369 } 370 371 if (nerr != 0) 372 return (-1); 373 else 374 return (0); 375 } 376 377 static int 378 dimm_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc) 379 { 380 int i, err, nerr = 0; 381 nvpair_t *nvp; 382 tnode_t *dimmnode; 383 nvlist_t *fmri, *asru, **dimmarr = NULL; 384 nvlist_t *pfmri, *args; 385 uint64_t ldimmnum; 386 uint_t ndimm; 387 topo_hdl_t *thp; 388 389 thp = topo_mod_handle(mod); 390 391 if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) 392 return (-1); 393 394 if (topo_node_range_create(mod, pnode, name, 0, ndimm) < 0) 395 return (-1); 396 397 for (i = 0; i < ndimm; i++) { 398 if (nvlist_lookup_uint64(dimmarr[i], "num", &ldimmnum) != 0) { 399 ++nerr; 400 continue; 401 } 402 403 args = pfmri = NULL; 404 if (topo_node_resource(pnode, &pfmri, &err) < 0 || 405 topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 406 nvlist_add_nvlist(args, 407 TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 408 nvlist_free(pfmri); 409 nvlist_free(args); 410 ++nerr; 411 continue; 412 } 413 fmri = topo_fmri_create(thp, 414 FM_FMRI_SCHEME_HC, name, ldimmnum, args, &err); 415 nvlist_free(pfmri); 416 nvlist_free(args); 417 if (fmri == NULL) { 418 ++nerr; 419 continue; 420 } 421 422 if ((dimmnode = topo_node_bind(mod, pnode, name, ldimmnum, fmri, 423 NULL)) == NULL) { 424 nvlist_free(fmri); 425 ++nerr; 426 continue; 427 } 428 429 (void) topo_node_fru_set(dimmnode, fmri, 0, &err); 430 if ((asru = mem_fmri_create(mod)) != NULL) { 431 (void) topo_node_asru_set(dimmnode, asru, 432 TOPO_ASRU_COMPUTE, &err); 433 nvlist_free(asru); 434 } 435 436 nvlist_free(fmri); 437 438 (void) topo_pgroup_create(dimmnode, DIMM_PGROUP, 439 TOPO_STABILITY_PRIVATE, &err); 440 441 for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL; 442 nvp = nvlist_next_nvpair(dimmarr[i], nvp)) { 443 if (nvprop_add(nvp, DIMM_PGROUP, dimmnode) == 0) { 444 continue; 445 } else if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY) { 446 uint64_t *csnumarr; 447 uint_t ncs; 448 int i; 449 450 if (strcmp(nvpair_name(nvp), "csnums") != 0 || 451 nvpair_value_uint64_array(nvp, &csnumarr, 452 &ncs) != 0) 453 continue; 454 455 for (i = 0; i < ncs; i++) { 456 char name[7]; 457 (void) snprintf(name, sizeof (name), 458 "csnum%d", i); 459 (void) topo_prop_set_uint64(dimmnode, 460 DIMM_PGROUP, name, 461 TOPO_PROP_SET_ONCE, 462 csnumarr[i], &err); 463 } 464 } 465 } 466 } 467 468 if (nerr != 0) 469 return (-1); 470 else 471 return (0); 472 } 473 474 static nvlist_t * 475 mc_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) 476 { 477 mc_snapshot_info_t mcs; 478 void *buf = NULL; 479 480 nvlist_t *nvl; 481 char path[64]; 482 int fd, err; 483 484 (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 485 fd = open(path, O_RDONLY); 486 487 if (fd == -1) { 488 topo_mod_dprintf(mod, "mc failed to open %s: %s\n", 489 path, strerror(errno)); 490 return (NULL); 491 } 492 493 if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 494 (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 495 ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { 496 497 topo_mod_dprintf(mod, "mc failed to snapshot %s: %s\n", 498 path, strerror(errno)); 499 500 free(buf); 501 (void) close(fd); 502 return (NULL); 503 } 504 505 (void) close(fd); 506 err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 507 topo_mod_free(mod, buf, mcs.mcs_size); 508 return (err ? NULL : nvl); 509 } 510 511 static int 512 mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name) 513 { 514 int err, rc = 0; 515 tnode_t *mcnode; 516 nvlist_t *fmri; 517 nvpair_t *nvp; 518 nvlist_t *mc = NULL; 519 nvlist_t *pfmri, *args; 520 topo_hdl_t *thp; 521 522 thp = topo_mod_handle(mod); 523 args = pfmri = NULL; 524 if (topo_node_resource(pnode, &pfmri, &err) < 0 || 525 topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 526 nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 527 nvlist_free(pfmri); 528 nvlist_free(args); 529 return (-1); 530 } 531 fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 0, args, &err); 532 nvlist_free(pfmri); 533 nvlist_free(args); 534 if (fmri == NULL) 535 return (-1); 536 537 if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) { 538 nvlist_free(fmri); 539 return (-1); 540 } 541 542 /* 543 * Gather and create memory controller topology 544 */ 545 if ((mc = mc_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL || 546 (mcnode = topo_node_bind(mod, pnode, 547 name, 0, fmri, NULL)) == NULL) { 548 if (mc != NULL) 549 nvlist_free(mc); 550 topo_node_range_destroy(pnode, name); 551 nvlist_free(fmri); 552 return (-1); 553 } 554 555 (void) topo_node_fru_set(mcnode, NULL, 0, &err); 556 nvlist_free(fmri); 557 558 /* 559 * Add memory controller properties 560 */ 561 (void) topo_pgroup_create(mcnode, MC_PGROUP, 562 TOPO_STABILITY_PRIVATE, &err); 563 564 for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL; 565 nvp = nvlist_next_nvpair(mc, nvp)) { 566 if (nvprop_add(nvp, MC_PGROUP, mcnode) == 0) 567 continue; 568 else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) 569 break; 570 } 571 572 if (dimm_create(mod, mcnode, DIMM_NODE_NAME, mc) != 0 || 573 cs_create(mod, mcnode, CS_NODE_NAME, mc) != 0) 574 rc = -1; 575 576 nvlist_free(mc); 577 return (rc); 578 } 579 580 static int 581 chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 582 topo_instance_t min, topo_instance_t max, chip_t *chip) 583 { 584 int i, nerr = 0; 585 kstat_t *ksp; 586 ulong_t *chipmap; 587 tnode_t *cnode; 588 nvlist_t *pfmri, *fmri, *args; 589 topo_hdl_t *thp; 590 591 thp = topo_mod_handle(mod); 592 593 if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(chip->chip_ncpustats) * 594 sizeof (ulong_t))) == NULL) 595 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 596 597 for (i = min; i <= MAX(max, chip->chip_ncpustats); i++) { 598 599 if (i < min || i > max) 600 break; 601 602 if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == 603 NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) 604 continue; 605 606 chip->chip_cpustats[i] = ksp; 607 } 608 609 for (i = 0; i <= chip->chip_ncpustats; i++) { 610 kstat_named_t *k; 611 int err, chipid; 612 613 if ((ksp = chip->chip_cpustats[i]) == NULL) 614 continue; 615 616 if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) { 617 ++nerr; 618 continue; 619 } 620 621 chipid = k->value.l; 622 if (BT_TEST(chipmap, chipid)) 623 continue; 624 625 if (chipid < min || chipid > max) 626 continue; 627 628 args = pfmri = NULL; 629 if (topo_node_resource(pnode, &pfmri, &err) < 0 || 630 topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || 631 nvlist_add_nvlist(args, 632 TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { 633 nvlist_free(pfmri); 634 nvlist_free(args); 635 ++nerr; 636 continue; 637 } 638 fmri = topo_fmri_create(thp, 639 FM_FMRI_SCHEME_HC, name, chipid, args, &err); 640 nvlist_free(pfmri); 641 nvlist_free(args); 642 if (fmri == NULL) { 643 ++nerr; 644 continue; 645 } 646 647 if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri, 648 NULL)) == NULL) { 649 ++nerr; 650 nvlist_free(fmri); 651 continue; 652 } 653 654 (void) topo_node_fru_set(cnode, fmri, 0, &err); 655 656 nvlist_free(fmri); 657 658 (void) topo_pgroup_create(cnode, CHIP_PGROUP, 659 TOPO_STABILITY_PRIVATE, &err); 660 (void) chip_strprop(cnode, ksp, CHIP_VENDOR_ID); 661 (void) chip_longprop(cnode, ksp, CHIP_FAMILY); 662 (void) chip_longprop(cnode, ksp, CHIP_MODEL); 663 (void) chip_longprop(cnode, ksp, CHIP_STEPPING); 664 665 if (mc_create(mod, cnode, MC_NODE_NAME) != 0 || 666 cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip) != 0) 667 ++nerr; 668 } 669 670 topo_mod_free(mod, chipmap, BT_BITOUL(chip->chip_ncpustats) * 671 sizeof (ulong_t)); 672 673 if (nerr != 0) 674 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 675 676 return (0); 677 } 678 679 static int 680 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 681 topo_instance_t min, topo_instance_t max, void *arg) 682 { 683 chip_t *chip = (chip_t *)arg; 684 685 if (strcmp(name, "chip") == 0) 686 return (chip_create(mod, pnode, name, min, max, chip)); 687 688 return (0); 689 } 690