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