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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * AMD memory enumeration 31 */ 32 33 #include <sys/types.h> 34 #include <unistd.h> 35 #include <stropts.h> 36 #include <sys/fm/protocol.h> 37 #include <sys/mc.h> 38 #include <sys/mc_amd.h> 39 #include <fm/topo_mod.h> 40 #include <strings.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 44 #include "chip.h" 45 46 #define MAX_CHANNUM 1 47 #define MAX_DIMMNUM 7 48 #define MAX_CSNUM 7 49 50 static const topo_pgroup_info_t cs_pgroup = 51 { PGNAME(CS), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 52 static const topo_pgroup_info_t dimm_pgroup = 53 { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 54 static const topo_pgroup_info_t mc_pgroup = 55 { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 56 static const topo_pgroup_info_t rank_pgroup = 57 { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 58 static const topo_pgroup_info_t chan_pgroup = 59 { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 60 61 static const topo_method_t dimm_methods[] = { 62 { SIMPLE_DIMM_LBL, "Property method", 0, 63 TOPO_STABILITY_INTERNAL, simple_dimm_label}, 64 { SIMPLE_DIMM_LBL_MP, "Property method", 0, 65 TOPO_STABILITY_INTERNAL, simple_dimm_label_mp}, 66 { SEQ_DIMM_LBL, "Property method", 0, 67 TOPO_STABILITY_INTERNAL, seq_dimm_label}, 68 { G4_DIMM_LBL, "Property method", 0, 69 TOPO_STABILITY_INTERNAL, g4_dimm_label}, 70 { GET_DIMM_SERIAL, "Property method", 0, 71 TOPO_STABILITY_INTERNAL, get_dimm_serial}, 72 { NULL } 73 }; 74 75 static const topo_method_t rank_methods[] = { 76 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 77 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 78 mem_asru_compute }, 79 { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, 80 TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, 81 rank_fmri_present }, 82 { NULL } 83 }; 84 85 static const topo_method_t gen_cs_methods[] = { 86 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 87 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 88 mem_asru_compute }, 89 { SIMPLE_CS_LBL_MP, "Property method", 0, 90 TOPO_STABILITY_INTERNAL, simple_cs_label_mp}, 91 { NULL } 92 }; 93 94 static nvlist_t *cs_fmri[MC_CHIP_NCS]; 95 96 /* 97 * Called when there is no memory-controller driver to provide topology 98 * information. Generate a maximal memory topology that is appropriate 99 * for the chip revision. The memory-controller node has already been 100 * bound as mcnode, and the parent of that is cnode. 101 * 102 * We create a tree of dram-channel and chip-select nodes below the 103 * memory-controller node. There will be two dram channels and 8 chip-selects 104 * below each, regardless of actual socket type, processor revision and so on. 105 * This is adequate for generic diagnosis up to family 0x10 revision C. 106 * When support for revision D is implemented (or maybe C) we should take 107 * the opportunity to rework the topology tree completely (socket change will 108 * mean there can be no diagnosis history tied to the topology). 109 */ 110 /*ARGSUSED*/ 111 static int 112 amd_generic_mc_create(topo_mod_t *mod, tnode_t *cnode, tnode_t *mcnode, 113 int family, int model, int stepping, nvlist_t *auth) 114 { 115 int chan, cs; 116 117 /* 118 * Elsewhere we have already returned for families less than 0xf. 119 * This "generic" topology is adequate for all of family 0xf and 120 * for revisions A, B and C of family 0x10 (A = model 0, B = model 1, 121 * we'll guess C = model 3 at this point). 122 */ 123 if (family > 0x10 || (family == 0x10 && model > 3)) 124 return (1); 125 126 if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0, 127 MAX_CHANNUM) < 0) { 128 whinge(mod, NULL, "amd_generic_mc_create: range create for " 129 "channels failed\n"); 130 return (-1); 131 } 132 133 for (chan = 0; chan <= MAX_CHANNUM; chan++) { 134 tnode_t *chnode; 135 nvlist_t *fmri; 136 int err; 137 138 if (mkrsrc(mod, mcnode, CHAN_NODE_NAME, chan, auth, 139 &fmri) != 0) { 140 whinge(mod, NULL, "amd_generic_mc_create: mkrsrc " 141 "failed\n"); 142 return (-1); 143 } 144 145 if ((chnode = topo_node_bind(mod, mcnode, CHAN_NODE_NAME, 146 chan, fmri)) == NULL) { 147 nvlist_free(fmri); 148 whinge(mod, NULL, "amd_generic_mc_create: node " 149 "bind failed\n"); 150 return (-1); 151 } 152 153 nvlist_free(fmri); 154 155 (void) topo_pgroup_create(chnode, &chan_pgroup, &err); 156 157 (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel", 158 TOPO_PROP_IMMUTABLE, chan == 0 ? "A" : "B", &err); 159 160 if (topo_node_range_create(mod, chnode, CS_NODE_NAME, 161 0, MAX_CSNUM) < 0) { 162 whinge(mod, NULL, "amd_generic_mc_create: " 163 "range create for cs failed\n"); 164 return (-1); 165 } 166 167 for (cs = 0; cs <= MAX_CSNUM; cs++) { 168 tnode_t *csnode; 169 170 if (mkrsrc(mod, chnode, CS_NODE_NAME, cs, auth, 171 &fmri) != 0) { 172 whinge(mod, NULL, "amd_generic_mc_create: " 173 "mkrsrc for cs failed\n"); 174 return (-1); 175 } 176 177 if ((csnode = topo_node_bind(mod, chnode, CS_NODE_NAME, 178 cs, fmri)) == NULL) { 179 nvlist_free(fmri); 180 whinge(mod, NULL, "amd_generic_mc_create: " 181 "bind for cs failed\n"); 182 return (-1); 183 } 184 185 /* 186 * Dynamic ASRU for page faults within a chip-select. 187 * The topology does not represent pages (there are 188 * too many) so when a page is faulted we generate 189 * an ASRU to represent the individual page. 190 */ 191 if (topo_method_register(mod, csnode, 192 gen_cs_methods) < 0) 193 whinge(mod, NULL, "amd_generic_mc_create: " 194 "method registration failed\n"); 195 196 (void) topo_node_asru_set(csnode, fmri, 197 TOPO_ASRU_COMPUTE, &err); 198 199 nvlist_free(fmri); 200 } 201 } 202 203 return (0); 204 } 205 206 static nvlist_t * 207 amd_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) 208 { 209 mc_snapshot_info_t mcs; 210 void *buf = NULL; 211 uint8_t ver; 212 213 nvlist_t *nvl = NULL; 214 char path[64]; 215 int fd, err; 216 217 (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 218 fd = open(path, O_RDONLY); 219 220 if (fd == -1) { 221 /* 222 * Some v20z and v40z systems may have had the 3rd-party 223 * NWSnps packagae installed which installs a /dev/mc 224 * link. So try again via /devices. 225 */ 226 (void) snprintf(path, sizeof (path), 227 "/devices/pci@0,0/pci1022,1102@%x,2:mc-amd", 228 MC_AMD_DEV_OFFSET + id); 229 fd = open(path, O_RDONLY); 230 } 231 232 if (fd == -1) 233 return (NULL); /* do not whinge */ 234 235 if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 236 (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 237 ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { 238 239 whinge(mod, NULL, "mc failed to snapshot %s: %s\n", 240 path, strerror(errno)); 241 242 free(buf); 243 (void) close(fd); 244 return (NULL); 245 } 246 247 (void) close(fd); 248 err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 249 topo_mod_free(mod, buf, mcs.mcs_size); 250 251 252 if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) { 253 whinge(mod, NULL, "mc nvlist is not versioned\n"); 254 nvlist_free(nvl); 255 return (NULL); 256 } else if (ver != MC_NVLIST_VERS1) { 257 whinge(mod, NULL, "mc nvlist version mismatch\n"); 258 nvlist_free(nvl); 259 return (NULL); 260 } 261 262 return (err ? NULL : nvl); 263 } 264 265 int 266 amd_rank_create(topo_mod_t *mod, tnode_t *pnode, nvlist_t *dimmnvl, 267 nvlist_t *auth) 268 { 269 uint64_t *csnumarr; 270 char **csnamearr; 271 uint_t ncs, ncsname; 272 tnode_t *ranknode; 273 nvlist_t *fmri, *pfmri = NULL; 274 uint64_t dsz, rsz; 275 int nerr = 0; 276 int err; 277 int i; 278 279 if (nvlist_lookup_uint64_array(dimmnvl, "csnums", &csnumarr, 280 &ncs) != 0 || nvlist_lookup_string_array(dimmnvl, "csnames", 281 &csnamearr, &ncsname) != 0 || ncs != ncsname) { 282 whinge(mod, &nerr, "amd_rank_create: " 283 "csnums/csnames extraction failed\n"); 284 return (nerr); 285 } 286 287 if (topo_node_resource(pnode, &pfmri, &err) < 0) { 288 whinge(mod, &nerr, "amd_rank_create: parent fmri lookup " 289 "failed\n"); 290 return (nerr); 291 } 292 293 if (topo_node_range_create(mod, pnode, RANK_NODE_NAME, 0, ncs) < 0) { 294 whinge(mod, &nerr, "amd_rank_create: range create failed\n"); 295 nvlist_free(pfmri); 296 return (nerr); 297 } 298 299 if (topo_prop_get_uint64(pnode, PGNAME(DIMM), "size", &dsz, 300 &err) == 0) { 301 rsz = dsz / ncs; 302 } else { 303 whinge(mod, &nerr, "amd_rank_create: parent dimm has no " 304 "size\n"); 305 return (nerr); 306 } 307 308 for (i = 0; i < ncs; i++) { 309 if (mkrsrc(mod, pnode, RANK_NODE_NAME, i, auth, &fmri) < 0) { 310 whinge(mod, &nerr, "amd_rank_create: mkrsrc failed\n"); 311 continue; 312 } 313 314 if ((ranknode = topo_node_bind(mod, pnode, RANK_NODE_NAME, i, 315 fmri)) == NULL) { 316 nvlist_free(fmri); 317 whinge(mod, &nerr, "amd_rank_create: node bind " 318 "failed\n"); 319 continue; 320 } 321 322 nvlist_free(fmri); 323 324 (void) topo_node_fru_set(ranknode, pfmri, 0, &err); 325 326 /* 327 * If a rank is faulted the asru is the associated 328 * chip-select, but if a page within a rank is faulted 329 * the asru is just that page. Hence the dual preconstructed 330 * and computed ASRU. 331 */ 332 if (topo_method_register(mod, ranknode, rank_methods) < 0) 333 whinge(mod, &nerr, "amd_rank_create: " 334 "topo_method_register failed"); 335 336 (void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]], 337 TOPO_ASRU_COMPUTE, &err); 338 339 (void) topo_pgroup_create(ranknode, &rank_pgroup, &err); 340 341 (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "size", 342 TOPO_PROP_IMMUTABLE, rsz, &err); 343 344 (void) topo_prop_set_string(ranknode, PGNAME(RANK), "csname", 345 TOPO_PROP_IMMUTABLE, csnamearr[i], &err); 346 347 (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "csnum", 348 TOPO_PROP_IMMUTABLE, csnumarr[i], &err); 349 } 350 351 nvlist_free(pfmri); 352 353 return (nerr); 354 } 355 356 static int 357 amd_dimm_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 358 nvlist_t *mc, nvlist_t *auth) 359 { 360 int i, err, nerr = 0; 361 nvpair_t *nvp; 362 tnode_t *dimmnode; 363 nvlist_t *fmri, *asru, **dimmarr = NULL; 364 uint64_t num; 365 uint_t ndimm; 366 367 if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) { 368 whinge(mod, NULL, "amd_dimm_create: dimmlist lookup failed\n"); 369 return (-1); 370 } 371 372 if (ndimm == 0) 373 return (0); /* no dimms present on this node */ 374 375 if (topo_node_range_create(mod, pnode, name, 0, MAX_DIMMNUM) < 0) { 376 whinge(mod, NULL, "amd_dimm_create: range create failed\n"); 377 return (-1); 378 } 379 380 for (i = 0; i < ndimm; i++) { 381 if (nvlist_lookup_uint64(dimmarr[i], "num", &num) != 0) { 382 whinge(mod, &nerr, "amd_dimm_create: dimm num property " 383 "missing\n"); 384 continue; 385 } 386 387 if (mkrsrc(mod, pnode, name, num, auth, &fmri) < 0) { 388 whinge(mod, &nerr, "amd_dimm_create: mkrsrc failed\n"); 389 continue; 390 } 391 392 if ((dimmnode = topo_node_bind(mod, pnode, name, num, fmri)) 393 == NULL) { 394 nvlist_free(fmri); 395 whinge(mod, &nerr, "amd_dimm_create: node bind " 396 "failed\n"); 397 continue; 398 } 399 400 if (topo_method_register(mod, dimmnode, dimm_methods) < 0) 401 whinge(mod, &nerr, "amd_dimm_create: " 402 "topo_method_register failed"); 403 404 /* 405 * Use the mem computation method directly to publish the asru 406 * in the "mem" scheme. 407 */ 408 if (mem_asru_create(mod, fmri, &asru) == 0) { 409 (void) topo_node_asru_set(dimmnode, asru, 0, &err); 410 nvlist_free(asru); 411 } else { 412 413 nvlist_free(fmri); 414 whinge(mod, &nerr, "amd_dimm_create: " 415 "mem_asru_create failed\n"); 416 continue; 417 } 418 419 (void) topo_node_fru_set(dimmnode, fmri, 0, &err); 420 421 nvlist_free(fmri); 422 423 (void) topo_pgroup_create(dimmnode, &dimm_pgroup, &err); 424 425 for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL; 426 nvp = nvlist_next_nvpair(dimmarr[i], nvp)) { 427 if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY && 428 strcmp(nvpair_name(nvp), "csnums") == 0 || 429 nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY && 430 strcmp(nvpair_name(nvp), "csnames") == 0) 431 continue; /* used in amd_rank_create() */ 432 433 nerr += nvprop_add(mod, nvp, PGNAME(DIMM), dimmnode); 434 } 435 436 nerr += amd_rank_create(mod, dimmnode, dimmarr[i], auth); 437 } 438 439 return (nerr == 0 ? 0 : -1); 440 } 441 442 static int 443 amd_cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc, 444 nvlist_t *auth) 445 { 446 int i, err, nerr = 0; 447 nvpair_t *nvp; 448 tnode_t *csnode; 449 nvlist_t *fmri, **csarr = NULL; 450 uint64_t csnum; 451 uint_t ncs; 452 453 if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0) 454 return (-1); 455 456 if (ncs == 0) 457 return (0); /* no chip-selects configured on this node */ 458 459 if (topo_node_range_create(mod, pnode, name, 0, MAX_CSNUM) < 0) 460 return (-1); 461 462 for (i = 0; i < ncs; i++) { 463 if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) { 464 whinge(mod, &nerr, "amd_cs_create: cs num property " 465 "missing\n"); 466 continue; 467 } 468 469 if (mkrsrc(mod, pnode, name, csnum, auth, &fmri) != 0) { 470 whinge(mod, &nerr, "amd_cs_create: mkrsrc failed\n"); 471 continue; 472 } 473 474 if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri)) 475 == NULL) { 476 nvlist_free(fmri); 477 whinge(mod, &nerr, "amd_cs_create: node bind failed\n"); 478 continue; 479 } 480 481 cs_fmri[csnum] = fmri; /* nvlist will be freed in mc_create */ 482 483 (void) topo_node_asru_set(csnode, fmri, 0, &err); 484 485 (void) topo_pgroup_create(csnode, &cs_pgroup, &err); 486 487 for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL; 488 nvp = nvlist_next_nvpair(csarr[i], nvp)) { 489 nerr += nvprop_add(mod, nvp, PGNAME(CS), csnode); 490 } 491 } 492 493 return (nerr == 0 ? 0 : -1); 494 } 495 496 static int 497 amd_dramchan_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 498 nvlist_t *auth) 499 { 500 tnode_t *chnode; 501 nvlist_t *fmri; 502 char *socket; 503 int i, nchan; 504 int err, nerr = 0; 505 506 /* 507 * We will enumerate the number of channels present even if only 508 * channel A is in use (i.e., running in 64-bit mode). Only 509 * the socket 754 package has a single channel. 510 */ 511 if (topo_prop_get_string(pnode, PGNAME(MCT), "socket", 512 &socket, &err) == 0 && strcmp(socket, "Socket 754") == 0) 513 nchan = 1; 514 else 515 nchan = 2; 516 517 topo_mod_strfree(mod, socket); 518 519 if (topo_node_range_create(mod, pnode, name, 0, nchan - 1) < 0) 520 return (-1); 521 522 for (i = 0; i < nchan; i++) { 523 if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 524 whinge(mod, &nerr, "amd_dramchan_create: mkrsrc " 525 "failed\n"); 526 continue; 527 } 528 529 if ((chnode = topo_node_bind(mod, pnode, name, i, fmri)) 530 == NULL) { 531 nvlist_free(fmri); 532 whinge(mod, &nerr, "amd_dramchan_create: node bind " 533 "failed\n"); 534 continue; 535 } 536 537 nvlist_free(fmri); 538 539 (void) topo_pgroup_create(chnode, &chan_pgroup, &err); 540 541 (void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel", 542 TOPO_PROP_IMMUTABLE, i == 0 ? "A" : "B", &err); 543 } 544 545 return (nerr == 0 ? 0 : -1); 546 } 547 548 static int 549 amd_htconfig(topo_mod_t *mod, tnode_t *cnode, nvlist_t *htnvl) 550 { 551 nvpair_t *nvp; 552 int nerr = 0; 553 554 if (strcmp(topo_node_name(cnode), CHIP_NODE_NAME) != 0) { 555 whinge(mod, &nerr, "amd_htconfig: must pass a chip node!"); 556 return (-1); 557 } 558 559 for (nvp = nvlist_next_nvpair(htnvl, NULL); nvp != NULL; 560 nvp = nvlist_next_nvpair(htnvl, nvp)) { 561 if (nvprop_add(mod, nvp, PGNAME(CHIP), cnode) != 0) 562 nerr++; 563 } 564 565 return (nerr == 0 ? 0 : -1); 566 } 567 568 void 569 amd_mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 570 int family, int model, int stepping, int *nerrp) 571 { 572 tnode_t *mcnode; 573 nvlist_t *fmri; 574 nvpair_t *nvp; 575 nvlist_t *mc = NULL; 576 int i; 577 578 /* 579 * Return with no error for anything before AMD family 0xf - we 580 * won't generate even a generic memory topolofy for earlier 581 * families. 582 */ 583 if (family < 0xf) 584 return; 585 586 if (mkrsrc(mod, pnode, name, 0, auth, &fmri) != 0) { 587 whinge(mod, nerrp, "mc_create: mkrsrc failed\n"); 588 return; 589 } 590 591 if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) { 592 nvlist_free(fmri); 593 whinge(mod, nerrp, "mc_create: node range create failed\n"); 594 return; 595 } 596 597 if ((mcnode = topo_node_bind(mod, pnode, name, 0, 598 fmri)) == NULL) { 599 nvlist_free(mc); 600 topo_node_range_destroy(pnode, name); 601 nvlist_free(fmri); 602 whinge(mod, nerrp, "mc_create: mc bind failed\n"); 603 return; 604 } 605 (void) topo_node_fru_set(mcnode, NULL, 0, nerrp); 606 nvlist_free(fmri); 607 608 if ((mc = amd_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL) { 609 /* 610 * If a memory-controller driver exists for this chip model 611 * it has not attached or has otherwise malfunctioned; 612 * alternatively no memory-controller driver exists for this 613 * (presumably newly-released) cpu model. We fallback to 614 * creating a generic maximal topology. 615 */ 616 if (amd_generic_mc_create(mod, pnode, mcnode, 617 family, model, stepping, auth) != 0) 618 ++*nerrp; 619 return; 620 } 621 622 /* 623 * Add memory controller properties 624 */ 625 (void) topo_pgroup_create(mcnode, &mc_pgroup, nerrp); 626 627 for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL; 628 nvp = nvlist_next_nvpair(mc, nvp)) { 629 char *name = nvpair_name(nvp); 630 data_type_t type = nvpair_type(nvp); 631 632 if (type == DATA_TYPE_NVLIST_ARRAY && 633 (strcmp(name, "cslist") == 0 || 634 strcmp(name, "dimmlist") == 0)) { 635 continue; 636 } else if (type == DATA_TYPE_UINT8 && 637 strcmp(name, MC_NVLIST_VERSTR) == 0) { 638 continue; 639 } else if (type == DATA_TYPE_NVLIST && 640 strcmp(name, "htconfig") == 0) { 641 nvlist_t *htnvl; 642 643 (void) nvpair_value_nvlist(nvp, &htnvl); 644 if (amd_htconfig(mod, pnode, htnvl) != 0) 645 ++*nerrp; 646 } else { 647 if (nvprop_add(mod, nvp, PGNAME(MCT), mcnode) != 0) 648 ++*nerrp; 649 } 650 } 651 652 if (amd_dramchan_create(mod, mcnode, CHAN_NODE_NAME, auth) != 0 || 653 amd_cs_create(mod, mcnode, CS_NODE_NAME, mc, auth) != 0 || 654 amd_dimm_create(mod, mcnode, DIMM_NODE_NAME, mc, auth) != 0) 655 ++*nerrp; 656 657 /* 658 * Free the fmris for the chip-selects allocated in amd_cs_create 659 */ 660 for (i = 0; i < MC_CHIP_NCS; i++) { 661 if (cs_fmri[i] != NULL) { 662 nvlist_free(cs_fmri[i]); 663 cs_fmri[i] = NULL; 664 } 665 } 666 667 nvlist_free(mc); 668 } 669