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