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