1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2023 Oxide Computer Company 14 */ 15 16 /* 17 * This implements common DIMM creation for the hc tree. Currently this is based 18 * primarily on providing SPD data. 19 */ 20 21 #include <sys/fm/protocol.h> 22 #include <fm/topo_mod.h> 23 #include <libjedec.h> 24 #include <string.h> 25 #include <stdbool.h> 26 27 #include "topo_dimm.h" 28 29 typedef struct { 30 uint32_t sc_dram_type; 31 uint32_t sc_mod_type; 32 const char *sc_dram_str; 33 const char *sc_mod_str; 34 bool sc_asym; 35 uint32_t sc_nranks; 36 uint32_t sc_even_ranks; 37 uint32_t sc_odd_ranks; 38 uint32_t sc_data_bits; 39 uint32_t sc_ecc_bits; 40 uint32_t sc_nsubchan; 41 uint32_t sc_pkg_sl[2]; 42 uint32_t sc_pkg_ndie[2]; 43 uint64_t sc_die_size[2]; 44 uint32_t sc_dram_width[2]; 45 uint32_t sc_nrows[2]; 46 uint32_t sc_ncols[2]; 47 uint32_t sc_nbank_bits[2]; 48 uint32_t sc_nbgrp_bits[2]; 49 uint32_t sc_vdd; 50 uint32_t sc_devices; 51 } spd_cache_t; 52 53 static const topo_pgroup_info_t topo_dimm_pgroup = { 54 TOPO_PGROUP_DIMM_PROPS, 55 TOPO_STABILITY_PRIVATE, 56 TOPO_STABILITY_PRIVATE, 57 1 58 }; 59 60 static const topo_pgroup_info_t topo_dimm_comps_pgroup = { 61 TOPO_PGROUP_DIMM_COMPONENTS, 62 TOPO_STABILITY_PRIVATE, 63 TOPO_STABILITY_PRIVATE, 64 1 65 }; 66 67 /* 68 * Translate a subset of the DDR types that we're likely to support into the 69 * corresponding current DDR information. We only really support taking these 70 * apart, so that's OK. 71 */ 72 static const char * 73 topo_dimm_dram_type2str(spd_dram_type_t type) 74 { 75 switch (type) { 76 case SPD_DT_DDR4_SDRAM: 77 return (TOPO_DIMM_TYPE_DDR4); 78 case SPD_DT_LPDDR4_SDRAM: 79 return (TOPO_DIMM_TYPE_LPDDR4); 80 case SPD_DT_DDR5_SDRAM: 81 return (TOPO_DIMM_TYPE_DDR5); 82 case SPD_DT_LPDDR5_SDRAM: 83 return (TOPO_DIMM_TYPE_LPDDR5); 84 default: 85 return (NULL); 86 } 87 88 } 89 90 /* 91 * Various string functions for different component types. 92 */ 93 static const char * 94 topo_dimm_temp2str(uint32_t val) 95 { 96 switch (val) { 97 case SPD_TEMP_T_TSE2002: 98 return ("TSE2002"); 99 case SPD_TEMP_T_TSE2004av: 100 return ("TSE2004av"); 101 case SPD_TEMP_T_TS5111: 102 return ("TS5111"); 103 case SPD_TEMP_T_TS5110: 104 return ("TS5110"); 105 default: 106 return ("unknown"); 107 } 108 } 109 110 static const char * 111 topo_dimm_pmic2str(uint32_t val) 112 { 113 switch (val) { 114 case SPD_PMIC_T_PMIC5000: 115 return ("PMIC5000"); 116 case SPD_PMIC_T_PMIC5010: 117 return ("PMIC5010"); 118 case SPD_PMIC_T_PMIC5100: 119 return ("PMIC5100"); 120 default: 121 return ("unknown"); 122 } 123 } 124 125 static const char * 126 topo_dimm_cd2str(uint32_t val) 127 { 128 switch (val) { 129 case SPD_CD_T_DDR5CK01: 130 return ("DDR5CK01"); 131 default: 132 return ("unknown"); 133 } 134 } 135 136 static const char * 137 topo_dimm_rcd2str(uint32_t val) 138 { 139 switch (val) { 140 case SPD_RCD_T_SSTE32882: 141 return ("SSTE32882"); 142 case SPD_RCD_T_DDR4RCD01: 143 return ("DDR4RCD01"); 144 case SPD_RCD_T_DDR4RCD02: 145 return ("DDR4RCD02"); 146 case SPD_RCD_T_DDR5RCD01: 147 return ("DDR5RCD01"); 148 case SPD_RCD_T_DDR5RCD02: 149 return ("DDR5RCD02"); 150 case SPD_RCD_T_DDR5RCD03: 151 return ("DDR5RCD03"); 152 default: 153 return ("unknown"); 154 } 155 } 156 157 static const char * 158 topo_dimm_db2str(uint32_t val) 159 { 160 switch (val) { 161 case SPD_DB_T_DDR4DB01: 162 return ("DDR4DB01"); 163 case SPD_DB_T_DDR4DB02: 164 return ("DDR4DB02"); 165 case SPD_DB_T_DDR5DB01: 166 return ("DDR5DB01"); 167 case SPD_DB_T_DDR5DB02: 168 return ("DDR5DB02"); 169 default: 170 return ("unknown"); 171 } 172 } 173 174 static const char * 175 topo_dimm_mrcd2str(uint32_t val) 176 { 177 switch (val) { 178 case SPD_MRCD_T_DDR5MRCD01: 179 return ("DDR5MRCD01"); 180 default: 181 return ("unknown"); 182 } 183 } 184 185 static const char * 186 topo_dimm_mdb2str(uint32_t val) 187 { 188 switch (val) { 189 case SPD_MDB_T_DDR5MDB01: 190 return ("DDR5MDB01"); 191 default: 192 return ("unknown"); 193 } 194 } 195 196 static const char * 197 topo_dimm_dmb2str(uint32_t val) 198 { 199 switch (val) { 200 case SPD_DMB_T_DMB5011: 201 return ("DMB5011"); 202 default: 203 return ("unknown"); 204 } 205 } 206 207 static const char * 208 topo_dimm_spd2str(uint32_t val) 209 { 210 switch (val) { 211 case SPD_SPD_T_EE1004: 212 return ("EE1004"); 213 case SPD_SPD_T_SPD5118: 214 return ("SPD5118"); 215 case SPD_SPD_T_ESPD5216: 216 return ("ESPD5216"); 217 default: 218 return ("unknown"); 219 } 220 } 221 222 /* 223 * DDR4 and DDR5 have a fixed voltage. DDR3 had a range of voltages that could 224 * be selected. In addition, LPDDR4 and LPDDR5 depend on the specifics of the 225 * memory controller as they allow for variable options here. 226 */ 227 static uint32_t 228 topo_dimm_mod_vdd(spd_dram_type_t type) 229 { 230 switch (type) { 231 case SPD_DT_DDR4_SDRAM: 232 return (1200); 233 case SPD_DT_DDR5_SDRAM: 234 return (1100); 235 default: 236 return (0); 237 } 238 } 239 240 static const char * 241 topo_dimm_mod_type2str(spd_module_type_t type) 242 { 243 switch (type) { 244 case SPD_MOD_TYPE_RDIMM: 245 return ("RDIMM"); 246 case SPD_MOD_TYPE_UDIMM: 247 return ("UDIMM"); 248 case SPD_MOD_TYPE_SODIMM: 249 return ("SO-DIMM"); 250 case SPD_MOD_TYPE_LRDIMM: 251 return ("LRDIMM"); 252 case SPD_MOD_TYPE_MRDIMM: 253 return ("MRDIMM"); 254 case SPD_MOD_TYPE_DDIMM: 255 return ("DDIMM"); 256 case SPD_MOD_TYPE_SOLDER: 257 return ("solder-down"); 258 case SPD_MOD_TYPE_MINI_RDIMM: 259 return ("Mini-RDIMM"); 260 case SPD_MOD_TYPE_MINI_UDIMM: 261 return ("Mini-UDIMM"); 262 case SPD_MOD_TYPE_72b_SO_RDIMM: 263 return ("72b-SO-RDIMM"); 264 case SPD_MOD_TYPE_72b_SO_UDIMM: 265 return ("72b-SO-UDIMM"); 266 case SPD_MOD_TYPE_16b_SO_DIMM: 267 return ("16b-SO-DIMM"); 268 case SPD_MOD_TYPE_32b_SO_DIMM: 269 return ("32b-SO-DIMM"); 270 default: 271 return (NULL); 272 } 273 } 274 275 /* 276 * Go through and cache common properties that we would look up in the NVL into 277 * a structure. We do this once and then reuse this for common settings. We 278 * don't generally include PN/SN/Rev information in here since not having that 279 * is OK and we can still create nodes and due to the fact that we generally 280 * only use it once. 281 */ 282 static bool 283 topo_dimm_cache_spd(topo_mod_t *mod, nvlist_t *spd, spd_cache_t *cache) 284 { 285 /* 286 * First go through and look up values that we expect to always be 287 * present. 288 */ 289 if (nvlist_lookup_pairs(spd, 0, 290 SPD_KEY_MOD_TYPE, DATA_TYPE_UINT32, &cache->sc_mod_type, 291 SPD_KEY_NRANKS, DATA_TYPE_UINT32, &cache->sc_nranks, 292 SPD_KEY_NSUBCHAN, DATA_TYPE_UINT32, &cache->sc_nsubchan, 293 SPD_KEY_DATA_WIDTH, DATA_TYPE_UINT32, &cache->sc_data_bits, 294 SPD_KEY_ECC_WIDTH, DATA_TYPE_UINT32, &cache->sc_ecc_bits, 295 SPD_KEY_NBANK_BITS, DATA_TYPE_UINT32, &cache->sc_nbank_bits[0], 296 SPD_KEY_NBGRP_BITS, DATA_TYPE_UINT32, &cache->sc_nbgrp_bits[0], 297 SPD_KEY_NROW_BITS, DATA_TYPE_UINT32, &cache->sc_nrows[0], 298 SPD_KEY_NCOL_BITS, DATA_TYPE_UINT32, &cache->sc_ncols[0], 299 300 SPD_KEY_PKG_SL, DATA_TYPE_UINT32, &cache->sc_pkg_sl[0], 301 SPD_KEY_PKG_NDIE, DATA_TYPE_UINT32, &cache->sc_pkg_ndie[0], 302 SPD_KEY_DRAM_WIDTH, DATA_TYPE_UINT32, &cache->sc_dram_width[0], 303 SPD_KEY_DIE_SIZE, DATA_TYPE_UINT64, &cache->sc_die_size[0], 304 SPD_KEY_DEVS, DATA_TYPE_UINT32, &cache->sc_devices, 305 NULL) != 0) { 306 topo_mod_dprintf(mod, "failed to find expected primary SPD " 307 "keys"); 308 return (false); 309 } 310 311 /* 312 * Set information that should be valid based on the types that we 313 * support right now. 314 */ 315 cache->sc_dram_str = topo_dimm_dram_type2str(cache->sc_dram_type); 316 cache->sc_mod_str = topo_dimm_mod_type2str(cache->sc_mod_type); 317 cache->sc_vdd = topo_dimm_mod_vdd(cache->sc_dram_type); 318 319 /* 320 * Next we have keys that may or may not be present. 321 */ 322 cache->sc_asym = nvlist_lookup_boolean(spd, SPD_KEY_RANK_ASYM) == 0; 323 324 if (!cache->sc_asym) 325 return (true); 326 327 cache->sc_even_ranks = cache->sc_odd_ranks = cache->sc_nranks / 2; 328 if (cache->sc_nranks % 2 == 1) 329 cache->sc_even_ranks++; 330 331 /* 332 * Now go through and look up keys that we believe should always be 333 * present given that we have an asymmetric configuration. 334 */ 335 if (nvlist_lookup_pairs(spd, 0, 336 SPD_KEY_SEC_NBANK_BITS, DATA_TYPE_UINT32, &cache->sc_nbank_bits[1], 337 SPD_KEY_SEC_NBGRP_BITS, DATA_TYPE_UINT32, &cache->sc_nbgrp_bits[1], 338 SPD_KEY_SEC_NROW_BITS, DATA_TYPE_UINT32, &cache->sc_nrows[1], 339 SPD_KEY_SEC_NCOL_BITS, DATA_TYPE_UINT32, &cache->sc_ncols[1], 340 SPD_KEY_SEC_PKG_SL, DATA_TYPE_UINT32, &cache->sc_pkg_sl[1], 341 SPD_KEY_SEC_PKG_NDIE, DATA_TYPE_UINT32, &cache->sc_pkg_ndie[1], 342 SPD_KEY_SEC_DRAM_WIDTH, DATA_TYPE_UINT32, &cache->sc_dram_width[1], 343 SPD_KEY_SEC_DIE_SIZE, DATA_TYPE_UINT32, &cache->sc_die_size[1], 344 NULL) != 0) { 345 topo_mod_dprintf(mod, "failed to get secondary keys for SPD " 346 "size calculation"); 347 return (false); 348 } 349 350 return (true); 351 } 352 353 /* 354 * Calculating the size here is a little nuanced. The rough formula is provided 355 * by JEDEC in the various SPD Annexes. The rough formula is: 356 * 357 * (SDRAM Capacity / 8) * (Bus width / SDRAM width) * Logical ranks 358 * 359 * Phrased in terms of SPD macros this is really: 360 * 361 * SPD_KEY_DIE_SIZE / 8 * (SPD_KEY_DATA_WIDTH / SPD_KEY_DRAM_WIDTH) * Logical 362 * Ranks 363 * 364 * The DIMM operates in chunks that are equal to its data width multiplied by 365 * the number of sub-channels. In general for DDR4/5 this is always going to be 366 * 64-bits or 8 bytes. The ECC is not included in this. The SDRAM width is 367 * fairly straightforward. The logical ranks depends on the die type and the 368 * number of actual ranks present. This is basically SPD_KEY_PKG_NDIE * 369 * SPD_KEY_NRANKS. 370 * 371 * However, there are two small wrinkles: the calculation of logical ranks and 372 * asymmetrical modules. With asymmetrical modules the data width doesn't 373 * change, the capacity and SDRAM width may change. In addition, calculating 374 * logical ranks is a bit nuanced here. First, each module declares the number 375 * of ranks that exist in the package. This has to then be transformed into 376 * logical ranks, which happens if we're using 3DS based DIMMs, which is 377 * determined based on the SPD_KEY_PKG_SL key. When using 3DS we need to 378 * multiple the number of dies by the number of ranks, otherwise it stays at 379 * 1x. 380 * 381 * When we're using asymmetrical DIMMs, the primary fields nominally apply to 382 * the even ranks and the secondary fields to the odd ranks. This is explicitly 383 * the case in DDR5. It is less explicit in DDR4, but we treat it the same way. 384 */ 385 static bool 386 topo_dimm_calc_size(topo_mod_t *mod, const spd_cache_t *cache, uint64_t *sizep) 387 { 388 uint32_t pndie = cache->sc_pkg_ndie[0]; 389 uint32_t width = cache->sc_data_bits * cache->sc_nsubchan / 390 cache->sc_dram_width[0]; 391 392 *sizep = 0; 393 if (cache->sc_pkg_sl[0] != SPD_SL_3DS) 394 pndie = 1; 395 396 if (!cache->sc_asym) { 397 *sizep = pndie * width * cache->sc_nranks * 398 cache->sc_die_size[0] / 8; 399 return (true); 400 } 401 402 if (cache->sc_nranks < 2) { 403 topo_mod_dprintf(mod, "encountered asymmetrical module but it " 404 "only has %u ranks", cache->sc_nranks); 405 return (false); 406 } 407 408 *sizep = pndie * width * cache->sc_even_ranks * 409 cache->sc_die_size[0] / 8; 410 411 pndie = cache->sc_pkg_ndie[1]; 412 if (cache->sc_pkg_sl[1] != SPD_SL_3DS) 413 pndie = 1; 414 415 *sizep += pndie * width * cache->sc_odd_ranks * 416 cache->sc_die_size[1] / 8; 417 return (true); 418 } 419 420 /* 421 * Add basic information to the DIMM. Some information like the current memory 422 * speed or LPDDR voltage can only be derived from the memory controller or 423 * systems firmware (i.e. SMBIOS). 424 */ 425 static bool 426 topo_dimm_add_props(topo_mod_t *mod, tnode_t *dimm, const spd_cache_t *cache) 427 { 428 uint32_t nbanks[2], nbgrps[2], nbpbg[2]; 429 uint_t arr_len = 1; 430 uint64_t size; 431 432 nbgrps[0] = 1 << cache->sc_nbgrp_bits[0]; 433 nbpbg[0] = 1 << cache->sc_nbank_bits[0]; 434 nbanks[0] = nbgrps[0] * nbpbg[0]; 435 436 if (!topo_dimm_calc_size(mod, cache, &size)) { 437 return (false); 438 } 439 440 /* 441 * This indicates that we have an asymmetrical DIMM configuration. This 442 * implies that the number of banks and bank groups actually vary based 443 * on whether it's an odd/even rank. 444 */ 445 if (cache->sc_asym) { 446 arr_len = 2; 447 nbgrps[1] = 1 << cache->sc_nbgrp_bits[1]; 448 nbpbg[1] = 1 << cache->sc_nbank_bits[1]; 449 nbanks[1] = nbgrps[1] * nbpbg[1]; 450 } 451 452 if (topo_create_props(mod, dimm, TOPO_PROP_IMMUTABLE, &topo_dimm_pgroup, 453 TOPO_PROP_DIMM_RANKS, TOPO_TYPE_UINT32, cache->sc_nranks, 454 TOPO_PROP_DIMM_BANKS, TOPO_TYPE_UINT32_ARRAY, nbanks, arr_len, 455 TOPO_PROP_DIMM_BANK_GROUPS, TOPO_TYPE_UINT32_ARRAY, nbgrps, arr_len, 456 TOPO_PROP_DIMM_BANKS_PER_GROUP, TOPO_TYPE_UINT32_ARRAY, nbpbg, 457 arr_len, 458 TOPO_PROP_DIMM_SUBCHANNELS, TOPO_TYPE_UINT32, cache->sc_nsubchan, 459 TOPO_PROP_DIMM_DATA_WIDTH, TOPO_TYPE_UINT32, cache->sc_data_bits, 460 TOPO_PROP_DIMM_ECC_WIDTH, TOPO_TYPE_UINT32, cache->sc_ecc_bits, 461 TOPO_PROP_DIMM_VDD, TOPO_TYPE_UINT32, cache->sc_vdd, 462 TOPO_PROP_DIMM_SIZE, TOPO_TYPE_UINT64, size, 463 TOPO_PROP_DIMM_TYPE, TOPO_TYPE_STRING, cache->sc_dram_str, 464 TOPO_PROP_DIMM_MODULE_TYPE, TOPO_TYPE_STRING, cache->sc_mod_str, 465 NULL) != 0) { 466 topo_mod_dprintf(mod, "failed to set basic DIMM properties: %s", 467 topo_mod_errmsg(mod)); 468 return (false); 469 } 470 471 return (true); 472 } 473 474 static int 475 topo_dimm_create_tn(topo_mod_t *mod, tnode_t *pn, tnode_t **tnp, 476 const char *name, topo_instance_t inst, const char *part, const char *rev, 477 const char *serial) 478 { 479 int ret; 480 nvlist_t *auth = NULL; 481 nvlist_t *fmri = NULL; 482 tnode_t *tn; 483 484 if ((auth = topo_mod_auth(mod, pn)) == NULL) { 485 topo_mod_dprintf(mod, "failed to get auth data: %s", 486 topo_mod_errmsg(mod)); 487 ret = -1; 488 goto out; 489 } 490 491 if ((fmri = topo_mod_hcfmri(mod, pn, FM_HC_SCHEME_VERSION, name, 492 inst, NULL, auth, part, rev, serial)) == NULL) { 493 topo_mod_dprintf(mod, "failed to create fmri for %s[%" PRIu64 494 "]: %s\n", name, inst, topo_mod_errmsg(mod)); 495 ret = -1; 496 goto out; 497 } 498 499 if ((tn = topo_node_bind(mod, pn, name, inst, fmri)) == NULL) { 500 topo_mod_dprintf(mod, "failed to bind fmri for %s[%" PRIu64 501 "]: %s\n", name, inst, topo_mod_errmsg(mod)); 502 ret = -1; 503 goto out; 504 } 505 506 topo_pgroup_hcset(tn, auth); 507 if (topo_node_fru_set(tn, fmri, 0, &ret) != 0) { 508 topo_mod_dprintf(mod, "failed to set FRU: %s\n", 509 topo_strerror(ret)); 510 ret = topo_mod_seterrno(mod, ret); 511 goto out; 512 } 513 514 *tnp = tn; 515 ret = 0; 516 out: 517 nvlist_free(auth); 518 nvlist_free(fmri); 519 return (ret); 520 } 521 522 static bool 523 topo_dimm_crc_ok(topo_mod_t *mod, nvlist_t *nvl, spd_dram_type_t type) 524 { 525 nvlist_t *errs; 526 const char *crc_keys[2] = { NULL }; 527 528 /* 529 * Note: Because this function determines which forms of SPD we support, 530 * if you end up adding something to the list you should update 531 * topo_dimm_add_props() to make sure that any additional variants have 532 * been added there or that we have information from their corresponding 533 * memory controllers. 534 */ 535 switch (type) { 536 case SPD_DT_DDR4_SDRAM: 537 crc_keys[0] = SPD_KEY_CRC_DDR4_BASE; 538 crc_keys[1] = SPD_KEY_CRC_DDR4_BLK1; 539 break; 540 case SPD_DT_DDR5_SDRAM: 541 crc_keys[0] = SPD_KEY_CRC_DDR5; 542 break; 543 default: 544 topo_mod_dprintf(mod, "unsupported DRAM type: 0x%x", type); 545 return (false); 546 } 547 548 /* 549 * If there are no errors then we're likely OK and we can continue. 550 */ 551 if (nvlist_lookup_nvlist(nvl, SPD_KEY_ERRS, &errs) != 0) { 552 return (true); 553 } 554 555 for (size_t i = 0; i < ARRAY_SIZE(crc_keys); i++) { 556 nvlist_t *key; 557 558 if (crc_keys[i] == NULL) 559 continue; 560 561 if (nvlist_lookup_nvlist(errs, crc_keys[i], &key) == 0) { 562 return (false); 563 } 564 } 565 566 return (true); 567 } 568 569 typedef struct dimm_comp { 570 const char *dc_comp; 571 spd_device_t dc_mask; 572 bool dc_always; 573 uint32_t (*dc_count)(const struct dimm_comp *, const spd_cache_t *, 574 nvlist_t *); 575 /* XXX determine if cache is needed */ 576 bool (*dc_mfg)(topo_mod_t *, tnode_t *, const struct dimm_comp *, 577 const spd_cache_t *, nvlist_t *, void *); 578 const char *(*dc_type2str)(uint32_t); 579 void *dc_mfg_arg; 580 } dimm_comp_t; 581 582 static uint32_t 583 dimm_comp_count_solo(const dimm_comp_t *comp, const spd_cache_t *cache, 584 nvlist_t *spd) 585 { 586 return (1); 587 } 588 589 /* 590 * We'd like to determine the number of dies that are actually present. One 591 * way to calculate this is to look at the data bits and ecc bits that are 592 * required and divide that by the DRAM width. There should be one set of such 593 * dies for each primary rank. In DDR4/5 these contain the banks/groups. 594 * 595 * In a physical sense, even when using DDP or 3DS stacked modules, then there 596 * is still only a single refdes basically on the board so we create it that 597 * way. In the DDR4/5 world when there are more than two ranks, they are stacked 598 * or using the older DDP technology. So basically we assume there are only up 599 * to two ranks worth of dies at most. 600 */ 601 static uint32_t 602 dimm_comp_count_dies(const dimm_comp_t *comp, const spd_cache_t *cache, 603 nvlist_t *spd) 604 { 605 uint32_t chan_width = (cache->sc_ecc_bits + cache->sc_data_bits) * 606 cache->sc_nsubchan; 607 uint32_t ndies_rank[2] = { 0, 0 }; 608 609 ndies_rank[0] = chan_width / cache->sc_dram_width[0]; 610 if (cache->sc_asym) { 611 ndies_rank[1] = chan_width / cache->sc_dram_width[1]; 612 } else if (cache->sc_nranks >= 2) { 613 ndies_rank[1] = ndies_rank[0]; 614 } 615 616 return (ndies_rank[0] + ndies_rank[1]); 617 } 618 619 static uint32_t 620 dimm_comp_count_mask(const dimm_comp_t *comp, const spd_cache_t *cache, 621 nvlist_t *spd) 622 { 623 uint32_t ret = 0; 624 uint32_t combo_mask = cache->sc_devices & comp->dc_mask; 625 626 for (uint32_t i = 0; i < sizeof (uint32_t) * NBBY; i++) { 627 if (((1 << i) & combo_mask) != 0) 628 ret++; 629 } 630 631 return (ret); 632 } 633 634 /* 635 * In the DDR4 SPD information, there is an explicit key for the number of 636 * registers that actually exist in the system. If the key exists then we return 637 * that, otherwise we don't do anything. 638 */ 639 static uint32_t 640 dimm_comp_count_regs(const dimm_comp_t *comp, const spd_cache_t *cache, 641 nvlist_t *spd) 642 { 643 uint32_t ret; 644 645 if (nvlist_lookup_uint32(spd, SPD_KEY_MOD_NREGS, &ret) != 0) 646 return (0); 647 return (ret); 648 } 649 650 /* 651 * This enum indicates the possible state for all the keys of a given type. 652 * Basically we need to make sure that for the given range of keys they are 653 * generally consistent. 654 */ 655 typedef enum { 656 DIMM_COMP_K_VALID, 657 DIMM_COMP_K_ERR, 658 DIMM_COMP_K_ENOENT 659 } dimm_comp_key_state_t; 660 661 static dimm_comp_key_state_t 662 dimm_comp_keys_exist(nvlist_t *spd, const char *const *keys, uint_t nents, 663 bool partial_enoent) 664 { 665 dimm_comp_key_state_t ret; 666 667 if (nents == 0) { 668 return (DIMM_COMP_K_ERR); 669 } 670 671 if (keys == NULL) { 672 return (DIMM_COMP_K_ENOENT); 673 } 674 675 for (uint_t i = 0; i < nents; i++) { 676 dimm_comp_key_state_t cur; 677 678 cur = nvlist_exists(spd, keys[i]) ? DIMM_COMP_K_VALID : 679 DIMM_COMP_K_ENOENT; 680 if (i == 0) { 681 ret = cur; 682 continue; 683 } 684 685 /* 686 * If we have changed disposition that is a problem. However, we 687 * will allow a partial ENOENT to exist if we've been given the 688 * flag to cover for the case where we don't have a translation 689 * for a given manufacturer's JEDEC ID name. 690 */ 691 if (ret != cur) { 692 if (partial_enoent) { 693 ret = DIMM_COMP_K_VALID; 694 } else { 695 return (DIMM_COMP_K_ERR); 696 } 697 } 698 } 699 700 return (ret); 701 } 702 703 /* 704 * The JEDEC IDs are a pair of two digits. Because we don't really have arrays 705 * of arrays in topo, we instead convert this into a string of the form 706 * 0x%x:0x%x with the continuation first and then the specific value. 707 */ 708 static bool 709 dimm_comp_mfg_common_ids(topo_mod_t *mod, tnode_t *dimm, nvlist_t *spd, 710 const char *prop, const char *const *keys, uint_t nents) 711 { 712 char **strs = NULL; 713 bool ret = false; 714 int err; 715 716 if ((strs = topo_mod_zalloc(mod, sizeof (char *) * nents)) == NULL) { 717 topo_mod_dprintf(mod, "failed to allocate memory for %s string " 718 "array: %s", prop, topo_strerror(EMOD_NOMEM)); 719 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 720 return (false); 721 } 722 723 for (size_t i = 0; i < nents; i++) { 724 uint32_t *data; 725 uint_t nvals; 726 int nret = nvlist_lookup_uint32_array(spd, keys[i], &data, 727 &nvals); 728 729 if (nret != 0) { 730 topo_mod_dprintf(mod, "failed to look up %s: %s", 731 keys[i], strerror(nret)); 732 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 733 goto out; 734 } 735 736 if (nvals != 2) { 737 topo_mod_dprintf(mod, "key %s has wrong number of " 738 "array entries: found %u, expected %u", keys[i], 739 nvals, 2); 740 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 741 goto out; 742 } 743 744 if (topo_mod_asprintf(mod, &strs[i], "0x%x:0x%x", data[0], 745 data[1]) == -1) { 746 topo_mod_dprintf(mod, "failed to construct ID string " 747 "for %s: %s\n", keys[i], strerror(errno)); 748 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 749 goto out; 750 } 751 } 752 753 if (topo_prop_set_string_array(dimm, TOPO_PGROUP_DIMM_COMPONENTS, prop, 754 TOPO_PROP_IMMUTABLE, (const char **)strs, nents, &err) != 0) { 755 topo_mod_dprintf(mod, "failed to set property %s: %s", prop, 756 topo_strerror(err)); 757 (void) topo_mod_seterrno(mod, err); 758 goto out; 759 } 760 761 ret = true; 762 out: 763 for (uint_t i = 0; i < nents; i++) { 764 topo_mod_strfree(mod, strs[i]); 765 } 766 topo_mod_free(mod, strs, sizeof (char *) * nents); 767 return (ret); 768 } 769 770 static bool 771 dimm_comp_mfg_common_strings(topo_mod_t *mod, tnode_t *dimm, nvlist_t *spd, 772 const char *prop, const char *const *keys, uint_t nents, bool allow_enoent) 773 { 774 char **strs = NULL; 775 int err; 776 bool ret = false; 777 778 if ((strs = topo_mod_zalloc(mod, sizeof (char *) * nents)) == NULL) { 779 topo_mod_dprintf(mod, "failed to allocate memory for %s string " 780 "array: %s", prop, topo_strerror(EMOD_NOMEM)); 781 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 782 return (false); 783 } 784 785 for (size_t i = 0; i < nents; i++) { 786 int nret = nvlist_lookup_string(spd, keys[i], &strs[i]); 787 if (nret != 0 && !(allow_enoent && nret == ENOENT)) { 788 topo_mod_dprintf(mod, "failed to look up %s: %s", 789 keys[i], strerror(nret)); 790 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 791 goto out; 792 } 793 } 794 795 if (topo_prop_set_string_array(dimm, TOPO_PGROUP_DIMM_COMPONENTS, prop, 796 TOPO_PROP_IMMUTABLE, (const char **)strs, nents, &err) != 0) { 797 topo_mod_dprintf(mod, "failed to set property %s: %s", prop, 798 topo_strerror(err)); 799 (void) topo_mod_seterrno(mod, err); 800 goto out; 801 } 802 803 ret = true; 804 out: 805 topo_mod_free(mod, strs, sizeof (char *) * nents); 806 return (ret); 807 } 808 809 /* 810 * The type of a part is encoded as a uint32_t and has a corresponding enum. We 811 * want to translate that into a string. The table for that is stored in the 812 * dimm_comp_t. 813 */ 814 static bool 815 dimm_comp_mfg_common_type(topo_mod_t *mod, tnode_t *dimm, nvlist_t *spd, 816 const dimm_comp_t *comp, const char *const *keys, uint_t nents) 817 { 818 const char **strs = NULL; 819 int err; 820 bool ret = false; 821 char prop[64]; 822 823 if (comp->dc_type2str == NULL) { 824 (void) topo_mod_dprintf(mod, "missing type2str function for " 825 "component type %s", comp->dc_comp); 826 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 827 return (false); 828 } 829 830 (void) snprintf(prop, sizeof (prop), "%s-type", comp->dc_comp); 831 if ((strs = topo_mod_zalloc(mod, sizeof (char *) * nents)) == NULL) { 832 topo_mod_dprintf(mod, "failed to allocate memory for %s string " 833 "array: %s", prop, topo_strerror(EMOD_NOMEM)); 834 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 835 return (false); 836 } 837 838 for (size_t i = 0; i < nents; i++) { 839 uint32_t raw; 840 841 int nret = nvlist_lookup_uint32(spd, keys[i], &raw); 842 if (nret != 0) { 843 topo_mod_dprintf(mod, "failed to look up %s: %s", 844 keys[i], strerror(nret)); 845 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 846 goto out; 847 } 848 849 strs[i] = comp->dc_type2str(raw); 850 } 851 852 if (topo_prop_set_string_array(dimm, TOPO_PGROUP_DIMM_COMPONENTS, prop, 853 TOPO_PROP_IMMUTABLE, strs, nents, &err) != 0) { 854 topo_mod_dprintf(mod, "failed to set property %s: %s", prop, 855 topo_strerror(err)); 856 (void) topo_mod_seterrno(mod, err); 857 goto out; 858 } 859 860 ret = true; 861 out: 862 topo_mod_free(mod, strs, sizeof (char *) * nents); 863 return (ret); 864 } 865 866 867 /* 868 * Given a number of keys to check for each item type, attempt to look up each 869 * item and add a property based on it. Prior to DDR5, we generally won't have 870 * information for the manufacturers or revisions. As such, when we fail to get 871 * any keys of a given type, that's fine. However, we do want to make sure that 872 * we are always adding things consistently, that is if we are told we have 873 * three keys for something and sometimes only look up two, that's an error. 874 */ 875 static bool 876 dimm_comp_mfg_common(topo_mod_t *mod, tnode_t *dimm, const dimm_comp_t *comp, 877 nvlist_t *spd, const char *const *mfg_id_key, 878 const char *const *mfg_name_key, const char *const *type_key, 879 const char *const *rev_key, uint_t nents) 880 { 881 dimm_comp_key_state_t mfg_id_valid, mfg_name_valid, type_valid; 882 dimm_comp_key_state_t rev_valid; 883 884 if (nents == 0) { 885 return (true); 886 } 887 888 mfg_id_valid = dimm_comp_keys_exist(spd, mfg_id_key, nents, false); 889 mfg_name_valid = dimm_comp_keys_exist(spd, mfg_name_key, nents, true); 890 type_valid = dimm_comp_keys_exist(spd, type_key, nents, false); 891 rev_valid = dimm_comp_keys_exist(spd, rev_key, nents, false); 892 893 if (mfg_name_valid == DIMM_COMP_K_ERR || rev_valid == DIMM_COMP_K_ERR || 894 mfg_id_valid == DIMM_COMP_K_ERR || type_valid == DIMM_COMP_K_ERR) { 895 topo_mod_dprintf(mod, "encountered erroneous keys: 0x%x 0x%x " 896 "0x%x 0x%x", mfg_name_valid, rev_valid, mfg_id_valid, 897 type_valid); 898 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 899 return (false); 900 } 901 902 if (mfg_id_valid == DIMM_COMP_K_VALID) { 903 char key[64]; 904 905 (void) snprintf(key, sizeof (key), "%s-id", 906 comp->dc_comp); 907 if (!dimm_comp_mfg_common_ids(mod, dimm, spd, key, 908 mfg_id_key, nents)) { 909 return (false); 910 } 911 } 912 913 if (mfg_name_valid == DIMM_COMP_K_VALID) { 914 char key[64]; 915 916 (void) snprintf(key, sizeof (key), "%s-mfg-name", 917 comp->dc_comp); 918 if (!dimm_comp_mfg_common_strings(mod, dimm, spd, key, 919 mfg_name_key, nents, true)) { 920 return (false); 921 } 922 } 923 924 if (rev_valid == DIMM_COMP_K_VALID) { 925 char key[64]; 926 927 (void) snprintf(key, sizeof (key), "%s-revision", 928 comp->dc_comp); 929 if (!dimm_comp_mfg_common_strings(mod, dimm, spd, key, rev_key, 930 nents, false)) { 931 return (false); 932 } 933 } 934 935 if (type_valid == DIMM_COMP_K_VALID) { 936 if (!dimm_comp_mfg_common_type(mod, dimm, spd, comp, type_key, 937 nents)) { 938 return (false); 939 } 940 } 941 942 return (true); 943 } 944 945 static bool 946 dimm_comp_mfg_die(topo_mod_t *mod, tnode_t *dimm, const dimm_comp_t *comp, 947 const spd_cache_t *cache, nvlist_t *spd, void *arg) 948 { 949 const char *mfg_id = SPD_KEY_MFG_DRAM_MFG_ID; 950 const char *mfg_name = SPD_KEY_MFG_DRAM_MFG_NAME; 951 const char *rev = SPD_KEY_MFG_DRAM_STEP; 952 953 return (dimm_comp_mfg_common(mod, dimm, comp, spd, &mfg_id, &mfg_name, 954 NULL, &rev, 1)); 955 } 956 957 static bool 958 dimm_comp_mfg_single(topo_mod_t *mod, tnode_t *dimm, const dimm_comp_t *comp, 959 const spd_cache_t *cache, nvlist_t *spd, void *arg) 960 { 961 char *mfg_key = NULL, *mfg_str_key = NULL, *type_key = NULL; 962 char *rev_key = NULL; 963 const char *name = arg; 964 bool ret; 965 966 if (name == NULL) { 967 name = comp->dc_comp; 968 } 969 970 if (topo_mod_asprintf(mod, &mfg_key, "module.%s.mfg-id", name) == -1 || 971 topo_mod_asprintf(mod, &mfg_str_key, "module.%s.mfg-name", 972 name) == -1 || 973 topo_mod_asprintf(mod, &type_key, "module.%s.type", name) == -1 || 974 topo_mod_asprintf(mod, &rev_key, "module.%s.revision", name) == 975 -1) { 976 ret = false; 977 goto done; 978 } 979 980 ret = dimm_comp_mfg_common(mod, dimm, comp, spd, 981 (const char **)&mfg_key, (const char **)&mfg_str_key, 982 (const char **)&type_key, (const char **)&rev_key, 1); 983 984 done: 985 topo_mod_strfree(mod, mfg_key); 986 topo_mod_strfree(mod, mfg_str_key); 987 topo_mod_strfree(mod, type_key); 988 topo_mod_strfree(mod, rev_key); 989 return (ret); 990 } 991 992 static bool 993 dimm_comp_mfg_pmic(topo_mod_t *mod, tnode_t *dimm, const dimm_comp_t *comp, 994 const spd_cache_t *cache, nvlist_t *spd, void *arg) 995 { 996 const char **mfg_keys = NULL, **mfg_str_keys = NULL, **type_keys = NULL; 997 const char **rev_keys = NULL; 998 bool ret = false; 999 uint32_t nents = 0, curent = 0; 1000 size_t alen; 1001 1002 if ((cache->sc_devices & SPD_DEVICE_PMIC_0) != 0) 1003 nents++; 1004 if ((cache->sc_devices & SPD_DEVICE_PMIC_1) != 0) 1005 nents++; 1006 if ((cache->sc_devices & SPD_DEVICE_PMIC_2) != 0) 1007 nents++; 1008 1009 if (nents == 0) { 1010 return (true); 1011 } 1012 1013 alen = sizeof (char *) * nents; 1014 1015 if ((mfg_keys = topo_mod_zalloc(mod, alen)) == NULL || 1016 (mfg_str_keys = topo_mod_zalloc(mod, alen)) == NULL || 1017 (type_keys = topo_mod_zalloc(mod, alen)) == NULL || 1018 (rev_keys = topo_mod_zalloc(mod, alen)) == NULL) { 1019 goto done; 1020 } 1021 1022 if ((cache->sc_devices & SPD_DEVICE_PMIC_0) != 0) { 1023 mfg_keys[curent] = SPD_KEY_DEV_PMIC0_MFG; 1024 mfg_str_keys[curent] = SPD_KEY_DEV_PMIC0_MFG_NAME; 1025 type_keys[curent] = SPD_KEY_DEV_PMIC0_TYPE; 1026 rev_keys[curent] = SPD_KEY_DEV_PMIC0_REV; 1027 curent++; 1028 } 1029 1030 if ((cache->sc_devices & SPD_DEVICE_PMIC_1) != 0) { 1031 mfg_keys[curent] = SPD_KEY_DEV_PMIC1_MFG; 1032 mfg_str_keys[curent] = SPD_KEY_DEV_PMIC1_MFG_NAME; 1033 type_keys[curent] = SPD_KEY_DEV_PMIC1_TYPE; 1034 rev_keys[curent] = SPD_KEY_DEV_PMIC1_REV; 1035 curent++; 1036 } 1037 1038 if ((cache->sc_devices & SPD_DEVICE_PMIC_2) != 0) { 1039 mfg_keys[curent] = SPD_KEY_DEV_PMIC2_MFG; 1040 mfg_str_keys[curent] = SPD_KEY_DEV_PMIC2_MFG_NAME; 1041 type_keys[curent] = SPD_KEY_DEV_PMIC2_TYPE; 1042 rev_keys[curent] = SPD_KEY_DEV_PMIC2_REV; 1043 curent++; 1044 } 1045 1046 ret = dimm_comp_mfg_common(mod, dimm, comp, spd, mfg_keys, 1047 mfg_str_keys, type_keys, rev_keys, nents); 1048 1049 done: 1050 topo_mod_free(mod, mfg_keys, alen); 1051 topo_mod_free(mod, mfg_str_keys, alen); 1052 topo_mod_free(mod, type_keys, alen); 1053 topo_mod_free(mod, rev_keys, alen); 1054 return (ret); 1055 } 1056 static const dimm_comp_t dimm_comps[] = { 1057 { .dc_comp = TOPO_PROP_DIMM_COMP_DIE, .dc_always = true, 1058 .dc_count = dimm_comp_count_dies, .dc_mfg = dimm_comp_mfg_die }, 1059 { .dc_comp = TOPO_PROP_DIMM_COMP_SPD, .dc_mask = SPD_DEVICE_SPD, 1060 .dc_count = dimm_comp_count_solo, .dc_mfg = dimm_comp_mfg_single, 1061 .dc_type2str = topo_dimm_spd2str }, 1062 { .dc_comp = TOPO_PROP_DIMM_COMP_TS, .dc_mask = SPD_DEVICE_TEMP_1 | 1063 SPD_DEVICE_TEMP_2, .dc_count = dimm_comp_count_mask, 1064 .dc_mfg = dimm_comp_mfg_single, .dc_mfg_arg = "temp", 1065 .dc_type2str = topo_dimm_temp2str }, 1066 { .dc_comp = TOPO_PROP_DIMM_COMP_HS, .dc_mask = SPD_DEVICE_HS }, 1067 { .dc_comp = TOPO_PROP_DIMM_COMP_PMIC, .dc_mask = SPD_DEVICE_PMIC_0 | 1068 SPD_DEVICE_PMIC_1 | SPD_DEVICE_PMIC_2, .dc_mfg = dimm_comp_mfg_pmic, 1069 .dc_type2str = topo_dimm_pmic2str }, 1070 { .dc_comp = TOPO_PROP_DIMM_COMP_CD, .dc_mask = SPD_DEVICE_CD, 1071 .dc_mfg = dimm_comp_mfg_single, .dc_type2str = topo_dimm_cd2str }, 1072 { .dc_comp = TOPO_PROP_DIMM_COMP_RCD, .dc_mask = SPD_DEVICE_RCD, 1073 .dc_count = dimm_comp_count_regs, .dc_mfg = dimm_comp_mfg_single, 1074 .dc_type2str = topo_dimm_rcd2str }, 1075 { .dc_comp = TOPO_PROP_DIMM_COMP_DB, .dc_mask = SPD_DEVICE_DB, 1076 .dc_mfg = dimm_comp_mfg_single, .dc_type2str = topo_dimm_db2str }, 1077 { .dc_comp = TOPO_PROP_DIMM_COMP_MRCD, .dc_mask = SPD_DEVICE_MRCD, 1078 .dc_mfg = dimm_comp_mfg_single, .dc_type2str = topo_dimm_mrcd2str }, 1079 { .dc_comp = TOPO_PROP_DIMM_COMP_MDB, .dc_mask = SPD_DEVICE_MDB, 1080 .dc_mfg = dimm_comp_mfg_single, .dc_type2str = topo_dimm_mdb2str }, 1081 { .dc_comp = TOPO_PROP_DIMM_COMP_DMB, .dc_mask = SPD_DEVICE_DMB, 1082 .dc_mfg = dimm_comp_mfg_single, .dc_type2str = topo_dimm_dmb2str } 1083 }; 1084 1085 /* 1086 * Go through and add the different information that exists for each type of 1087 * component that we might have. For most items on here, we can know they are 1088 * present, but we may not be able to get the count and much more than a 1089 * revision string or type. See additional discussion at the definition of 1090 * TOPO_PGROUP_DIMM_COMPONENTS for this property group and a bit of the design. 1091 */ 1092 static bool 1093 topo_dimm_add_comps(topo_mod_t *mod, tnode_t *dimm, nvlist_t *spd, 1094 const spd_cache_t *cache) 1095 { 1096 int ret; 1097 const char *devs[ARRAY_SIZE(dimm_comps)]; 1098 uint_t ndevs = 0; 1099 const char *pg = topo_dimm_comps_pgroup.tpi_name; 1100 1101 /* 1102 * Always create the pgroup, as we'll at least have information about 1103 * the DRAM dies to add. 1104 */ 1105 if (topo_pgroup_create(dimm, &topo_dimm_comps_pgroup, &ret) != 0) { 1106 topo_mod_dprintf(mod, "failed to create property group %s: %s", 1107 pg, topo_strerror(ret)); 1108 (void) topo_mod_seterrno(mod, ret); 1109 return (false); 1110 } 1111 1112 for (size_t i = 0; i < ARRAY_SIZE(dimm_comps); i++) { 1113 const dimm_comp_t *c = &dimm_comps[i]; 1114 char prop[64]; 1115 bool pres = false; 1116 1117 if (c->dc_always || (cache->sc_devices & c->dc_mask) != 0) { 1118 pres = true; 1119 devs[ndevs] = dimm_comps[i].dc_comp; 1120 ndevs++; 1121 } 1122 1123 if (pres && c->dc_count != NULL) { 1124 uint32_t count = c->dc_count(c, cache, spd); 1125 (void) snprintf(prop, sizeof (prop), "%s-count", 1126 c->dc_comp); 1127 if (count != 0 && topo_prop_set_uint32(dimm, pg, prop, 1128 TOPO_PROP_IMMUTABLE, count, &ret) != 0) { 1129 topo_mod_dprintf(mod, "failed to set property " 1130 "%s: %s", prop, topo_strerror(ret)); 1131 (void) topo_mod_seterrno(mod, ret); 1132 return (false); 1133 } 1134 } 1135 1136 if (pres && c->dc_mfg != NULL && !c->dc_mfg(mod, dimm, c, cache, 1137 spd, c->dc_mfg_arg)) { 1138 return (false); 1139 } 1140 } 1141 1142 if (topo_prop_set_string_array(dimm, pg, TOPO_PROP_DIMM_COMP, 1143 TOPO_PROP_IMMUTABLE, devs, ndevs, &ret) != 0) { 1144 topo_mod_dprintf(mod, "failed to create components array: %s", 1145 topo_strerror(ret)); 1146 (void) topo_mod_seterrno(mod, ret); 1147 return (false); 1148 } 1149 1150 return (true); 1151 } 1152 1153 static int 1154 topo_dimm_enum(topo_mod_t *mod, tnode_t *pn, const char *name, 1155 topo_instance_t min, topo_instance_t max, void *modarg, void *data) 1156 { 1157 int ret; 1158 const topo_dimm_t *dimm; 1159 spd_error_t spd_err; 1160 nvlist_t *spd_nvl = NULL; 1161 uint32_t dram_type; 1162 char *mod_pn = NULL, *mod_sn = NULL, *mod_rev = NULL; 1163 char *mod_c_pn = NULL, *mod_c_sn = NULL, *mod_c_rev = NULL; 1164 tnode_t *dimm_tn; 1165 spd_cache_t spd_cache; 1166 1167 topo_mod_dprintf(mod, "asked to enum %s [%" PRIu64 ", %" PRIu64 "] on " 1168 "%s%" PRIu64 "\n", name, min, max, topo_node_name(pn), 1169 topo_node_instance(pn)); 1170 1171 if (strcmp(name, DIMM) != 0) { 1172 topo_mod_dprintf(mod, "cannot enumerate %s: unknown type\n", 1173 name); 1174 ret = -1; 1175 goto out; 1176 } 1177 1178 if (data == NULL) { 1179 topo_mod_dprintf(mod, "cannot enumerate %s: missing required " 1180 "data\n", name); 1181 ret = topo_mod_seterrno(mod, EMOD_METHOD_INVAL); 1182 goto out; 1183 } 1184 1185 if (min != max) { 1186 topo_mod_dprintf(mod, "cannot enumerate %s: multiple instances " 1187 "requested\n", name); 1188 ret = topo_mod_seterrno(mod, EMOD_METHOD_INVAL); 1189 goto out; 1190 } 1191 1192 dimm = data; 1193 if (dimm->td_nspd == 0 || dimm->td_spd == NULL) { 1194 topo_mod_dprintf(mod, "cannot enumerate %s: no valid DIMM " 1195 "data provided", name); 1196 ret = topo_mod_seterrno(mod, EMOD_METHOD_INVAL); 1197 goto out; 1198 } 1199 1200 spd_nvl = libjedec_spd(dimm->td_spd, dimm->td_nspd, &spd_err); 1201 if (spd_nvl == NULL) { 1202 topo_mod_dprintf(mod, "failed to parse SPD information: got " 1203 "error 0x%x", spd_err); 1204 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 1205 } 1206 1207 if ((ret = nvlist_lookup_uint32(spd_nvl, SPD_KEY_DRAM_TYPE, 1208 &dram_type)) != 0) { 1209 topo_mod_dprintf(mod, "failed to get SPD key %s: %s", 1210 SPD_KEY_DRAM_TYPE, strerror(ret)); 1211 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 1212 goto out; 1213 } 1214 1215 if (!topo_dimm_crc_ok(mod, spd_nvl, dram_type)) { 1216 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 1217 goto out; 1218 } 1219 1220 /* 1221 * If we have SPD data, we'd expect all of the basic part, serial, and 1222 * revision information to be available for the module. However, if 1223 * there was bad data for some reason, we allow ourselves to not be able 1224 * to look it up. 1225 */ 1226 if (nvlist_lookup_pairs(spd_nvl, NV_FLAG_NOENTOK, 1227 SPD_KEY_MFG_MOD_PN, DATA_TYPE_STRING, &mod_pn, 1228 SPD_KEY_MFG_MOD_SN, DATA_TYPE_STRING, &mod_sn, 1229 SPD_KEY_MFG_MOD_REV, DATA_TYPE_STRING, &mod_rev, NULL) != 0) { 1230 topo_mod_dprintf(mod, "failed to look up basic DIMM FMRI " 1231 "information"); 1232 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 1233 goto out; 1234 } 1235 1236 mod_c_pn = topo_mod_clean_str(mod, mod_pn); 1237 mod_c_sn = topo_mod_clean_str(mod, mod_sn); 1238 mod_c_rev = topo_mod_clean_str(mod, mod_rev); 1239 1240 if ((ret = topo_node_range_create(mod, pn, DIMM, 0, 0)) != 0) { 1241 topo_mod_dprintf(mod, "failed to create DIMM range: %s", 1242 topo_mod_errmsg(mod)); 1243 goto out; 1244 } 1245 1246 if ((ret = topo_dimm_create_tn(mod, pn, &dimm_tn, DIMM, 0, mod_c_pn, 1247 mod_c_rev, mod_c_sn)) != 0) { 1248 goto out; 1249 } 1250 1251 if (topo_node_label_set(dimm_tn, NULL, &ret) != 0) { 1252 topo_mod_dprintf(mod, "failed to set label on DIMM: %s", 1253 topo_mod_errmsg(mod)); 1254 ret = topo_mod_seterrno(mod, ret); 1255 goto out; 1256 } 1257 1258 (void) memset(&spd_cache, 0, sizeof (spd_cache)); 1259 spd_cache.sc_dram_type = dram_type; 1260 if (!topo_dimm_cache_spd(mod, spd_nvl, &spd_cache)) 1261 goto out; 1262 1263 if (!topo_dimm_add_props(mod, dimm_tn, &spd_cache)) 1264 goto out; 1265 1266 if (!topo_dimm_add_comps(mod, dimm_tn, spd_nvl, &spd_cache)) 1267 goto out; 1268 1269 ret = 0; 1270 out: 1271 topo_mod_strfree(mod, mod_c_sn); 1272 topo_mod_strfree(mod, mod_c_pn); 1273 topo_mod_strfree(mod, mod_c_rev); 1274 nvlist_free(spd_nvl); 1275 return (ret); 1276 } 1277 1278 static const topo_modops_t topo_dimm_ops = { 1279 topo_dimm_enum, NULL 1280 }; 1281 1282 static topo_modinfo_t topo_dimm_mod = { 1283 "Common DIMM Enumerator", FM_FMRI_SCHEME_HC, TOPO_MOD_DIMM_VERS, 1284 &topo_dimm_ops 1285 }; 1286 1287 int 1288 _topo_init(topo_mod_t *mod, topo_version_t version) 1289 { 1290 if (getenv("TOPODIMMDEBUG") != NULL) { 1291 topo_mod_setdebug(mod); 1292 } 1293 topo_mod_dprintf(mod, "module initializing\n"); 1294 1295 return (topo_mod_register(mod, &topo_dimm_mod, TOPO_VERSION)); 1296 } 1297 1298 void 1299 _topo_fini(topo_mod_t *mod) 1300 { 1301 topo_mod_unregister(mod); 1302 } 1303