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 2025 Oxide Computer Company 14 */ 15 16 /* 17 * Dump and restore logic for external processing. Dump generally runs in kernel 18 * context from a well formed structure created by the driver. Restore is used 19 * in userland as part of testing and related. 20 * 21 * Note, there are a lot of fields in these structures that are not serialized 22 * because they are not used as part of the decoder (e.g. the various raw values 23 * which are captured to aid future debugging). 24 */ 25 26 #include "zen_umc.h" 27 #ifndef _KERNEL 28 #include <string.h> 29 #include <strings.h> 30 #include <libnvpair.h> 31 #endif 32 33 static nvlist_t * 34 zen_umc_dump_dram_rule(df_dram_rule_t *rule) 35 { 36 nvlist_t *nvl; 37 38 nvl = fnvlist_alloc(); 39 fnvlist_add_uint32(nvl, "ddr_flags", rule->ddr_flags); 40 fnvlist_add_uint64(nvl, "ddr_base", rule->ddr_base); 41 fnvlist_add_uint64(nvl, "ddr_limit", rule->ddr_limit); 42 fnvlist_add_uint16(nvl, "ddr_dest_fabid", rule->ddr_dest_fabid); 43 fnvlist_add_uint8(nvl, "ddr_sock_ileave_bits", 44 rule->ddr_sock_ileave_bits); 45 fnvlist_add_uint8(nvl, "ddr_die_ileave_bits", 46 rule->ddr_die_ileave_bits); 47 fnvlist_add_uint8(nvl, "ddr_addr_start", rule->ddr_addr_start); 48 fnvlist_add_uint8(nvl, "ddr_remap_ent", rule->ddr_remap_ent); 49 fnvlist_add_uint32(nvl, "ddr_chan_ileave", rule->ddr_chan_ileave); 50 51 return (nvl); 52 } 53 54 static nvlist_t * 55 zen_umc_dump_cs(umc_cs_t *cs) 56 { 57 nvlist_t *nvl = fnvlist_alloc(); 58 nvlist_t *base = fnvlist_alloc(); 59 nvlist_t *sec = fnvlist_alloc(); 60 61 fnvlist_add_uint32(nvl, "ucs_flags", cs->ucs_flags); 62 fnvlist_add_uint64(base, "udb_base", cs->ucs_base.udb_base); 63 fnvlist_add_uint8(base, "udb_valid", cs->ucs_base.udb_valid); 64 fnvlist_add_nvlist(nvl, "ucs_base", base); 65 nvlist_free(base); 66 fnvlist_add_uint64(sec, "udb_base", cs->ucs_sec.udb_base); 67 fnvlist_add_uint8(sec, "udb_valid", cs->ucs_sec.udb_valid); 68 fnvlist_add_nvlist(nvl, "ucs_sec", sec); 69 nvlist_free(sec); 70 fnvlist_add_uint64(nvl, "ucs_base_mask", cs->ucs_base_mask); 71 fnvlist_add_uint64(nvl, "ucs_sec_mask", cs->ucs_sec_mask); 72 fnvlist_add_uint8(nvl, "ucs_nrow_lo", cs->ucs_nrow_lo); 73 fnvlist_add_uint8(nvl, "ucs_nrow_hi", cs->ucs_nrow_hi); 74 fnvlist_add_uint8(nvl, "ucs_nbank_groups", cs->ucs_nbank_groups); 75 fnvlist_add_uint8(nvl, "ucs_cs_xor", cs->ucs_cs_xor); 76 fnvlist_add_uint8(nvl, "ucs_row_hi_bit", cs->ucs_row_hi_bit); 77 fnvlist_add_uint8(nvl, "ucs_row_low_bit", cs->ucs_row_low_bit); 78 fnvlist_add_uint8_array(nvl, "ucs_bank_bits", cs->ucs_bank_bits, 79 cs->ucs_nbanks); 80 fnvlist_add_uint8_array(nvl, "ucs_col_bits", cs->ucs_col_bits, 81 cs->ucs_ncol); 82 fnvlist_add_uint8(nvl, "ucs_inv_msbs", cs->ucs_inv_msbs); 83 fnvlist_add_uint8_array(nvl, "ucs_rm_bits", cs->ucs_rm_bits, 84 cs->ucs_nrm); 85 fnvlist_add_uint8(nvl, "ucs_inv_msbs_sec", cs->ucs_inv_msbs_sec); 86 fnvlist_add_uint8_array(nvl, "ucs_rm_bits_sec", cs->ucs_rm_bits_sec, 87 cs->ucs_nrm); 88 fnvlist_add_uint8(nvl, "ucs_subchan", cs->ucs_subchan); 89 90 return (nvl); 91 } 92 93 static nvlist_t * 94 zen_umc_dump_dimm(umc_dimm_t *dimm) 95 { 96 nvlist_t *nvl = fnvlist_alloc(); 97 nvlist_t *cs[ZEN_UMC_MAX_CS_PER_DIMM]; 98 99 fnvlist_add_uint32(nvl, "ud_flags", dimm->ud_flags); 100 fnvlist_add_uint32(nvl, "ud_width", dimm->ud_width); 101 fnvlist_add_uint32(nvl, "ud_kind", dimm->ud_kind); 102 fnvlist_add_uint32(nvl, "ud_dimmno", dimm->ud_dimmno); 103 104 for (uint_t i = 0; i < ZEN_UMC_MAX_CS_PER_DIMM; i++) { 105 cs[i] = zen_umc_dump_cs(&dimm->ud_cs[i]); 106 } 107 fnvlist_add_nvlist_array(nvl, "ud_cs", cs, ZEN_UMC_MAX_CS_PER_DIMM); 108 for (uint_t i = 0; i < ZEN_UMC_MAX_CS_PER_DIMM; i++) { 109 nvlist_free(cs[i]); 110 } 111 112 return (nvl); 113 } 114 115 static nvlist_t * 116 zen_umc_dump_chan_hash(umc_chan_hash_t *hash) 117 { 118 nvlist_t *nvl = fnvlist_alloc(); 119 120 fnvlist_add_uint32(nvl, "uch_flags", hash->uch_flags); 121 122 if (hash->uch_flags & UMC_CHAN_HASH_F_BANK) { 123 nvlist_t *banks[ZEN_UMC_MAX_CHAN_BANK_HASH]; 124 for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_BANK_HASH; i++) { 125 banks[i] = fnvlist_alloc(); 126 127 fnvlist_add_uint32(banks[i], "ubh_row_xor", 128 hash->uch_bank_hashes[i].ubh_row_xor); 129 fnvlist_add_uint32(banks[i], "ubh_col_xor", 130 hash->uch_bank_hashes[i].ubh_col_xor); 131 fnvlist_add_boolean_value(banks[i], "ubh_en", 132 hash->uch_bank_hashes[i].ubh_en); 133 } 134 fnvlist_add_nvlist_array(nvl, "uch_bank_hashes", banks, 135 ZEN_UMC_MAX_CHAN_BANK_HASH); 136 137 for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_BANK_HASH; i++) { 138 nvlist_free(banks[i]); 139 } 140 } 141 142 if (hash->uch_flags & UMC_CHAN_HASH_F_RM) { 143 nvlist_t *rm[ZEN_UMC_MAX_CHAN_RM_HASH]; 144 for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_RM_HASH; i++) { 145 rm[i] = fnvlist_alloc(); 146 147 fnvlist_add_uint64(rm[i], "uah_addr_xor", 148 hash->uch_rm_hashes[i].uah_addr_xor); 149 fnvlist_add_boolean_value(rm[i], "uah_en", 150 hash->uch_rm_hashes[i].uah_en); 151 } 152 fnvlist_add_nvlist_array(nvl, "uch_rm_hashes", rm, 153 ZEN_UMC_MAX_CHAN_RM_HASH); 154 155 for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_RM_HASH; i++) { 156 nvlist_free(rm[i]); 157 } 158 } 159 160 if (hash->uch_flags & UMC_CHAN_HASH_F_CS) { 161 nvlist_t *cs[ZEN_UMC_MAX_CHAN_CS_HASH]; 162 for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_CS_HASH; i++) { 163 cs[i] = fnvlist_alloc(); 164 165 fnvlist_add_uint64(cs[i], "uah_addr_xor", 166 hash->uch_rm_hashes[i].uah_addr_xor); 167 fnvlist_add_boolean_value(cs[i], "uah_en", 168 hash->uch_rm_hashes[i].uah_en); 169 } 170 fnvlist_add_nvlist_array(nvl, "uch_cs_hashes", cs, 171 ZEN_UMC_MAX_CHAN_CS_HASH); 172 173 for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_CS_HASH; i++) { 174 nvlist_free(cs[i]); 175 } 176 } 177 178 if (hash->uch_flags & UMC_CHAN_HASH_F_PC) { 179 nvlist_t *pc = fnvlist_alloc(); 180 181 fnvlist_add_uint32(pc, "uph_row_xor", 182 hash->uch_pc_hash.uph_row_xor); 183 fnvlist_add_uint32(pc, "uph_col_xor", 184 hash->uch_pc_hash.uph_col_xor); 185 fnvlist_add_uint8(pc, "uph_bank_xor", 186 hash->uch_pc_hash.uph_bank_xor); 187 fnvlist_add_boolean_value(pc, "uph_en", 188 hash->uch_pc_hash.uph_en); 189 190 fnvlist_add_nvlist(nvl, "uch_pch_hash", pc); 191 fnvlist_free(pc); 192 193 } 194 195 return (nvl); 196 } 197 198 static nvlist_t * 199 zen_umc_dump_chan(zen_umc_chan_t *chan) 200 { 201 nvlist_t *nvl, *hash; 202 nvlist_t *rules[ZEN_UMC_MAX_CS_RULES]; 203 nvlist_t *offsets[ZEN_UMC_MAX_DRAM_OFFSET]; 204 nvlist_t *dimms[ZEN_UMC_MAX_DIMMS]; 205 206 nvl = fnvlist_alloc(); 207 fnvlist_add_uint32(nvl, "chan_flags", chan->chan_flags); 208 fnvlist_add_uint32(nvl, "chan_fabid", chan->chan_fabid); 209 fnvlist_add_uint32(nvl, "chan_instid", chan->chan_instid); 210 fnvlist_add_uint32(nvl, "chan_logid", chan->chan_logid); 211 fnvlist_add_uint32(nvl, "chan_np2_space0", chan->chan_np2_space0); 212 fnvlist_add_uint32(nvl, "chan_type", chan->chan_type); 213 214 for (uint_t i = 0; i < chan->chan_nrules; i++) { 215 rules[i] = zen_umc_dump_dram_rule(&chan->chan_rules[i]); 216 } 217 218 for (uint_t i = 0; i < chan->chan_nrules - 1; i++) { 219 offsets[i] = fnvlist_alloc(); 220 fnvlist_add_boolean_value(offsets[i], "cho_valid", 221 chan->chan_offsets[i].cho_valid); 222 fnvlist_add_uint64(offsets[i], "cho_offset", 223 chan->chan_offsets[i].cho_offset); 224 } 225 226 for (uint_t i = 0; i < ZEN_UMC_MAX_DIMMS; i++) { 227 dimms[i] = zen_umc_dump_dimm(&chan->chan_dimms[i]); 228 } 229 230 fnvlist_add_nvlist_array(nvl, "chan_rules", rules, chan->chan_nrules); 231 fnvlist_add_nvlist_array(nvl, "chan_offsets", offsets, 232 chan->chan_nrules - 1); 233 fnvlist_add_nvlist_array(nvl, "chan_dimms", dimms, ZEN_UMC_MAX_DIMMS); 234 hash = zen_umc_dump_chan_hash(&chan->chan_hash); 235 fnvlist_add_nvlist(nvl, "chan_hash", hash); 236 237 for (uint_t i = 0; i < chan->chan_nrules; i++) { 238 nvlist_free(rules[i]); 239 } 240 241 for (uint_t i = 0; i < chan->chan_nrules - 1; i++) { 242 nvlist_free(offsets[i]); 243 } 244 245 for (uint_t i = 0; i < ZEN_UMC_MAX_DIMMS; i++) { 246 nvlist_free(dimms[i]); 247 } 248 249 nvlist_free(hash); 250 251 return (nvl); 252 } 253 254 static nvlist_t * 255 zen_umc_dump_df(zen_umc_df_t *df) 256 { 257 nvlist_t *nvl; 258 nvlist_t *rules[ZEN_UMC_MAX_DRAM_RULES]; 259 nvlist_t *remap[ZEN_UMC_MAX_CS_REMAPS]; 260 nvlist_t *chan[ZEN_UMC_MAX_UMCS]; 261 262 nvl = fnvlist_alloc(); 263 fnvlist_add_uint32(nvl, "zud_flags", df->zud_flags); 264 fnvlist_add_uint32(nvl, "zud_dfno", df->zud_dfno); 265 fnvlist_add_uint32(nvl, "zud_ccm_inst", df->zud_ccm_inst); 266 fnvlist_add_uint64(nvl, "zud_hole_base", df->zud_hole_base); 267 268 for (uint_t i = 0; i < df->zud_dram_nrules; i++) { 269 rules[i] = zen_umc_dump_dram_rule(&df->zud_rules[i]); 270 } 271 272 for (uint_t i = 0; i < df->zud_cs_nremap; i++) { 273 remap[i] = fnvlist_alloc(); 274 fnvlist_add_uint16_array(remap[i], "csr_remaps", 275 df->zud_remap[i].csr_remaps, df->zud_remap[i].csr_nremaps); 276 } 277 278 for (uint_t i = 0; i < df->zud_nchan; i++) { 279 chan[i] = zen_umc_dump_chan(&df->zud_chan[i]); 280 } 281 282 fnvlist_add_nvlist_array(nvl, "zud_rules", rules, df->zud_dram_nrules); 283 fnvlist_add_nvlist_array(nvl, "zud_remap", remap, df->zud_cs_nremap); 284 fnvlist_add_nvlist_array(nvl, "zud_chan", chan, df->zud_nchan); 285 286 for (uint_t i = 0; i < df->zud_dram_nrules; i++) { 287 nvlist_free(rules[i]); 288 } 289 290 for (uint_t i = 0; i < df->zud_cs_nremap; i++) { 291 nvlist_free(remap[i]); 292 } 293 294 for (uint_t i = 0; i < df->zud_nchan; i++) { 295 nvlist_free(chan[i]); 296 } 297 298 return (nvl); 299 } 300 301 nvlist_t * 302 zen_umc_dump_decoder(zen_umc_t *umc) 303 { 304 nvlist_t *nvl, *umc_nvl, *decomp; 305 nvlist_t *dfs[ZEN_UMC_MAX_DFS]; 306 307 nvl = fnvlist_alloc(); 308 fnvlist_add_uint32(nvl, "mc_dump_version", 0); 309 fnvlist_add_string(nvl, "mc_dump_driver", "zen_umc"); 310 311 umc_nvl = fnvlist_alloc(); 312 fnvlist_add_uint64(umc_nvl, "umc_tom", umc->umc_tom); 313 fnvlist_add_uint64(umc_nvl, "umc_tom2", umc->umc_tom2); 314 fnvlist_add_uint32(umc_nvl, "umc_family", umc->umc_family); 315 fnvlist_add_uint32(umc_nvl, "umc_df_rev", umc->umc_df_rev); 316 317 decomp = fnvlist_alloc(); 318 fnvlist_add_uint32(decomp, "dfd_sock_mask", 319 umc->umc_decomp.dfd_sock_mask); 320 fnvlist_add_uint32(decomp, "dfd_die_mask", 321 umc->umc_decomp.dfd_die_mask); 322 fnvlist_add_uint32(decomp, "dfd_node_mask", 323 umc->umc_decomp.dfd_node_mask); 324 fnvlist_add_uint32(decomp, "dfd_comp_mask", 325 umc->umc_decomp.dfd_comp_mask); 326 fnvlist_add_uint8(decomp, "dfd_sock_shift", 327 umc->umc_decomp.dfd_sock_shift); 328 fnvlist_add_uint8(decomp, "dfd_die_shift", 329 umc->umc_decomp.dfd_die_shift); 330 fnvlist_add_uint8(decomp, "dfd_node_shift", 331 umc->umc_decomp.dfd_node_shift); 332 fnvlist_add_uint8(decomp, "dfd_comp_shift", 333 umc->umc_decomp.dfd_comp_shift); 334 fnvlist_add_nvlist(umc_nvl, "umc_decomp", decomp); 335 nvlist_free(decomp); 336 337 for (uint_t i = 0; i < umc->umc_ndfs; i++) { 338 dfs[i] = zen_umc_dump_df(&umc->umc_dfs[i]); 339 } 340 341 fnvlist_add_nvlist_array(umc_nvl, "umc_dfs", dfs, umc->umc_ndfs); 342 fnvlist_add_nvlist(nvl, "zen_umc", umc_nvl); 343 for (uint_t i = 0; i < umc->umc_ndfs; i++) { 344 nvlist_free(dfs[i]); 345 } 346 347 return (nvl); 348 } 349 350 static boolean_t 351 zen_umc_restore_dram_rule(nvlist_t *nvl, df_dram_rule_t *rule) 352 { 353 return (nvlist_lookup_pairs(nvl, 0, 354 "ddr_flags", DATA_TYPE_UINT32, &rule->ddr_flags, 355 "ddr_base", DATA_TYPE_UINT64, &rule->ddr_base, 356 "ddr_limit", DATA_TYPE_UINT64, &rule->ddr_limit, 357 "ddr_dest_fabid", DATA_TYPE_UINT16, &rule->ddr_dest_fabid, 358 "ddr_sock_ileave_bits", DATA_TYPE_UINT8, 359 &rule->ddr_sock_ileave_bits, 360 "ddr_die_ileave_bits", DATA_TYPE_UINT8, &rule->ddr_die_ileave_bits, 361 "ddr_addr_start", DATA_TYPE_UINT8, &rule->ddr_addr_start, 362 "ddr_remap_ent", DATA_TYPE_UINT8, &rule->ddr_remap_ent, 363 "ddr_chan_ileave", DATA_TYPE_UINT32, &rule->ddr_chan_ileave, 364 NULL) == 0); 365 } 366 367 static boolean_t 368 zen_umc_restore_cs(nvlist_t *nvl, umc_cs_t *cs) 369 { 370 nvlist_t *base, *sec; 371 uint8_t *bank_bits, *col_bits, *rm_bits, *rm_bits_sec; 372 uint_t nbanks, ncols, nrm, nrm_sec; 373 374 if (nvlist_lookup_pairs(nvl, 0, 375 "ucs_flags", DATA_TYPE_UINT32, &cs->ucs_flags, 376 "ucs_base", DATA_TYPE_NVLIST, &base, 377 "ucs_sec", DATA_TYPE_NVLIST, &sec, 378 "ucs_base_mask", DATA_TYPE_UINT64, &cs->ucs_base_mask, 379 "ucs_sec_mask", DATA_TYPE_UINT64, &cs->ucs_sec_mask, 380 "ucs_nrow_lo", DATA_TYPE_UINT8, &cs->ucs_nrow_lo, 381 "ucs_nrow_hi", DATA_TYPE_UINT8, &cs->ucs_nrow_hi, 382 "ucs_nbank_groups", DATA_TYPE_UINT8, &cs->ucs_nbank_groups, 383 "ucs_cs_xor", DATA_TYPE_UINT8, &cs->ucs_cs_xor, 384 "ucs_row_hi_bit", DATA_TYPE_UINT8, &cs->ucs_row_hi_bit, 385 "ucs_row_low_bit", DATA_TYPE_UINT8, &cs->ucs_row_low_bit, 386 "ucs_bank_bits", DATA_TYPE_UINT8_ARRAY, &bank_bits, &nbanks, 387 "ucs_col_bits", DATA_TYPE_UINT8_ARRAY, &col_bits, &ncols, 388 "ucs_inv_msbs", DATA_TYPE_UINT8, &cs->ucs_inv_msbs, 389 "ucs_rm_bits", DATA_TYPE_UINT8_ARRAY, &rm_bits, &nrm, 390 "ucs_inv_msbs_sec", DATA_TYPE_UINT8, &cs->ucs_inv_msbs_sec, 391 "ucs_rm_bits_sec", DATA_TYPE_UINT8_ARRAY, &rm_bits_sec, &nrm_sec, 392 "ucs_subchan", DATA_TYPE_UINT8, &cs->ucs_subchan, 393 NULL) != 0) { 394 return (B_FALSE); 395 } 396 397 if (nbanks > ZEN_UMC_MAX_BANK_BITS || 398 ncols > ZEN_UMC_MAX_COL_BITS || 399 nrm > ZEN_UMC_MAX_RM_BITS || 400 nrm != nrm_sec) { 401 return (B_FALSE); 402 } 403 404 cs->ucs_nbanks = nbanks; 405 cs->ucs_ncol = ncols; 406 cs->ucs_nrm = nrm; 407 408 bcopy(bank_bits, cs->ucs_bank_bits, cs->ucs_nbanks * 409 sizeof (uint8_t)); 410 bcopy(col_bits, cs->ucs_col_bits, cs->ucs_ncol * sizeof (uint8_t)); 411 bcopy(rm_bits, cs->ucs_rm_bits, cs->ucs_nrm * sizeof (uint8_t)); 412 bcopy(rm_bits_sec, cs->ucs_rm_bits_sec, cs->ucs_nrm * 413 sizeof (uint8_t)); 414 415 if (nvlist_lookup_pairs(base, 0, 416 "udb_base", DATA_TYPE_UINT64, &cs->ucs_base.udb_base, 417 "udb_valid", DATA_TYPE_UINT8, &cs->ucs_base.udb_valid, 418 NULL) != 0) { 419 return (B_FALSE); 420 } 421 422 if (nvlist_lookup_pairs(sec, 0, 423 "udb_base", DATA_TYPE_UINT64, &cs->ucs_sec.udb_base, 424 "udb_valid", DATA_TYPE_UINT8, &cs->ucs_sec.udb_valid, 425 NULL) != 0) { 426 return (B_FALSE); 427 } 428 429 return (B_TRUE); 430 } 431 432 static boolean_t 433 zen_umc_restore_dimm(nvlist_t *nvl, umc_dimm_t *dimm) 434 { 435 nvlist_t **cs; 436 uint_t ncs; 437 438 if (nvlist_lookup_pairs(nvl, 0, 439 "ud_flags", DATA_TYPE_UINT32, &dimm->ud_flags, 440 "ud_width", DATA_TYPE_UINT32, &dimm->ud_width, 441 "ud_kind", DATA_TYPE_UINT32, &dimm->ud_kind, 442 "ud_dimmno", DATA_TYPE_UINT32, &dimm->ud_dimmno, 443 "ud_cs", DATA_TYPE_NVLIST_ARRAY, &cs, &ncs, 444 NULL) != 0) { 445 return (B_FALSE); 446 } 447 448 if (ncs != ZEN_UMC_MAX_CS_PER_DIMM) { 449 return (B_FALSE); 450 } 451 452 for (uint_t i = 0; i < ZEN_UMC_MAX_CS_PER_DIMM; i++) { 453 if (!zen_umc_restore_cs(cs[i], &dimm->ud_cs[i])) { 454 return (B_FALSE); 455 } 456 } 457 458 return (B_TRUE); 459 } 460 461 static boolean_t 462 zen_umc_restore_hash(nvlist_t *nvl, umc_chan_hash_t *hash) 463 { 464 if (nvlist_lookup_uint32(nvl, "uch_flags", &hash->uch_flags) != 0) { 465 return (B_FALSE); 466 } 467 468 if (hash->uch_flags & UMC_CHAN_HASH_F_BANK) { 469 nvlist_t **banks; 470 uint_t nbanks; 471 472 if (nvlist_lookup_nvlist_array(nvl, "uch_bank_hashes", &banks, 473 &nbanks) != 0) { 474 return (B_FALSE); 475 } 476 477 if (nbanks != ZEN_UMC_MAX_CHAN_BANK_HASH) { 478 return (B_FALSE); 479 } 480 481 for (uint_t i = 0; i < nbanks; i++) { 482 if (nvlist_lookup_pairs(banks[i], 0, 483 "ubh_row_xor", DATA_TYPE_UINT32, 484 &hash->uch_bank_hashes[i].ubh_row_xor, 485 "ubh_col_xor", DATA_TYPE_UINT32, 486 &hash->uch_bank_hashes[i].ubh_col_xor, 487 "ubh_en", DATA_TYPE_BOOLEAN_VALUE, 488 &hash->uch_bank_hashes[i].ubh_en, 489 NULL) != 0) { 490 return (B_FALSE); 491 } 492 } 493 } 494 495 if (hash->uch_flags & UMC_CHAN_HASH_F_RM) { 496 nvlist_t **rm; 497 uint_t nrm; 498 499 if (nvlist_lookup_nvlist_array(nvl, "uch_rm_hashes", &rm, 500 &nrm) != 0) { 501 return (B_FALSE); 502 } 503 504 if (nrm != ZEN_UMC_MAX_CHAN_RM_HASH) { 505 return (B_FALSE); 506 } 507 508 for (uint_t i = 0; i < nrm; i++) { 509 if (nvlist_lookup_pairs(rm[i], 0, 510 "uah_addr_xor", DATA_TYPE_UINT64, 511 &hash->uch_rm_hashes[i].uah_addr_xor, 512 "uah_en", DATA_TYPE_BOOLEAN_VALUE, 513 &hash->uch_rm_hashes[i].uah_en, 514 NULL) != 0) { 515 return (B_FALSE); 516 } 517 } 518 } 519 520 if (hash->uch_flags & UMC_CHAN_HASH_F_CS) { 521 nvlist_t **cs; 522 uint_t ncs; 523 524 if (nvlist_lookup_nvlist_array(nvl, "uch_cs_hashes", &cs, 525 &ncs) != 0) { 526 return (B_FALSE); 527 } 528 529 if (ncs != ZEN_UMC_MAX_CHAN_CS_HASH) { 530 return (B_FALSE); 531 } 532 533 for (uint_t i = 0; i < ncs; i++) { 534 if (nvlist_lookup_pairs(cs[i], 0, 535 "uah_addr_xor", DATA_TYPE_UINT64, 536 &hash->uch_cs_hashes[i].uah_addr_xor, 537 "uah_en", DATA_TYPE_BOOLEAN_VALUE, 538 &hash->uch_cs_hashes[i].uah_en, 539 NULL) != 0) { 540 return (B_FALSE); 541 } 542 } 543 } 544 545 if (hash->uch_flags & UMC_CHAN_HASH_F_PC) { 546 nvlist_t *pc; 547 548 if (nvlist_lookup_nvlist(nvl, "uch_pch_hash", &pc) != 0) { 549 return (B_FALSE); 550 } 551 552 if (nvlist_lookup_pairs(pc, 0, 553 "uph_row_xor", DATA_TYPE_UINT32, 554 &hash->uch_pc_hash.uph_row_xor, 555 "uph_col_xor", DATA_TYPE_UINT32, 556 &hash->uch_pc_hash.uph_col_xor, 557 "uph_bank_xor", DATA_TYPE_UINT32, 558 &hash->uch_pc_hash.uph_bank_xor, 559 "uph_en", DATA_TYPE_BOOLEAN_VALUE, 560 &hash->uch_pc_hash.uph_en, 561 NULL) != 0) { 562 return (B_FALSE); 563 } 564 } 565 return (B_TRUE); 566 } 567 568 static boolean_t 569 zen_umc_restore_chan(nvlist_t *nvl, zen_umc_chan_t *chan) 570 { 571 uint_t noffsets, ndimms; 572 nvlist_t **rules, **offsets, **dimms, *hash; 573 574 if (nvlist_lookup_pairs(nvl, 0, 575 "chan_flags", DATA_TYPE_UINT32, &chan->chan_flags, 576 "chan_fabid", DATA_TYPE_UINT32, &chan->chan_fabid, 577 "chan_instid", DATA_TYPE_UINT32, &chan->chan_instid, 578 "chan_logid", DATA_TYPE_UINT32, &chan->chan_logid, 579 "chan_rules", DATA_TYPE_NVLIST_ARRAY, &rules, &chan->chan_nrules, 580 "chan_np2_space0", DATA_TYPE_UINT32, &chan->chan_np2_space0, 581 "chan_type", DATA_TYPE_UINT32, &chan->chan_np2_space0, 582 "chan_offsets", DATA_TYPE_NVLIST_ARRAY, &offsets, &noffsets, 583 "chan_dimms", DATA_TYPE_NVLIST_ARRAY, &dimms, &ndimms, 584 "chan_hash", DATA_TYPE_NVLIST, &hash, 585 NULL) != 0) { 586 return (B_FALSE); 587 } 588 589 if (chan->chan_nrules > ZEN_UMC_MAX_CS_RULES || 590 noffsets != chan->chan_nrules - 1 || ndimms != ZEN_UMC_MAX_DIMMS) { 591 return (B_FALSE); 592 } 593 594 for (uint_t i = 0; i < chan->chan_nrules; i++) { 595 if (!zen_umc_restore_dram_rule(rules[i], 596 &chan->chan_rules[i])) { 597 return (B_FALSE); 598 } 599 } 600 601 for (uint_t i = 0; i < chan->chan_nrules - 1; i++) { 602 chan_offset_t *coff = &chan->chan_offsets[i]; 603 604 if (nvlist_lookup_pairs(offsets[i], 0, 605 "cho_valid", DATA_TYPE_BOOLEAN_VALUE, &coff->cho_valid, 606 "cho_offset", DATA_TYPE_UINT64, &coff->cho_offset, 607 NULL) != 0) { 608 return (B_FALSE); 609 } 610 } 611 612 for (uint_t i = 0; i < ZEN_UMC_MAX_DIMMS; i++) { 613 if (!zen_umc_restore_dimm(dimms[i], &chan->chan_dimms[i])) { 614 return (B_FALSE); 615 } 616 } 617 618 if (!zen_umc_restore_hash(hash, &chan->chan_hash)) { 619 return (B_FALSE); 620 } 621 622 return (B_TRUE); 623 } 624 625 static boolean_t 626 zen_umc_restore_df(nvlist_t *nvl, zen_umc_df_t *df) 627 { 628 nvlist_t **rules, **chan, **remap; 629 630 if (nvlist_lookup_pairs(nvl, 0, 631 "zud_flags", DATA_TYPE_UINT32, &df->zud_flags, 632 "zud_dfno", DATA_TYPE_UINT32, &df->zud_dfno, 633 "zud_ccm_inst", DATA_TYPE_UINT32, &df->zud_ccm_inst, 634 "zud_hole_base", DATA_TYPE_UINT64, &df->zud_hole_base, 635 "zud_rules", DATA_TYPE_NVLIST_ARRAY, &rules, &df->zud_dram_nrules, 636 "zud_remap", DATA_TYPE_NVLIST_ARRAY, &remap, &df->zud_cs_nremap, 637 "zud_chan", DATA_TYPE_NVLIST_ARRAY, &chan, &df->zud_nchan, 638 NULL != 0) || 639 df->zud_dram_nrules > ZEN_UMC_MAX_DRAM_RULES || 640 df->zud_cs_nremap > ZEN_UMC_MAX_CS_REMAPS || 641 df->zud_nchan > ZEN_UMC_MAX_UMCS) { 642 return (B_FALSE); 643 } 644 645 for (uint_t i = 0; i < df->zud_dram_nrules; i++) { 646 if (!zen_umc_restore_dram_rule(rules[i], &df->zud_rules[i])) { 647 return (B_FALSE); 648 } 649 } 650 651 for (uint_t i = 0; i < df->zud_cs_nremap; i++) { 652 uint16_t *u16p; 653 if (nvlist_lookup_uint16_array(remap[i], "csr_remaps", &u16p, 654 &df->zud_remap[i].csr_nremaps) != 0 || 655 df->zud_remap[i].csr_nremaps > ZEN_UMC_MAX_REMAP_ENTS) { 656 return (B_FALSE); 657 } 658 bcopy(u16p, df->zud_remap[i].csr_remaps, 659 df->zud_remap[i].csr_nremaps); 660 } 661 662 for (uint_t i = 0; i < df->zud_nchan; i++) { 663 if (!zen_umc_restore_chan(chan[i], &df->zud_chan[i])) { 664 return (B_FALSE); 665 } 666 } 667 668 return (B_TRUE); 669 } 670 671 boolean_t 672 zen_umc_restore_decoder(nvlist_t *nvl, zen_umc_t *umc) 673 { 674 uint32_t vers; 675 char *driver; 676 nvlist_t *umc_nvl, *decomp, **dfs; 677 bzero(umc, sizeof (zen_umc_t)); 678 679 if (nvlist_lookup_pairs(nvl, 0, 680 "mc_dump_version", DATA_TYPE_UINT32, &vers, 681 "mc_dump_driver", DATA_TYPE_STRING, &driver, 682 NULL) != 0 || vers != 0 || strcmp(driver, "zen_umc") != 0 || 683 nvlist_lookup_nvlist(nvl, "zen_umc", &umc_nvl) != 0) { 684 return (B_FALSE); 685 } 686 687 if (nvlist_lookup_pairs(umc_nvl, 0, 688 "umc_tom", DATA_TYPE_UINT64, &umc->umc_tom, 689 "umc_tom2", DATA_TYPE_UINT64, &umc->umc_tom2, 690 "umc_family", DATA_TYPE_UINT32, &umc->umc_family, 691 "umc_df_rev", DATA_TYPE_UINT32, &umc->umc_df_rev, 692 "umc_decomp", DATA_TYPE_NVLIST, &decomp, 693 "umc_dfs", DATA_TYPE_NVLIST_ARRAY, &dfs, &umc->umc_ndfs, 694 NULL) != 0 || umc->umc_ndfs > ZEN_UMC_MAX_DFS) { 695 return (B_FALSE); 696 } 697 698 699 if (nvlist_lookup_pairs(decomp, 0, 700 "dfd_sock_mask", DATA_TYPE_UINT32, &umc->umc_decomp.dfd_sock_mask, 701 "dfd_die_mask", DATA_TYPE_UINT32, &umc->umc_decomp.dfd_die_mask, 702 "dfd_node_mask", DATA_TYPE_UINT32, &umc->umc_decomp.dfd_node_mask, 703 "dfd_comp_mask", DATA_TYPE_UINT32, &umc->umc_decomp.dfd_comp_mask, 704 "dfd_sock_shift", DATA_TYPE_UINT8, &umc->umc_decomp.dfd_sock_shift, 705 "dfd_die_shift", DATA_TYPE_UINT8, &umc->umc_decomp.dfd_die_shift, 706 "dfd_node_shift", DATA_TYPE_UINT8, &umc->umc_decomp.dfd_node_shift, 707 "dfd_comp_shift", DATA_TYPE_UINT8, &umc->umc_decomp.dfd_comp_shift, 708 NULL) != 0) { 709 return (B_FALSE); 710 } 711 712 for (uint_t i = 0; i < umc->umc_ndfs; i++) { 713 if (!zen_umc_restore_df(dfs[i], &umc->umc_dfs[i])) { 714 return (B_FALSE); 715 } 716 } 717 718 return (B_TRUE); 719 } 720