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