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 2022 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_type", dimm->ud_type); 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 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_type", DATA_TYPE_UINT32, &dimm->ud_type, 440 "ud_kind", DATA_TYPE_UINT32, &dimm->ud_kind, 441 "ud_dimmno", DATA_TYPE_UINT32, &dimm->ud_dimmno, 442 "ud_cs", DATA_TYPE_NVLIST_ARRAY, &cs, &ncs, 443 NULL) != 0) { 444 return (B_FALSE); 445 } 446 447 if (ncs != ZEN_UMC_MAX_CS_PER_DIMM) { 448 return (B_FALSE); 449 } 450 451 for (uint_t i = 0; i < ZEN_UMC_MAX_CS_PER_DIMM; i++) { 452 if (!zen_umc_restore_cs(cs[i], &dimm->ud_cs[i])) { 453 return (B_FALSE); 454 } 455 } 456 457 return (B_TRUE); 458 } 459 460 static boolean_t 461 zen_umc_restore_hash(nvlist_t *nvl, umc_chan_hash_t *hash) 462 { 463 if (nvlist_lookup_uint32(nvl, "uch_flags", &hash->uch_flags) != 0) { 464 return (B_FALSE); 465 } 466 467 if (hash->uch_flags & UMC_CHAN_HASH_F_BANK) { 468 nvlist_t **banks; 469 uint_t nbanks; 470 471 if (nvlist_lookup_nvlist_array(nvl, "uch_bank_hashes", &banks, 472 &nbanks) != 0) { 473 return (B_FALSE); 474 } 475 476 if (nbanks != ZEN_UMC_MAX_CHAN_BANK_HASH) { 477 return (B_FALSE); 478 } 479 480 for (uint_t i = 0; i < nbanks; i++) { 481 if (nvlist_lookup_pairs(banks[i], 0, 482 "ubh_row_xor", DATA_TYPE_UINT32, 483 &hash->uch_bank_hashes[i].ubh_row_xor, 484 "ubh_col_xor", DATA_TYPE_UINT32, 485 &hash->uch_bank_hashes[i].ubh_col_xor, 486 "ubh_en", DATA_TYPE_BOOLEAN_VALUE, 487 &hash->uch_bank_hashes[i].ubh_en, 488 NULL) != 0) { 489 return (B_FALSE); 490 } 491 } 492 } 493 494 if (hash->uch_flags & UMC_CHAN_HASH_F_RM) { 495 nvlist_t **rm; 496 uint_t nrm; 497 498 if (nvlist_lookup_nvlist_array(nvl, "uch_rm_hashes", &rm, 499 &nrm) != 0) { 500 return (B_FALSE); 501 } 502 503 if (nrm != ZEN_UMC_MAX_CHAN_RM_HASH) { 504 return (B_FALSE); 505 } 506 507 for (uint_t i = 0; i < nrm; i++) { 508 if (nvlist_lookup_pairs(rm[i], 0, 509 "uah_addr_xor", DATA_TYPE_UINT64, 510 &hash->uch_rm_hashes[i].uah_addr_xor, 511 "uah_en", DATA_TYPE_BOOLEAN_VALUE, 512 &hash->uch_rm_hashes[i].uah_en, 513 NULL) != 0) { 514 return (B_FALSE); 515 } 516 } 517 } 518 519 if (hash->uch_flags & UMC_CHAN_HASH_F_CS) { 520 nvlist_t **cs; 521 uint_t ncs; 522 523 if (nvlist_lookup_nvlist_array(nvl, "uch_cs_hashes", &cs, 524 &ncs) != 0) { 525 return (B_FALSE); 526 } 527 528 if (ncs != ZEN_UMC_MAX_CHAN_CS_HASH) { 529 return (B_FALSE); 530 } 531 532 for (uint_t i = 0; i < ncs; i++) { 533 if (nvlist_lookup_pairs(cs[i], 0, 534 "uah_addr_xor", DATA_TYPE_UINT64, 535 &hash->uch_cs_hashes[i].uah_addr_xor, 536 "uah_en", DATA_TYPE_BOOLEAN_VALUE, 537 &hash->uch_cs_hashes[i].uah_en, 538 NULL) != 0) { 539 return (B_FALSE); 540 } 541 } 542 } 543 544 if (hash->uch_flags & UMC_CHAN_HASH_F_PC) { 545 nvlist_t *pc; 546 547 if (nvlist_lookup_nvlist(nvl, "uch_pch_hash", &pc) != 0) { 548 return (B_FALSE); 549 } 550 551 if (nvlist_lookup_pairs(pc, 0, 552 "uph_row_xor", DATA_TYPE_UINT32, 553 &hash->uch_pc_hash.uph_row_xor, 554 "uph_col_xor", DATA_TYPE_UINT32, 555 &hash->uch_pc_hash.uph_col_xor, 556 "uph_bank_xor", DATA_TYPE_UINT32, 557 &hash->uch_pc_hash.uph_bank_xor, 558 "uph_en", DATA_TYPE_BOOLEAN_VALUE, 559 &hash->uch_pc_hash.uph_en, 560 NULL) != 0) { 561 return (B_FALSE); 562 } 563 } 564 return (B_TRUE); 565 } 566 567 static boolean_t 568 zen_umc_restore_chan(nvlist_t *nvl, zen_umc_chan_t *chan) 569 { 570 uint_t noffsets, ndimms; 571 nvlist_t **rules, **offsets, **dimms, *hash; 572 573 if (nvlist_lookup_pairs(nvl, 0, 574 "chan_flags", DATA_TYPE_UINT32, &chan->chan_flags, 575 "chan_fabid", DATA_TYPE_UINT32, &chan->chan_fabid, 576 "chan_instid", DATA_TYPE_UINT32, &chan->chan_instid, 577 "chan_logid", DATA_TYPE_UINT32, &chan->chan_logid, 578 "chan_rules", DATA_TYPE_NVLIST_ARRAY, &rules, &chan->chan_nrules, 579 "chan_np2_space0", 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