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