8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / intel / io / mc-amd / mcamd_subr.c
blob04cc5e5460b0a6e91d33b5ba4ebfb0f1db541a73
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Stub routines used to link in files from $SRC/common/mc
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/smb/fmsmb.h>
39 #include <sys/fm/protocol.h>
40 #include <sys/mc.h>
41 #include <sys/smbios.h>
42 #include <sys/smbios_impl.h>
44 #include <mcamd.h>
45 #include <mcamd_off.h>
47 int mcamd_debug = 0; /* see mcamd_api.h for MCAMD_DBG_* values */
49 extern int x86gentopo_legacy;
51 struct mc_offmap {
52 int mcom_code;
53 uint_t mcom_offset;
56 static uint_t
57 nodetype(mcamd_node_t *node)
59 mc_hdr_t *mch = (mc_hdr_t *)node;
60 return (mch->mch_type);
63 static void *
64 node2type(mcamd_node_t *node, int type)
66 mc_hdr_t *mch = (mc_hdr_t *)node;
67 ASSERT(mch->mch_type == type);
68 return (mch);
72 * Iterate over all memory controllers.
74 /*ARGSUSED*/
75 mcamd_node_t *
76 mcamd_mc_next(mcamd_hdl_t *hdl, mcamd_node_t *root, mcamd_node_t *last)
78 mc_t *mc;
80 ASSERT(RW_LOCK_HELD(&mc_lock));
82 if (last == NULL)
83 return ((mcamd_node_t *)mc_list);
85 mc = node2type(last, MC_NT_MC);
87 return ((mcamd_node_t *)mc->mc_next);
91 * Iterate over all chip-selects of a MC or all chip-selects of a DIMM
92 * depending on the node type of 'node'. In the DIMM case we do not
93 * have a linked list of associated chip-selects but an array of pointer
94 * to them.
96 /*ARGSUSED*/
97 mcamd_node_t *
98 mcamd_cs_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last)
100 uint_t nt = nodetype(node);
101 mc_t *mc;
102 mc_cs_t *mccs;
103 mc_dimm_t *mcd;
104 int i;
105 void *retval;
107 ASSERT(nt == MC_NT_MC || nt == MC_NT_DIMM);
109 if (last == NULL) {
110 switch (nt) {
111 case MC_NT_MC:
112 mc = node2type(node, MC_NT_MC);
113 retval = mc->mc_cslist;
114 break;
115 case MC_NT_DIMM:
116 mcd = node2type(node, MC_NT_DIMM);
117 retval = mcd->mcd_cs[0];
118 break;
120 } else {
121 mccs = node2type(last, MC_NT_CS);
123 switch (nt) {
124 case MC_NT_MC:
125 retval = mccs->mccs_next;
126 break;
127 case MC_NT_DIMM:
128 mcd = node2type(node, MC_NT_DIMM);
129 for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) {
130 if (mcd->mcd_cs[i] == mccs)
131 break;
133 if (i == MC_CHIP_DIMMRANKMAX)
134 cmn_err(CE_PANIC, "Bad last value for "
135 "mcamd_cs_next");
137 if (i == MC_CHIP_DIMMRANKMAX - 1)
138 retval = NULL;
139 else
140 retval = mcd->mcd_cs[i + 1];
141 break;
145 return ((mcamd_node_t *)retval);
149 * Iterate over all DIMMs of an MC or all DIMMs of a chip-select depending
150 * on the node type of 'node'. In the chip-select case we do not have
151 * a linked list of associated DIMMs but an array of pointers to them.
153 /*ARGSUSED*/
154 mcamd_node_t *
155 mcamd_dimm_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last)
157 uint_t nt = nodetype(node);
158 mc_t *mc;
159 mc_cs_t *mccs;
160 mc_dimm_t *mcd;
161 int i;
162 void *retval;
164 ASSERT(nt == MC_NT_MC || nt == MC_NT_CS);
166 if (last == NULL) {
167 switch (nt) {
168 case MC_NT_MC:
169 mc = node2type(node, MC_NT_MC);
170 retval = mc->mc_dimmlist;
171 break;
172 case MC_NT_CS:
173 mccs = node2type(node, MC_NT_CS);
174 retval = mccs->mccs_dimm[0];
175 break;
177 } else {
178 mcd = node2type(last, MC_NT_DIMM);
180 switch (nt) {
181 case MC_NT_MC:
182 retval = mcd->mcd_next;
183 break;
184 case MC_NT_CS:
185 mccs = node2type(node, MC_NT_CS);
186 for (i = 0; i < MC_CHIP_DIMMPERCS; i++) {
187 if (mccs->mccs_dimm[i] == mcd)
188 break;
190 if (i == MC_CHIP_DIMMPERCS)
191 cmn_err(CE_PANIC, "Bad last value for "
192 "mcamd_dimm_next");
194 if (i == MC_CHIP_DIMMPERCS - 1)
195 retval = NULL;
196 else
197 retval = mccs->mccs_dimm[i + 1];
198 break;
202 return ((mcamd_node_t *)retval);
205 /*ARGSUSED*/
206 mcamd_node_t *
207 mcamd_cs_mc(mcamd_hdl_t *hdl, mcamd_node_t *csnode)
209 mc_cs_t *mccs = node2type(csnode, MC_NT_CS);
210 return ((mcamd_node_t *)mccs->mccs_mc);
213 /*ARGSUSED*/
214 mcamd_node_t *
215 mcamd_dimm_mc(mcamd_hdl_t *hdl, mcamd_node_t *dnode)
217 mc_dimm_t *mcd = node2type(dnode, MC_NT_DIMM);
218 return ((mcamd_node_t *)mcd->mcd_mc);
222 * Node properties. A property is accessed through a property number code;
223 * we search these tables for a match (choosing table from node type) and
224 * return the uint64_t property at the indicated offset into the node
225 * structure. All properties must be of type uint64_t. It is assumed that
226 * property lookup does not have to be super-fast - we search linearly
227 * down the (small) lists.
229 static const struct mc_offmap mcamd_mc_offmap[] = {
230 { MCAMD_PROP_NUM, MCAMD_MC_OFF_NUM },
231 { MCAMD_PROP_REV, MCAMD_MC_OFF_REV },
232 { MCAMD_PROP_BASE_ADDR, MCAMD_MC_OFF_BASE_ADDR },
233 { MCAMD_PROP_LIM_ADDR, MCAMD_MC_OFF_LIM_ADDR },
234 { MCAMD_PROP_ILEN, MCAMD_MC_OFF_ILEN },
235 { MCAMD_PROP_ILSEL, MCAMD_MC_OFF_ILSEL },
236 { MCAMD_PROP_CSINTLVFCTR, MCAMD_MC_OFF_CSINTLVFCTR },
237 { MCAMD_PROP_DRAMHOLE_SIZE, MCAMD_MC_OFF_DRAMHOLE_SIZE },
238 { MCAMD_PROP_ACCESS_WIDTH, MCAMD_MC_OFF_ACCWIDTH },
239 { MCAMD_PROP_CSBANKMAPREG, MCAMD_MC_OFF_CSBANKMAPREG },
240 { MCAMD_PROP_BANKSWZL, MCAMD_MC_OFF_BNKSWZL },
241 { MCAMD_PROP_MOD64MUX, MCAMD_MC_OFF_MOD64MUX },
242 { MCAMD_PROP_SPARECS, MCAMD_MC_OFF_SPARECS },
243 { MCAMD_PROP_BADCS, MCAMD_MC_OFF_BADCS },
246 static const struct mc_offmap mcamd_cs_offmap[] = {
247 { MCAMD_PROP_NUM, MCAMD_CS_OFF_NUM },
248 { MCAMD_PROP_BASE_ADDR, MCAMD_CS_OFF_BASE_ADDR },
249 { MCAMD_PROP_MASK, MCAMD_CS_OFF_MASK },
250 { MCAMD_PROP_SIZE, MCAMD_CS_OFF_SIZE },
251 { MCAMD_PROP_CSBE, MCAMD_CS_OFF_CSBE },
252 { MCAMD_PROP_SPARE, MCAMD_CS_OFF_SPARE },
253 { MCAMD_PROP_TESTFAIL, MCAMD_CS_OFF_TESTFAIL },
254 { MCAMD_PROP_CSDIMM1, MCAMD_CS_OFF_DIMMNUMS },
255 { MCAMD_PROP_CSDIMM2, MCAMD_CS_OFF_DIMMNUMS +
256 MCAMD_CS_OFF_DIMMNUMS_INCR },
257 { MCAMD_PROP_DIMMRANK, MCAMD_CS_OFF_DIMMRANK },
260 static const struct mc_offmap mcamd_dimm_offmap[] = {
261 { MCAMD_PROP_NUM, MCAMD_DIMM_OFF_NUM },
262 { MCAMD_PROP_SIZE, MCAMD_DIMM_OFF_SIZE },
265 struct nt_offmap {
266 const struct mc_offmap *omp;
267 int mapents;
270 /*ARGSUSED*/
271 static int
272 findoffset(mcamd_hdl_t *hdl, mcamd_node_t *node, struct nt_offmap *arr,
273 int code, uint_t *offset)
275 int i;
276 mc_hdr_t *mch = (mc_hdr_t *)node;
277 int nt = mch->mch_type;
278 const struct mc_offmap *omp;
280 if (nt > MC_NT_NTYPES || (omp = arr[nt].omp) == NULL)
281 return (0);
283 for (i = 0; i < arr[nt].mapents; i++, omp++) {
284 if (omp->mcom_code == code) {
285 *offset = omp->mcom_offset;
286 return (1);
290 return (0);
293 /*ARGSUSED*/
295 mcamd_get_numprop(mcamd_hdl_t *hdl, mcamd_node_t *node,
296 mcamd_propcode_t code, mcamd_prop_t *valp)
298 int found;
299 uint_t offset;
301 struct nt_offmap props[] = {
302 { mcamd_mc_offmap, /* MC_NT_MC */
303 sizeof (mcamd_mc_offmap) / sizeof (struct mc_offmap) },
304 { mcamd_cs_offmap, /* MC_NT_CS */
305 sizeof (mcamd_cs_offmap) / sizeof (struct mc_offmap) },
306 { mcamd_dimm_offmap, /* MC_NT_DIMM */
307 sizeof (mcamd_dimm_offmap) / sizeof (struct mc_offmap) }
310 found = findoffset(hdl, node, &props[0], code, &offset);
311 ASSERT(found);
313 if (found)
314 *valp = *(uint64_t *)((uintptr_t)node + offset);
316 return (found == 1);
320 mcamd_get_numprops(mcamd_hdl_t *hdl, ...)
322 va_list ap;
323 mcamd_node_t *node;
324 mcamd_propcode_t code;
325 mcamd_prop_t *valp;
327 va_start(ap, hdl);
328 while ((node = va_arg(ap, mcamd_node_t *)) != NULL) {
329 code = va_arg(ap, mcamd_propcode_t);
330 valp = va_arg(ap, mcamd_prop_t *);
331 if (!mcamd_get_numprop(hdl, node, code, valp))
332 return (0);
334 va_end(ap);
335 return (1);
338 static const struct mc_offmap mcreg_offmap[] = {
339 { MCAMD_REG_DRAMBASE, MCAMD_MC_OFF_DRAMBASE_REG },
340 { MCAMD_REG_DRAMLIMIT, MCAMD_MC_OFF_DRAMLIMIT_REG },
341 { MCAMD_REG_DRAMHOLE, MCAMD_MC_OFF_DRAMHOLE_REG },
342 { MCAMD_REG_DRAMCFGLO, MCAMD_MC_OFF_DRAMCFGLO_REG },
343 { MCAMD_REG_DRAMCFGHI, MCAMD_MC_OFF_DRAMCFGHI_REG },
346 static const struct mc_offmap csreg_offmap[] = {
347 { MCAMD_REG_CSBASE, MCAMD_CS_OFF_CSBASE_REG },
348 { MCAMD_REG_CSMASK, MCAMD_CS_OFF_CSMASK_REG },
351 /*ARGSUSED*/
353 mcamd_get_cfgreg(struct mcamd_hdl *hdl, mcamd_node_t *node,
354 mcamd_regcode_t code, uint32_t *valp)
356 int found;
357 uint_t offset;
359 struct nt_offmap regs[] = {
360 { mcreg_offmap, /* MC_NT_MC */
361 sizeof (mcreg_offmap) / sizeof (struct mc_offmap) },
362 { csreg_offmap, /* MC_NT_CS */
363 sizeof (csreg_offmap) / sizeof (struct mc_offmap) },
364 { NULL, 0 } /* MC_NT_DIMM */
367 found = findoffset(hdl, node, &regs[0], code, &offset);
368 ASSERT(found);
370 ASSERT(found);
371 if (found)
372 *valp = *(uint32_t *)((uintptr_t)node + offset);
374 return (found == 1);
378 mcamd_get_cfgregs(mcamd_hdl_t *hdl, ...)
380 va_list ap;
381 mcamd_node_t *node;
382 mcamd_regcode_t code;
383 uint32_t *valp;
385 va_start(ap, hdl);
386 while ((node = va_arg(ap, mcamd_node_t *)) != NULL) {
387 code = va_arg(ap, mcamd_regcode_t);
388 valp = va_arg(ap, uint32_t *);
389 if (!mcamd_get_cfgreg(hdl, node, code, valp))
390 return (0);
392 va_end(ap);
393 return (1);
398 mcamd_errno(mcamd_hdl_t *mcamd)
400 return (mcamd->mcamd_errno);
404 mcamd_set_errno(mcamd_hdl_t *mcamd, int err)
406 mcamd->mcamd_errno = err;
407 return (-1);
410 void
411 mcamd_dprintf(mcamd_hdl_t *mcamd, int mask, const char *fmt, ...)
413 va_list ap;
415 if (!(mcamd->mcamd_debug & mask))
416 return;
418 va_start(ap, fmt);
419 vcmn_err(mask & MCAMD_DBG_ERR ? CE_WARN : CE_NOTE, fmt, ap);
420 va_end(ap);
423 void
424 mcamd_mkhdl(mcamd_hdl_t *hdl)
426 hdl->mcamd_errno = 0;
427 hdl->mcamd_debug = mcamd_debug;
430 cmi_errno_t
431 mcamd_cmierr(int err, mcamd_hdl_t *hdl)
433 if (err == 0)
434 return (CMI_SUCCESS);
436 switch (mcamd_errno(hdl)) {
437 case EMCAMD_SYNDINVALID:
438 return (CMIERR_MC_SYNDROME);
440 case EMCAMD_TREEINVALID:
441 return (CMIERR_MC_BADSTATE);
443 case EMCAMD_NOADDR:
444 return (CMIERR_MC_NOADDR);
446 case EMCAMD_INSUFF_RES:
447 return (CMIERR_MC_ADDRBITS);
449 default:
450 return (CMIERR_UNKNOWN);
455 /*ARGSUSED*/
456 cmi_errno_t
457 mcamd_patounum_wrap(void *arg, uint64_t pa, uint8_t valid_hi, uint8_t valid_lo,
458 uint32_t synd, int syndtype, mc_unum_t *unump)
460 mcamd_hdl_t mcamd;
461 int rc;
463 mcamd_mkhdl(&mcamd);
465 rw_enter(&mc_lock, RW_READER);
467 rc = mcamd_patounum(&mcamd, (mcamd_node_t *)mc_list, pa,
468 valid_hi, valid_lo, synd, syndtype, unump);
470 #ifdef DEBUG
472 * Apply the reverse operation to verify the result. If there is
473 * a problem complain but continue.
475 if (rc == 0 && MCAMD_RC_OFFSET_VALID(unump->unum_offset)) {
476 uint64_t rpa;
477 if (mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump,
478 &rpa) != 0 || rpa != pa) {
479 mcamd_dprintf(&mcamd, MCAMD_DBG_ERR,
480 "mcamd_patounum_wrap: offset calculation "
481 "verification for PA 0x%llx failed\n", pa);
484 #endif
485 rw_exit(&mc_lock);
487 return (mcamd_cmierr(rc, &mcamd));
490 static int
491 fmri2unum(nvlist_t *nvl, mc_unum_t *unump)
493 int i;
494 uint64_t offset;
495 nvlist_t *hcsp, **hcl;
496 uint_t npr;
498 if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) != 0 ||
499 (nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
500 &offset) != 0 && nvlist_lookup_uint64(hcsp,
501 FM_FMRI_HC_SPECIFIC_OFFSET, &offset) != 0) ||
502 nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcl, &npr) != 0)
503 return (0);
506 bzero(unump, sizeof (mc_unum_t));
507 unump->unum_chan = MC_INVALNUM;
508 for (i = 0; i < MC_UNUM_NDIMM; i++)
509 unump->unum_dimms[i] = MC_INVALNUM;
511 for (i = 0; i < npr; i++) {
512 char *hcnm, *hcid;
513 long v;
515 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &hcnm) != 0 ||
516 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0 ||
517 ddi_strtol(hcid, NULL, 0, &v) != 0)
518 return (0);
520 if (strcmp(hcnm, "motherboard") == 0)
521 unump->unum_board = (int)v;
522 else if (strcmp(hcnm, "chip") == 0)
523 unump->unum_chip = (int)v;
524 else if (strcmp(hcnm, "memory-controller") == 0)
525 unump->unum_mc = (int)v;
526 else if (strcmp(hcnm, "chip-select") == 0)
527 unump->unum_cs = (int)v;
528 else if (strcmp(hcnm, "dimm") == 0)
529 unump->unum_dimms[0] = (int)v;
530 else if (strcmp(hcnm, "rank") == 0)
531 unump->unum_rank = (int)v;
534 unump->unum_offset = offset;
536 return (1);
539 /*ARGSUSED*/
540 cmi_errno_t
541 mcamd_unumtopa_wrap(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap)
543 mcamd_hdl_t mcamd;
544 int rc;
545 mc_unum_t unum;
547 ASSERT(unump == NULL || nvl == NULL); /* enforced at cmi level */
549 if (unump == NULL) {
550 if (!fmri2unum(nvl, &unum))
551 return (CMIERR_MC_INVALUNUM);
552 unump = &unum;
555 mcamd_mkhdl(&mcamd);
557 rw_enter(&mc_lock, RW_READER);
558 rc = mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, pap);
559 rw_exit(&mc_lock);
561 return (mcamd_cmierr(rc, &mcamd));
564 static void
565 mc_ereport_dimm_resource(mc_unum_t *unump, nvlist_t *elems[], int *nump,
566 mc_t *mc)
568 int i;
570 for (i = 0; i < MC_UNUM_NDIMM; i++) {
571 if (unump->unum_dimms[i] == MC_INVALNUM)
572 break;
574 elems[(*nump)++] = fm_nvlist_create(NULL);
576 if (!x86gentopo_legacy && mc->smb_bboard != NULL) {
577 fm_fmri_hc_create(elems[i], FM_HC_SCHEME_VERSION,
578 NULL, NULL, mc->smb_bboard, 4,
579 "chip", mc->smb_chipid,
580 "memory-controller", unump->unum_mc,
581 "dimm", unump->unum_dimms[i],
582 "rank", unump->unum_rank);
583 } else {
584 fm_fmri_hc_set(elems[i], FM_HC_SCHEME_VERSION,
585 NULL, NULL, 5,
586 "motherboard", unump->unum_board,
587 "chip", unump->unum_chip,
588 "memory-controller", unump->unum_mc,
589 "dimm", unump->unum_dimms[i],
590 "rank", unump->unum_rank);
595 static void
596 mc_ereport_cs_resource(mc_unum_t *unump, nvlist_t *elems[], int *nump, mc_t *mc)
598 elems[0] = fm_nvlist_create(NULL);
600 if (!x86gentopo_legacy && mc->smb_bboard != NULL) {
601 fm_fmri_hc_create(elems[0], FM_HC_SCHEME_VERSION, NULL, NULL,
602 mc->smb_bboard, 3,
603 "chip", mc->smb_chipid,
604 "memory-controller", unump->unum_mc,
605 "chip-select", unump->unum_cs);
606 } else {
607 fm_fmri_hc_set(elems[0], FM_HC_SCHEME_VERSION, NULL, NULL, 4,
608 "motherboard", unump->unum_board,
609 "chip", unump->unum_chip,
610 "memory-controller", unump->unum_mc,
611 "chip-select", unump->unum_cs);
613 *nump = 1;
617 * Create the 'resource' payload member from the unum info. If valid
618 * dimm numbers are present in the unum info then create members
619 * identifying the dimm and rank; otherwise if a valid chip-select
620 * number is indicated then create a member identifying the chip-select
621 * topology node.
623 static void
624 mc_ereport_add_resource(nvlist_t *payload, mc_unum_t *unump, mc_t *mc)
626 nvlist_t *elems[MC_UNUM_NDIMM];
627 int nelems = 0;
628 int i;
630 if (unump->unum_dimms[0] != MC_INVALNUM)
631 mc_ereport_dimm_resource(unump, elems, &nelems, mc);
632 else if (unump->unum_cs != MC_INVALNUM)
633 mc_ereport_cs_resource(unump, elems, &nelems, mc);
635 if (nelems > 0) {
636 fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
637 DATA_TYPE_NVLIST_ARRAY, nelems, elems, NULL);
639 for (i = 0; i < nelems; i++)
640 fm_nvlist_destroy(elems[i], FM_NVA_FREE);
644 static void
645 mc_ereport_add_payload(nvlist_t *ereport, uint64_t members, mc_unum_t *unump,
646 mc_t *mc)
648 if (members & FM_EREPORT_PAYLOAD_FLAG_RESOURCE &&
649 unump != NULL)
650 mc_ereport_add_resource(ereport, unump, mc);
653 static nvlist_t *
654 mc_fmri_create(mc_t *mc)
656 nvlist_t *nvl = fm_nvlist_create(NULL);
658 if (!x86gentopo_legacy && mc->smb_bboard != NULL) {
659 fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, NULL,
660 mc->smb_bboard, 2,
661 "chip", mc->smb_chipid,
662 "memory-controller", 0);
663 } else {
664 fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
665 "motherboard", 0,
666 "chip", mc->mc_props.mcp_num,
667 "memory-controller", 0);
670 return (nvl);
674 * Simple ereport generator for errors detected by the memory controller.
675 * Posts an ereport of class ereport.cpu.amd.<class_sfx> with a resource nvlist
676 * derived from the given mc_unum_t. There are no other payload members.
677 * The mc argument is used to formulate a detector and this mc should
678 * correspond with that identified in the mc_unum_t.
680 * There is no control of which members to include the the resulting ereport -
681 * it will be an ereport formed using the given class suffix, detector
682 * indicated as the memory-controller and with a resource generated by
683 * expanding the given mc_unum_t.
685 * We do not use any special nv allocator here and so this is not suitable
686 * for use during panic. It is intended for use during MC topology
687 * discovery and other controlled circumstances.
689 void
690 mcamd_ereport_post(mc_t *mc, const char *class_sfx, mc_unum_t *unump,
691 uint64_t payload)
693 nvlist_t *ereport, *detector;
694 char buf[FM_MAX_CLASS];
696 ereport = fm_nvlist_create(NULL);
697 detector = mc_fmri_create(mc);
699 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", FM_ERROR_CPU,
700 "amd", class_sfx);
701 fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
702 fm_ena_generate(gethrtime(), FM_ENA_FMT1), detector, NULL);
703 fm_nvlist_destroy(detector, FM_NVA_FREE);
705 mc_ereport_add_payload(ereport, payload, unump, mc);
707 (void) fm_ereport_post(ereport, EVCH_TRYHARD);
708 fm_nvlist_destroy(ereport, FM_NVA_FREE);
711 static const cmi_mc_ops_t mcamd_mc_ops = {
712 mcamd_patounum_wrap, /* cmi_mc_patounum */
713 mcamd_unumtopa_wrap, /* cmi_mc_unumtopa */
714 NULL /* cmi_mc_logout */
717 void
718 mcamd_mc_register(cmi_hdl_t hdl, mc_t *mc)
720 cmi_mc_register(hdl, &mcamd_mc_ops, mc);