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