1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Stub routines used to link in files from $SRC/common/mc 29 */ 30 31 #include <sys/types.h> 32 #include <sys/cmn_err.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/varargs.h> 36 #include <sys/fm/util.h> 37 #include <sys/fm/cpu/AMD.h> 38 #include <sys/fm/protocol.h> 39 #include <sys/mc.h> 40 41 #include <mcamd.h> 42 #include <mcamd_off.h> 43 44 int mcamd_debug = 0; /* see mcamd_api.h for MCAMD_DBG_* values */ 45 46 struct mc_offmap { 47 int mcom_code; 48 uint_t mcom_offset; 49 }; 50 51 static uint_t 52 nodetype(mcamd_node_t *node) 53 { 54 mc_hdr_t *mch = (mc_hdr_t *)node; 55 return (mch->mch_type); 56 } 57 58 static void * 59 node2type(mcamd_node_t *node, int type) 60 { 61 mc_hdr_t *mch = (mc_hdr_t *)node; 62 ASSERT(mch->mch_type == type); 63 return (mch); 64 } 65 66 /* 67 * Iterate over all memory controllers. 68 */ 69 /*ARGSUSED*/ 70 mcamd_node_t * 71 mcamd_mc_next(mcamd_hdl_t *hdl, mcamd_node_t *root, mcamd_node_t *last) 72 { 73 mc_t *mc; 74 75 ASSERT(RW_LOCK_HELD(&mc_lock)); 76 77 if (last == NULL) 78 return ((mcamd_node_t *)mc_list); 79 80 mc = node2type(last, MC_NT_MC); 81 82 return ((mcamd_node_t *)mc->mc_next); 83 } 84 85 /* 86 * Iterate over all chip-selects of a MC or all chip-selects of a DIMM 87 * depending on the node type of 'node'. In the DIMM case we do not 88 * have a linked list of associated chip-selects but an array of pointer 89 * to them. 90 */ 91 /*ARGSUSED*/ 92 mcamd_node_t * 93 mcamd_cs_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last) 94 { 95 uint_t nt = nodetype(node); 96 mc_t *mc; 97 mc_cs_t *mccs; 98 mc_dimm_t *mcd; 99 int i; 100 void *retval; 101 102 ASSERT(nt == MC_NT_MC || nt == MC_NT_DIMM); 103 104 if (last == NULL) { 105 switch (nt) { 106 case MC_NT_MC: 107 mc = node2type(node, MC_NT_MC); 108 retval = mc->mc_cslist; 109 break; 110 case MC_NT_DIMM: 111 mcd = node2type(node, MC_NT_DIMM); 112 retval = mcd->mcd_cs[0]; 113 break; 114 } 115 } else { 116 mccs = node2type(last, MC_NT_CS); 117 118 switch (nt) { 119 case MC_NT_MC: 120 retval = mccs->mccs_next; 121 break; 122 case MC_NT_DIMM: 123 mcd = node2type(node, MC_NT_DIMM); 124 for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { 125 if (mcd->mcd_cs[i] == mccs) 126 break; 127 } 128 if (i == MC_CHIP_DIMMRANKMAX) 129 cmn_err(CE_PANIC, "Bad last value for " 130 "mcamd_cs_next"); 131 132 if (i == MC_CHIP_DIMMRANKMAX - 1) 133 retval = NULL; 134 else 135 retval = mcd->mcd_cs[i + 1]; 136 break; 137 } 138 } 139 140 return ((mcamd_node_t *)retval); 141 } 142 143 /* 144 * Iterate over all DIMMs of an MC or all DIMMs of a chip-select depending 145 * on the node type of 'node'. In the chip-select case we do not have 146 * a linked list of associated DIMMs but an array of pointers to them. 147 */ 148 /*ARGSUSED*/ 149 mcamd_node_t * 150 mcamd_dimm_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last) 151 { 152 uint_t nt = nodetype(node); 153 mc_t *mc; 154 mc_cs_t *mccs; 155 mc_dimm_t *mcd; 156 int i; 157 void *retval; 158 159 ASSERT(nt == MC_NT_MC || nt == MC_NT_CS); 160 161 if (last == NULL) { 162 switch (nt) { 163 case MC_NT_MC: 164 mc = node2type(node, MC_NT_MC); 165 retval = mc->mc_dimmlist; 166 break; 167 case MC_NT_CS: 168 mccs = node2type(node, MC_NT_CS); 169 retval = mccs->mccs_dimm[0]; 170 break; 171 } 172 } else { 173 mcd = node2type(last, MC_NT_DIMM); 174 175 switch (nt) { 176 case MC_NT_MC: 177 retval = mcd->mcd_next; 178 break; 179 case MC_NT_CS: 180 mccs = node2type(node, MC_NT_CS); 181 for (i = 0; i < MC_CHIP_DIMMPERCS; i++) { 182 if (mccs->mccs_dimm[i] == mcd) 183 break; 184 } 185 if (i == MC_CHIP_DIMMPERCS) 186 cmn_err(CE_PANIC, "Bad last value for " 187 "mcamd_dimm_next"); 188 189 if (i == MC_CHIP_DIMMPERCS - 1) 190 retval = NULL; 191 else 192 retval = mccs->mccs_dimm[i + 1]; 193 break; 194 } 195 } 196 197 return ((mcamd_node_t *)retval); 198 } 199 200 /*ARGSUSED*/ 201 mcamd_node_t * 202 mcamd_cs_mc(mcamd_hdl_t *hdl, mcamd_node_t *csnode) 203 { 204 mc_cs_t *mccs = node2type(csnode, MC_NT_CS); 205 return ((mcamd_node_t *)mccs->mccs_mc); 206 } 207 208 /*ARGSUSED*/ 209 mcamd_node_t * 210 mcamd_dimm_mc(mcamd_hdl_t *hdl, mcamd_node_t *dnode) 211 { 212 mc_dimm_t *mcd = node2type(dnode, MC_NT_DIMM); 213 return ((mcamd_node_t *)mcd->mcd_mc); 214 } 215 216 /* 217 * Node properties. A property is accessed through a property number code; 218 * we search these tables for a match (choosing table from node type) and 219 * return the uint64_t property at the indicated offset into the node 220 * structure. All properties must be of type uint64_t. It is assumed that 221 * property lookup does not have to be super-fast - we search linearly 222 * down the (small) lists. 223 */ 224 static const struct mc_offmap mcamd_mc_offmap[] = { 225 { MCAMD_PROP_NUM, MCAMD_MC_OFF_NUM }, 226 { MCAMD_PROP_REV, MCAMD_MC_OFF_REV }, 227 { MCAMD_PROP_BASE_ADDR, MCAMD_MC_OFF_BASE_ADDR }, 228 { MCAMD_PROP_LIM_ADDR, MCAMD_MC_OFF_LIM_ADDR }, 229 { MCAMD_PROP_ILEN, MCAMD_MC_OFF_ILEN }, 230 { MCAMD_PROP_ILSEL, MCAMD_MC_OFF_ILSEL }, 231 { MCAMD_PROP_CSINTLVFCTR, MCAMD_MC_OFF_CSINTLVFCTR }, 232 { MCAMD_PROP_DRAMHOLE_SIZE, MCAMD_MC_OFF_DRAMHOLE_SIZE }, 233 { MCAMD_PROP_ACCESS_WIDTH, MCAMD_MC_OFF_ACCWIDTH }, 234 { MCAMD_PROP_CSBANKMAPREG, MCAMD_MC_OFF_CSBANKMAPREG }, 235 { MCAMD_PROP_BANKSWZL, MCAMD_MC_OFF_BNKSWZL }, 236 { MCAMD_PROP_MOD64MUX, MCAMD_MC_OFF_MOD64MUX }, 237 { MCAMD_PROP_SPARECS, MCAMD_MC_OFF_SPARECS }, 238 { MCAMD_PROP_BADCS, MCAMD_MC_OFF_BADCS }, 239 }; 240 241 static const struct mc_offmap mcamd_cs_offmap[] = { 242 { MCAMD_PROP_NUM, MCAMD_CS_OFF_NUM }, 243 { MCAMD_PROP_BASE_ADDR, MCAMD_CS_OFF_BASE_ADDR }, 244 { MCAMD_PROP_MASK, MCAMD_CS_OFF_MASK }, 245 { MCAMD_PROP_SIZE, MCAMD_CS_OFF_SIZE }, 246 { MCAMD_PROP_CSBE, MCAMD_CS_OFF_CSBE }, 247 { MCAMD_PROP_SPARE, MCAMD_CS_OFF_SPARE }, 248 { MCAMD_PROP_TESTFAIL, MCAMD_CS_OFF_TESTFAIL }, 249 { MCAMD_PROP_CSDIMM1, MCAMD_CS_OFF_DIMMNUMS }, 250 { MCAMD_PROP_CSDIMM2, MCAMD_CS_OFF_DIMMNUMS + 251 MCAMD_CS_OFF_DIMMNUMS_INCR }, 252 { MCAMD_PROP_DIMMRANK, MCAMD_CS_OFF_DIMMRANK }, 253 }; 254 255 static const struct mc_offmap mcamd_dimm_offmap[] = { 256 { MCAMD_PROP_NUM, MCAMD_DIMM_OFF_NUM }, 257 { MCAMD_PROP_SIZE, MCAMD_DIMM_OFF_SIZE }, 258 }; 259 260 struct nt_offmap { 261 const struct mc_offmap *omp; 262 int mapents; 263 }; 264 265 /*ARGSUSED*/ 266 static int 267 findoffset(mcamd_hdl_t *hdl, mcamd_node_t *node, struct nt_offmap *arr, 268 int code, uint_t *offset) 269 { 270 int i; 271 mc_hdr_t *mch = (mc_hdr_t *)node; 272 int nt = mch->mch_type; 273 const struct mc_offmap *omp; 274 275 if (nt > MC_NT_NTYPES || (omp = arr[nt].omp) == NULL) 276 return (0); 277 278 for (i = 0; i < arr[nt].mapents; i++, omp++) { 279 if (omp->mcom_code == code) { 280 *offset = omp->mcom_offset; 281 return (1); 282 } 283 } 284 285 return (0); 286 } 287 288 /*ARGSUSED*/ 289 int 290 mcamd_get_numprop(mcamd_hdl_t *hdl, mcamd_node_t *node, 291 mcamd_propcode_t code, mcamd_prop_t *valp) 292 { 293 int found; 294 uint_t offset; 295 296 struct nt_offmap props[] = { 297 { mcamd_mc_offmap, /* MC_NT_MC */ 298 sizeof (mcamd_mc_offmap) / sizeof (struct mc_offmap) }, 299 { mcamd_cs_offmap, /* MC_NT_CS */ 300 sizeof (mcamd_cs_offmap) / sizeof (struct mc_offmap) }, 301 { mcamd_dimm_offmap, /* MC_NT_DIMM */ 302 sizeof (mcamd_dimm_offmap) / sizeof (struct mc_offmap) } 303 }; 304 305 found = findoffset(hdl, node, &props[0], code, &offset); 306 ASSERT(found); 307 308 if (found) 309 *valp = *(uint64_t *)((uintptr_t)node + offset); 310 311 return (found == 1); 312 } 313 314 int 315 mcamd_get_numprops(mcamd_hdl_t *hdl, ...) 316 { 317 va_list ap; 318 mcamd_node_t *node; 319 mcamd_propcode_t code; 320 mcamd_prop_t *valp; 321 322 va_start(ap, hdl); 323 while ((node = va_arg(ap, mcamd_node_t *)) != NULL) { 324 code = va_arg(ap, mcamd_propcode_t); 325 valp = va_arg(ap, mcamd_prop_t *); 326 if (!mcamd_get_numprop(hdl, node, code, valp)) 327 return (0); 328 } 329 va_end(ap); 330 return (1); 331 } 332 333 static const struct mc_offmap mcreg_offmap[] = { 334 { MCAMD_REG_DRAMBASE, MCAMD_MC_OFF_DRAMBASE_REG }, 335 { MCAMD_REG_DRAMLIMIT, MCAMD_MC_OFF_DRAMLIMIT_REG }, 336 { MCAMD_REG_DRAMHOLE, MCAMD_MC_OFF_DRAMHOLE_REG }, 337 { MCAMD_REG_DRAMCFGLO, MCAMD_MC_OFF_DRAMCFGLO_REG }, 338 { MCAMD_REG_DRAMCFGHI, MCAMD_MC_OFF_DRAMCFGHI_REG }, 339 }; 340 341 static const struct mc_offmap csreg_offmap[] = { 342 { MCAMD_REG_CSBASE, MCAMD_CS_OFF_CSBASE_REG }, 343 { MCAMD_REG_CSMASK, MCAMD_CS_OFF_CSMASK_REG }, 344 }; 345 346 /*ARGSUSED*/ 347 int 348 mcamd_get_cfgreg(struct mcamd_hdl *hdl, mcamd_node_t *node, 349 mcamd_regcode_t code, uint32_t *valp) 350 { 351 int found; 352 uint_t offset; 353 354 struct nt_offmap regs[] = { 355 { mcreg_offmap, /* MC_NT_MC */ 356 sizeof (mcreg_offmap) / sizeof (struct mc_offmap) }, 357 { csreg_offmap, /* MC_NT_CS */ 358 sizeof (csreg_offmap) / sizeof (struct mc_offmap) }, 359 { NULL, 0 } /* MC_NT_DIMM */ 360 }; 361 362 found = findoffset(hdl, node, ®s[0], code, &offset); 363 ASSERT(found); 364 365 ASSERT(found); 366 if (found) 367 *valp = *(uint32_t *)((uintptr_t)node + offset); 368 369 return (found == 1); 370 } 371 372 int 373 mcamd_get_cfgregs(mcamd_hdl_t *hdl, ...) 374 { 375 va_list ap; 376 mcamd_node_t *node; 377 mcamd_regcode_t code; 378 uint32_t *valp; 379 380 va_start(ap, hdl); 381 while ((node = va_arg(ap, mcamd_node_t *)) != NULL) { 382 code = va_arg(ap, mcamd_regcode_t); 383 valp = va_arg(ap, uint32_t *); 384 if (!mcamd_get_cfgreg(hdl, node, code, valp)) 385 return (0); 386 } 387 va_end(ap); 388 return (1); 389 } 390 391 392 int 393 mcamd_errno(mcamd_hdl_t *mcamd) 394 { 395 return (mcamd->mcamd_errno); 396 } 397 398 int 399 mcamd_set_errno(mcamd_hdl_t *mcamd, int err) 400 { 401 mcamd->mcamd_errno = err; 402 return (-1); 403 } 404 405 void 406 mcamd_dprintf(mcamd_hdl_t *mcamd, int mask, const char *fmt, ...) 407 { 408 va_list ap; 409 410 if (!(mcamd->mcamd_debug & mask)) 411 return; 412 413 va_start(ap, fmt); 414 vcmn_err(mask & MCAMD_DBG_ERR ? CE_WARN : CE_NOTE, fmt, ap); 415 va_end(ap); 416 } 417 418 void 419 mcamd_mkhdl(mcamd_hdl_t *hdl) 420 { 421 hdl->mcamd_errno = 0; 422 hdl->mcamd_debug = mcamd_debug; 423 } 424 425 cmi_errno_t 426 mcamd_cmierr(int err, mcamd_hdl_t *hdl) 427 { 428 if (err == 0) 429 return (CMI_SUCCESS); 430 431 switch (mcamd_errno(hdl)) { 432 case EMCAMD_SYNDINVALID: 433 return (CMIERR_MC_SYNDROME); 434 435 case EMCAMD_TREEINVALID: 436 return (CMIERR_MC_BADSTATE); 437 438 case EMCAMD_NOADDR: 439 return (CMIERR_MC_NOADDR); 440 441 case EMCAMD_INSUFF_RES: 442 return (CMIERR_MC_ADDRBITS); 443 444 default: 445 return (CMIERR_UNKNOWN); 446 } 447 448 } 449 450 /*ARGSUSED*/ 451 cmi_errno_t 452 mcamd_patounum_wrap(void *arg, uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, 453 uint32_t synd, int syndtype, mc_unum_t *unump) 454 { 455 mcamd_hdl_t mcamd; 456 int rc; 457 458 mcamd_mkhdl(&mcamd); 459 460 rw_enter(&mc_lock, RW_READER); 461 462 rc = mcamd_patounum(&mcamd, (mcamd_node_t *)mc_list, pa, 463 valid_hi, valid_lo, synd, syndtype, unump); 464 465 #ifdef DEBUG 466 /* 467 * Apply the reverse operation to verify the result. If there is 468 * a problem complain but continue. 469 */ 470 if (rc == 0 && MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { 471 uint64_t rpa; 472 if (mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, 473 &rpa) != 0 || rpa != pa) { 474 mcamd_dprintf(&mcamd, MCAMD_DBG_ERR, 475 "mcamd_patounum_wrap: offset calculation " 476 "verification for PA 0x%llx failed\n", pa); 477 } 478 } 479 #endif 480 rw_exit(&mc_lock); 481 482 return (mcamd_cmierr(rc, &mcamd)); 483 } 484 485 static int 486 fmri2unum(nvlist_t *nvl, mc_unum_t *unump) 487 { 488 int i; 489 uint64_t offset; 490 nvlist_t *hcsp, **hcl; 491 uint_t npr; 492 493 if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) != 0 || 494 (nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, 495 &offset) != 0 && nvlist_lookup_uint64(hcsp, 496 FM_FMRI_HC_SPECIFIC_OFFSET, &offset) != 0) || 497 nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcl, &npr) != 0) 498 return (0); 499 500 501 bzero(unump, sizeof (mc_unum_t)); 502 unump->unum_chan = MC_INVALNUM; 503 for (i = 0; i < MC_UNUM_NDIMM; i++) 504 unump->unum_dimms[i] = MC_INVALNUM; 505 506 for (i = 0; i < npr; i++) { 507 char *hcnm, *hcid; 508 long v; 509 510 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &hcnm) != 0 || 511 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0 || 512 ddi_strtol(hcid, NULL, 0, &v) != 0) 513 return (0); 514 515 if (strcmp(hcnm, "motherboard") == 0) 516 unump->unum_board = (int)v; 517 else if (strcmp(hcnm, "chip") == 0) 518 unump->unum_chip = (int)v; 519 else if (strcmp(hcnm, "memory-controller") == 0) 520 unump->unum_mc = (int)v; 521 else if (strcmp(hcnm, "chip-select") == 0) 522 unump->unum_cs = (int)v; 523 else if (strcmp(hcnm, "dimm") == 0) 524 unump->unum_dimms[0] = (int)v; 525 else if (strcmp(hcnm, "rank") == 0) 526 unump->unum_rank = (int)v; 527 } 528 529 unump->unum_offset = offset; 530 531 return (1); 532 } 533 534 /*ARGSUSED*/ 535 cmi_errno_t 536 mcamd_unumtopa_wrap(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap) 537 { 538 mcamd_hdl_t mcamd; 539 int rc; 540 mc_unum_t unum; 541 542 ASSERT(unump == NULL || nvl == NULL); /* enforced at cmi level */ 543 544 if (unump == NULL) { 545 if (!fmri2unum(nvl, &unum)) 546 return (CMIERR_MC_INVALUNUM); 547 unump = &unum; 548 } 549 550 mcamd_mkhdl(&mcamd); 551 552 rw_enter(&mc_lock, RW_READER); 553 rc = mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, pap); 554 rw_exit(&mc_lock); 555 556 return (mcamd_cmierr(rc, &mcamd)); 557 } 558 559 static void 560 mc_ereport_dimm_resource(mc_unum_t *unump, nvlist_t *elems[], int *nump) 561 { 562 int i; 563 564 for (i = 0; i < MC_UNUM_NDIMM; i++) { 565 if (unump->unum_dimms[i] == MC_INVALNUM) 566 break; 567 568 elems[(*nump)++] = fm_nvlist_create(NULL); 569 fm_fmri_hc_set(elems[i], FM_HC_SCHEME_VERSION, NULL, NULL, 5, 570 "motherboard", unump->unum_board, 571 "chip", unump->unum_chip, 572 "memory-controller", unump->unum_mc, 573 "dimm", unump->unum_dimms[i], 574 "rank", unump->unum_rank); 575 } 576 } 577 578 static void 579 mc_ereport_cs_resource(mc_unum_t *unump, nvlist_t *elems[], int *nump) 580 { 581 elems[0] = fm_nvlist_create(NULL); 582 fm_fmri_hc_set(elems[0], FM_HC_SCHEME_VERSION, NULL, NULL, 4, 583 "motherboard", unump->unum_board, 584 "chip", unump->unum_chip, 585 "memory-controller", unump->unum_mc, 586 "chip-select", unump->unum_cs); 587 *nump = 1; 588 } 589 590 /* 591 * Create the 'resource' payload member from the unum info. If valid 592 * dimm numbers are present in the unum info then create members 593 * identifying the dimm and rank; otherwise if a valid chip-select 594 * number is indicated then create a member identifying the chip-select 595 * topology node. 596 */ 597 static void 598 mc_ereport_add_resource(nvlist_t *payload, mc_unum_t *unump) 599 { 600 nvlist_t *elems[MC_UNUM_NDIMM]; 601 int nelems = 0; 602 int i; 603 604 if (unump->unum_dimms[0] != MC_INVALNUM) 605 mc_ereport_dimm_resource(unump, elems, &nelems); 606 else if (unump->unum_cs != MC_INVALNUM) 607 mc_ereport_cs_resource(unump, elems, &nelems); 608 609 if (nelems > 0) { 610 fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE, 611 DATA_TYPE_NVLIST_ARRAY, nelems, elems, NULL); 612 613 for (i = 0; i < nelems; i++) 614 fm_nvlist_destroy(elems[i], FM_NVA_FREE); 615 } 616 } 617 618 static void 619 mc_ereport_add_payload(nvlist_t *ereport, uint64_t members, mc_unum_t *unump) 620 { 621 if (members & FM_EREPORT_PAYLOAD_FLAG_RESOURCE && 622 unump != NULL) 623 mc_ereport_add_resource(ereport, unump); 624 } 625 626 static nvlist_t * 627 mc_fmri_create(mc_t *mc) 628 { 629 nvlist_t *nvl = fm_nvlist_create(NULL); 630 631 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3, 632 "motherboard", 0, 633 "chip", mc->mc_props.mcp_num, 634 "memory-controller", 0); 635 636 return (nvl); 637 } 638 639 /* 640 * Simple ereport generator for errors detected by the memory controller. 641 * Posts an ereport of class ereport.cpu.amd.<class_sfx> with a resource nvlist 642 * derived from the given mc_unum_t. There are no other payload members. 643 * The mc argument is used to formulate a detector and this mc should 644 * correspond with that identified in the mc_unum_t. 645 * 646 * There is no control of which members to include the the resulting ereport - 647 * it will be an ereport formed using the given class suffix, detector 648 * indicated as the memory-controller and with a resource generated by 649 * expanding the given mc_unum_t. 650 * 651 * We do not use any special nv allocator here and so this is not suitable 652 * for use during panic. It is intended for use during MC topology 653 * discovery and other controlled circumstances. 654 */ 655 void 656 mcamd_ereport_post(mc_t *mc, const char *class_sfx, mc_unum_t *unump, 657 uint64_t payload) 658 { 659 nvlist_t *ereport, *detector; 660 char buf[FM_MAX_CLASS]; 661 662 ereport = fm_nvlist_create(NULL); 663 detector = mc_fmri_create(mc); 664 665 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", FM_ERROR_CPU, 666 "amd", class_sfx); 667 fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, 668 fm_ena_generate(gethrtime(), FM_ENA_FMT1), detector, NULL); 669 fm_nvlist_destroy(detector, FM_NVA_FREE); 670 671 mc_ereport_add_payload(ereport, payload, unump); 672 673 (void) fm_ereport_post(ereport, EVCH_TRYHARD); 674 fm_nvlist_destroy(ereport, FM_NVA_FREE); 675 } 676 677 static const cmi_mc_ops_t mcamd_mc_ops = { 678 mcamd_patounum_wrap, /* cmi_mc_patounum */ 679 mcamd_unumtopa_wrap, /* cmi_mc_unumtopa */ 680 NULL /* cmi_mc_logout */ 681 }; 682 683 void 684 mcamd_mc_register(cmi_hdl_t hdl, mc_t *mc) 685 { 686 cmi_mc_register(hdl, &mcamd_mc_ops, mc); 687 } 688