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, ®s[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