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