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