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