13ad553a7Sgavinm /* 23ad553a7Sgavinm * CDDL HEADER START 33ad553a7Sgavinm * 43ad553a7Sgavinm * The contents of this file are subject to the terms of the 53ad553a7Sgavinm * Common Development and Distribution License (the "License"). 63ad553a7Sgavinm * You may not use this file except in compliance with the License. 73ad553a7Sgavinm * 83ad553a7Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93ad553a7Sgavinm * or http://www.opensolaris.org/os/licensing. 103ad553a7Sgavinm * See the License for the specific language governing permissions 113ad553a7Sgavinm * and limitations under the License. 123ad553a7Sgavinm * 133ad553a7Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 143ad553a7Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153ad553a7Sgavinm * If applicable, add the following below this CDDL HEADER, with the 163ad553a7Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 173ad553a7Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 183ad553a7Sgavinm * 193ad553a7Sgavinm * CDDL HEADER END 203ad553a7Sgavinm */ 213ad553a7Sgavinm 227aec1d6eScindi /* 23a3114836SGerry Liu * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247aec1d6eScindi * Use is subject to license terms. 25*2a613b59SRobert Mustacchi * Copyright (c) 2018, Joyent, Inc. 267aec1d6eScindi */ 277aec1d6eScindi 287aec1d6eScindi /* 297aec1d6eScindi * Public interface to routines implemented by CPU modules 307aec1d6eScindi */ 317aec1d6eScindi 3220c794b3Sgavinm #include <sys/types.h> 3320c794b3Sgavinm #include <sys/atomic.h> 347aec1d6eScindi #include <sys/x86_archext.h> 357aec1d6eScindi #include <sys/cpu_module_impl.h> 3620c794b3Sgavinm #include <sys/cpu_module_ms.h> 377aec1d6eScindi #include <sys/fm/util.h> 387aec1d6eScindi #include <sys/reboot.h> 397aec1d6eScindi #include <sys/modctl.h> 407aec1d6eScindi #include <sys/param.h> 417aec1d6eScindi #include <sys/cmn_err.h> 427aec1d6eScindi #include <sys/systm.h> 4320c794b3Sgavinm #include <sys/fm/protocol.h> 4420c794b3Sgavinm #include <sys/pcb.h> 4520c794b3Sgavinm #include <sys/ontrap.h> 4620c794b3Sgavinm #include <sys/psw.h> 4720c794b3Sgavinm #include <sys/privregs.h> 48e4b86885SCheng Sean Ye #include <sys/machsystm.h> 497aec1d6eScindi 5020c794b3Sgavinm /* 5120c794b3Sgavinm * Set to force cmi_init to fail. 5220c794b3Sgavinm */ 5320c794b3Sgavinm int cmi_no_init = 0; 547aec1d6eScindi 5520c794b3Sgavinm /* 5620c794b3Sgavinm * Set to avoid MCA initialization. 5720c794b3Sgavinm */ 5820c794b3Sgavinm int cmi_no_mca_init = 0; 597aec1d6eScindi 608a40a695Sgavinm /* 618a40a695Sgavinm * If cleared for debugging we will not attempt to load a model-specific 628a40a695Sgavinm * cpu module but will load the generic cpu module instead. 638a40a695Sgavinm */ 648a40a695Sgavinm int cmi_force_generic = 0; 658a40a695Sgavinm 667aec1d6eScindi /* 677aec1d6eScindi * If cleared for debugging, we will suppress panicking on fatal hardware 687aec1d6eScindi * errors. This should *only* be used for debugging; it use can and will 697aec1d6eScindi * cause data corruption if actual hardware errors are detected by the system. 707aec1d6eScindi */ 717aec1d6eScindi int cmi_panic_on_uncorrectable_error = 1; 727aec1d6eScindi 73e4b86885SCheng Sean Ye #ifndef __xpv 74e3d60c9bSAdrian Frost /* 75e3d60c9bSAdrian Frost * Set to indicate whether we are able to enable cmci interrupt. 76e3d60c9bSAdrian Frost */ 77e3d60c9bSAdrian Frost int cmi_enable_cmci = 0; 78e4b86885SCheng Sean Ye #endif 79e3d60c9bSAdrian Frost 8020c794b3Sgavinm /* 8120c794b3Sgavinm * Subdirectory (relative to the module search path) in which we will 8220c794b3Sgavinm * look for cpu modules. 8320c794b3Sgavinm */ 8420c794b3Sgavinm #define CPUMOD_SUBDIR "cpu" 8520c794b3Sgavinm 8620c794b3Sgavinm /* 8720c794b3Sgavinm * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and 8820c794b3Sgavinm * "cpu.generic" - the "cpu" prefix is specified by the following. 8920c794b3Sgavinm */ 9020c794b3Sgavinm #define CPUMOD_PREFIX "cpu" 9120c794b3Sgavinm 9220c794b3Sgavinm /* 9320c794b3Sgavinm * Structure used to keep track of cpu modules we have loaded and their ops 9420c794b3Sgavinm */ 9520c794b3Sgavinm typedef struct cmi { 9620c794b3Sgavinm struct cmi *cmi_next; 9720c794b3Sgavinm struct cmi *cmi_prev; 9820c794b3Sgavinm const cmi_ops_t *cmi_ops; 9920c794b3Sgavinm struct modctl *cmi_modp; 10020c794b3Sgavinm uint_t cmi_refcnt; 10120c794b3Sgavinm } cmi_t; 10220c794b3Sgavinm 1037aec1d6eScindi static cmi_t *cmi_list; 104a3114836SGerry Liu static const cmi_mc_ops_t *cmi_mc_global_ops; 105a3114836SGerry Liu static void *cmi_mc_global_data; 1067aec1d6eScindi static kmutex_t cmi_load_lock; 1077aec1d6eScindi 10820c794b3Sgavinm /* 10920c794b3Sgavinm * Functions we need from cmi_hw.c that are not part of the cpu_module.h 11020c794b3Sgavinm * interface. 11120c794b3Sgavinm */ 112e4b86885SCheng Sean Ye extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t); 113a3114836SGerry Liu extern void cmi_hdl_destroy(cmi_hdl_t ophdl); 11420c794b3Sgavinm extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *); 11520c794b3Sgavinm extern void *cmi_hdl_getcmi(cmi_hdl_t); 11620c794b3Sgavinm extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *); 117e4b86885SCheng Sean Ye extern void cmi_hdl_inj_begin(cmi_hdl_t); 118e4b86885SCheng Sean Ye extern void cmi_hdl_inj_end(cmi_hdl_t); 119074bb90dSTom Pothier extern void cmi_read_smbios(cmi_hdl_t); 12020c794b3Sgavinm 12120c794b3Sgavinm #define HDL2CMI(hdl) cmi_hdl_getcmi(hdl) 12220c794b3Sgavinm 12320c794b3Sgavinm #define CMI_OPS(cmi) (cmi)->cmi_ops 12420c794b3Sgavinm #define CMI_OP_PRESENT(cmi, op) ((cmi) && CMI_OPS(cmi)->op != NULL) 12520c794b3Sgavinm 12620c794b3Sgavinm #define CMI_MATCH_VENDOR 0 /* Just match on vendor */ 12720c794b3Sgavinm #define CMI_MATCH_FAMILY 1 /* Match down to family */ 12820c794b3Sgavinm #define CMI_MATCH_MODEL 2 /* Match down to model */ 12920c794b3Sgavinm #define CMI_MATCH_STEPPING 3 /* Match down to stepping */ 13020c794b3Sgavinm 13120c794b3Sgavinm static void 13220c794b3Sgavinm cmi_link(cmi_t *cmi) 13320c794b3Sgavinm { 13420c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 13520c794b3Sgavinm 13620c794b3Sgavinm cmi->cmi_prev = NULL; 13720c794b3Sgavinm cmi->cmi_next = cmi_list; 13820c794b3Sgavinm if (cmi_list != NULL) 13920c794b3Sgavinm cmi_list->cmi_prev = cmi; 14020c794b3Sgavinm cmi_list = cmi; 14120c794b3Sgavinm } 14220c794b3Sgavinm 14320c794b3Sgavinm static void 14420c794b3Sgavinm cmi_unlink(cmi_t *cmi) 1457aec1d6eScindi { 14620c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 14720c794b3Sgavinm ASSERT(cmi->cmi_refcnt == 0); 14820c794b3Sgavinm 14920c794b3Sgavinm if (cmi->cmi_prev != NULL) 15020c794b3Sgavinm cmi->cmi_prev = cmi->cmi_next; 15120c794b3Sgavinm 15220c794b3Sgavinm if (cmi->cmi_next != NULL) 15320c794b3Sgavinm cmi->cmi_next->cmi_prev = cmi->cmi_prev; 15420c794b3Sgavinm 15520c794b3Sgavinm if (cmi_list == cmi) 15620c794b3Sgavinm cmi_list = cmi->cmi_next; 15720c794b3Sgavinm } 15820c794b3Sgavinm 15920c794b3Sgavinm /* 16020c794b3Sgavinm * Hold the module in memory. We call to CPU modules without using the 16120c794b3Sgavinm * stubs mechanism, so these modules must be manually held in memory. 16220c794b3Sgavinm * The mod_ref acts as if another loaded module has a dependency on us. 16320c794b3Sgavinm */ 16420c794b3Sgavinm static void 16520c794b3Sgavinm cmi_hold(cmi_t *cmi) 16620c794b3Sgavinm { 16720c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 16820c794b3Sgavinm 16920c794b3Sgavinm mutex_enter(&mod_lock); 17020c794b3Sgavinm cmi->cmi_modp->mod_ref++; 17120c794b3Sgavinm mutex_exit(&mod_lock); 17220c794b3Sgavinm cmi->cmi_refcnt++; 17320c794b3Sgavinm } 17420c794b3Sgavinm 17520c794b3Sgavinm static void 17620c794b3Sgavinm cmi_rele(cmi_t *cmi) 17720c794b3Sgavinm { 17820c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 17920c794b3Sgavinm 18020c794b3Sgavinm mutex_enter(&mod_lock); 18120c794b3Sgavinm cmi->cmi_modp->mod_ref--; 18220c794b3Sgavinm mutex_exit(&mod_lock); 18320c794b3Sgavinm 18420c794b3Sgavinm if (--cmi->cmi_refcnt == 0) { 18520c794b3Sgavinm cmi_unlink(cmi); 18620c794b3Sgavinm kmem_free(cmi, sizeof (cmi_t)); 18720c794b3Sgavinm } 18820c794b3Sgavinm } 18920c794b3Sgavinm 19020c794b3Sgavinm static cmi_ops_t * 19120c794b3Sgavinm cmi_getops(modctl_t *modp) 19220c794b3Sgavinm { 19320c794b3Sgavinm cmi_ops_t *ops; 19420c794b3Sgavinm 19520c794b3Sgavinm if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) == 19620c794b3Sgavinm NULL) { 19720c794b3Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops " 19820c794b3Sgavinm "found", modp->mod_modname); 19920c794b3Sgavinm return (NULL); 20020c794b3Sgavinm } 20120c794b3Sgavinm 20220c794b3Sgavinm if (ops->cmi_init == NULL) { 20320c794b3Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init " 20420c794b3Sgavinm "entry point", modp->mod_modname); 20520c794b3Sgavinm return (NULL); 20620c794b3Sgavinm } 20720c794b3Sgavinm 20820c794b3Sgavinm return (ops); 2097aec1d6eScindi } 2107aec1d6eScindi 2117aec1d6eScindi static cmi_t * 2127aec1d6eScindi cmi_load_modctl(modctl_t *modp) 2137aec1d6eScindi { 21420c794b3Sgavinm cmi_ops_t *ops; 21520c794b3Sgavinm uintptr_t ver; 2167aec1d6eScindi cmi_t *cmi; 21720c794b3Sgavinm cmi_api_ver_t apiver; 2187aec1d6eScindi 2197aec1d6eScindi ASSERT(MUTEX_HELD(&cmi_load_lock)); 2207aec1d6eScindi 2217aec1d6eScindi for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) { 2227aec1d6eScindi if (cmi->cmi_modp == modp) 2237aec1d6eScindi return (cmi); 2247aec1d6eScindi } 2257aec1d6eScindi 22620c794b3Sgavinm if ((ver = modlookup_by_modctl(modp, "_cmi_api_version")) == NULL) { 22720c794b3Sgavinm /* 22820c794b3Sgavinm * Apparently a cpu module before versioning was introduced - 22920c794b3Sgavinm * we call this version 0. 23020c794b3Sgavinm */ 23120c794b3Sgavinm apiver = CMI_API_VERSION_0; 23220c794b3Sgavinm } else { 23320c794b3Sgavinm apiver = *((cmi_api_ver_t *)ver); 23420c794b3Sgavinm if (!CMI_API_VERSION_CHKMAGIC(apiver)) { 23520c794b3Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: " 23620c794b3Sgavinm "_cmi_api_version 0x%x has bad magic", 23720c794b3Sgavinm modp->mod_modname, apiver); 23820c794b3Sgavinm return (NULL); 23920c794b3Sgavinm } 24020c794b3Sgavinm } 24120c794b3Sgavinm 24220c794b3Sgavinm if (apiver != CMI_API_VERSION) { 24320c794b3Sgavinm cmn_err(CE_WARN, "cpu module '%s' has API version %d, " 24420c794b3Sgavinm "kernel requires API version %d", modp->mod_modname, 24520c794b3Sgavinm CMI_API_VERSION_TOPRINT(apiver), 24620c794b3Sgavinm CMI_API_VERSION_TOPRINT(CMI_API_VERSION)); 2477aec1d6eScindi return (NULL); 2487aec1d6eScindi } 2497aec1d6eScindi 25020c794b3Sgavinm if ((ops = cmi_getops(modp)) == NULL) 25120c794b3Sgavinm return (NULL); 2527aec1d6eScindi 25320c794b3Sgavinm cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP); 25420c794b3Sgavinm cmi->cmi_ops = ops; 2557aec1d6eScindi cmi->cmi_modp = modp; 2567aec1d6eScindi 25720c794b3Sgavinm cmi_link(cmi); 2587aec1d6eScindi 2597aec1d6eScindi return (cmi); 2607aec1d6eScindi } 2617aec1d6eScindi 26220c794b3Sgavinm static int 26320c794b3Sgavinm cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match) 26420c794b3Sgavinm { 26520c794b3Sgavinm if (match >= CMI_MATCH_VENDOR && 26620c794b3Sgavinm cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2)) 26720c794b3Sgavinm return (0); 26820c794b3Sgavinm 26920c794b3Sgavinm if (match >= CMI_MATCH_FAMILY && 27020c794b3Sgavinm cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2)) 27120c794b3Sgavinm return (0); 27220c794b3Sgavinm 27320c794b3Sgavinm if (match >= CMI_MATCH_MODEL && 27420c794b3Sgavinm cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2)) 27520c794b3Sgavinm return (0); 27620c794b3Sgavinm 27720c794b3Sgavinm if (match >= CMI_MATCH_STEPPING && 27820c794b3Sgavinm cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2)) 27920c794b3Sgavinm return (0); 28020c794b3Sgavinm 28120c794b3Sgavinm return (1); 28220c794b3Sgavinm } 28320c794b3Sgavinm 28420c794b3Sgavinm static int 28520c794b3Sgavinm cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3) 28620c794b3Sgavinm { 28720c794b3Sgavinm cmi_hdl_t thdl = (cmi_hdl_t)arg1; 28820c794b3Sgavinm int match = *((int *)arg2); 28920c794b3Sgavinm cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3; 29020c794b3Sgavinm 29120c794b3Sgavinm if (cmi_cpu_match(thdl, whdl, match)) { 29220c794b3Sgavinm cmi_hdl_hold(whdl); /* short-term hold */ 29320c794b3Sgavinm *rsltp = whdl; 29420c794b3Sgavinm return (CMI_HDL_WALK_DONE); 29520c794b3Sgavinm } else { 29620c794b3Sgavinm return (CMI_HDL_WALK_NEXT); 29720c794b3Sgavinm } 29820c794b3Sgavinm } 29920c794b3Sgavinm 3007aec1d6eScindi static cmi_t * 30120c794b3Sgavinm cmi_search_list(cmi_hdl_t hdl, int match) 3027aec1d6eScindi { 30320c794b3Sgavinm cmi_hdl_t dhdl = NULL; 30420c794b3Sgavinm cmi_t *cmi = NULL; 3057aec1d6eScindi 3067aec1d6eScindi ASSERT(MUTEX_HELD(&cmi_load_lock)); 3077aec1d6eScindi 30820c794b3Sgavinm cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl); 30920c794b3Sgavinm if (dhdl) { 31020c794b3Sgavinm cmi = HDL2CMI(dhdl); 31120c794b3Sgavinm cmi_hdl_rele(dhdl); /* held in cmi_search_list_cb */ 3127aec1d6eScindi } 3137aec1d6eScindi 31420c794b3Sgavinm return (cmi); 31520c794b3Sgavinm } 31620c794b3Sgavinm 31720c794b3Sgavinm static cmi_t * 31820c794b3Sgavinm cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp) 31920c794b3Sgavinm { 32020c794b3Sgavinm modctl_t *modp; 32120c794b3Sgavinm cmi_t *cmi; 32220c794b3Sgavinm int modid; 32320c794b3Sgavinm uint_t s[3]; 32420c794b3Sgavinm 32520c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 32620c794b3Sgavinm ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL || 32720c794b3Sgavinm match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR); 3287aec1d6eScindi 3297aec1d6eScindi /* 33020c794b3Sgavinm * Have we already loaded a module for a cpu with the same 33120c794b3Sgavinm * vendor/family/model/stepping? 3327aec1d6eScindi */ 33320c794b3Sgavinm if ((cmi = cmi_search_list(hdl, match)) != NULL) { 33420c794b3Sgavinm cmi_hold(cmi); 33520c794b3Sgavinm return (cmi); 33620c794b3Sgavinm } 3377aec1d6eScindi 33820c794b3Sgavinm s[0] = cmi_hdl_family(hdl); 33920c794b3Sgavinm s[1] = cmi_hdl_model(hdl); 34020c794b3Sgavinm s[2] = cmi_hdl_stepping(hdl); 3417aec1d6eScindi modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX, 34220c794b3Sgavinm cmi_hdl_vendorstr(hdl), ".", s, match, chosenp); 3437aec1d6eScindi 3447aec1d6eScindi if (modid == -1) 3457aec1d6eScindi return (NULL); 3467aec1d6eScindi 3477aec1d6eScindi modp = mod_hold_by_id(modid); 3487aec1d6eScindi cmi = cmi_load_modctl(modp); 34920c794b3Sgavinm if (cmi) 35020c794b3Sgavinm cmi_hold(cmi); 3517aec1d6eScindi mod_release_mod(modp); 3527aec1d6eScindi 3537aec1d6eScindi return (cmi); 3547aec1d6eScindi } 3557aec1d6eScindi 35620c794b3Sgavinm /* 35720c794b3Sgavinm * Try to load a cpu module with specific support for this chip type. 35820c794b3Sgavinm */ 3597aec1d6eScindi static cmi_t * 36020c794b3Sgavinm cmi_load_specific(cmi_hdl_t hdl, void **datap) 36120c794b3Sgavinm { 36220c794b3Sgavinm cmi_t *cmi; 36320c794b3Sgavinm int err; 36420c794b3Sgavinm int i; 36520c794b3Sgavinm 36620c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 36720c794b3Sgavinm 36820c794b3Sgavinm for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) { 36920c794b3Sgavinm int suffixlevel; 37020c794b3Sgavinm 37120c794b3Sgavinm if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL) 37220c794b3Sgavinm return (NULL); 37320c794b3Sgavinm 37420c794b3Sgavinm /* 37520c794b3Sgavinm * A module has loaded and has a _cmi_ops structure, and the 37620c794b3Sgavinm * module has been held for this instance. Call its cmi_init 37720c794b3Sgavinm * entry point - we expect success (0) or ENOTSUP. 37820c794b3Sgavinm */ 37920c794b3Sgavinm if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) { 38020c794b3Sgavinm if (boothowto & RB_VERBOSE) { 38120c794b3Sgavinm printf("initialized cpu module '%s' on " 38220c794b3Sgavinm "chip %d core %d strand %d\n", 38320c794b3Sgavinm cmi->cmi_modp->mod_modname, 38420c794b3Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 38520c794b3Sgavinm cmi_hdl_strandid(hdl)); 38620c794b3Sgavinm } 38720c794b3Sgavinm return (cmi); 38820c794b3Sgavinm } else if (err != ENOTSUP) { 38920c794b3Sgavinm cmn_err(CE_WARN, "failed to init cpu module '%s' on " 39020c794b3Sgavinm "chip %d core %d strand %d: err=%d\n", 39120c794b3Sgavinm cmi->cmi_modp->mod_modname, 39220c794b3Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 39320c794b3Sgavinm cmi_hdl_strandid(hdl), err); 39420c794b3Sgavinm } 39520c794b3Sgavinm 39620c794b3Sgavinm /* 39720c794b3Sgavinm * The module failed or declined to init, so release 39820c794b3Sgavinm * it and update i to be equal to the number 39920c794b3Sgavinm * of suffices actually used in the last module path. 40020c794b3Sgavinm */ 40120c794b3Sgavinm cmi_rele(cmi); 40220c794b3Sgavinm i = suffixlevel; 40320c794b3Sgavinm } 40420c794b3Sgavinm 40520c794b3Sgavinm return (NULL); 40620c794b3Sgavinm } 40720c794b3Sgavinm 40820c794b3Sgavinm /* 40920c794b3Sgavinm * Load the generic IA32 MCA cpu module, which may still supplement 41020c794b3Sgavinm * itself with model-specific support through cpu model-specific modules. 41120c794b3Sgavinm */ 41220c794b3Sgavinm static cmi_t * 41320c794b3Sgavinm cmi_load_generic(cmi_hdl_t hdl, void **datap) 4147aec1d6eScindi { 4157aec1d6eScindi modctl_t *modp; 4167aec1d6eScindi cmi_t *cmi; 4177aec1d6eScindi int modid; 41820c794b3Sgavinm int err; 41920c794b3Sgavinm 42020c794b3Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 4217aec1d6eScindi 4227aec1d6eScindi if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1) 4237aec1d6eScindi return (NULL); 4247aec1d6eScindi 4257aec1d6eScindi modp = mod_hold_by_id(modid); 4267aec1d6eScindi cmi = cmi_load_modctl(modp); 42720c794b3Sgavinm if (cmi) 42820c794b3Sgavinm cmi_hold(cmi); 4297aec1d6eScindi mod_release_mod(modp); 4307aec1d6eScindi 43120c794b3Sgavinm if (cmi == NULL) 43220c794b3Sgavinm return (NULL); 43320c794b3Sgavinm 43420c794b3Sgavinm if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) { 43520c794b3Sgavinm if (err != ENOTSUP) 43620c794b3Sgavinm cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to " 43720c794b3Sgavinm "init: err=%d", err); 43820c794b3Sgavinm cmi_rele(cmi); 43920c794b3Sgavinm return (NULL); 44020c794b3Sgavinm } 44120c794b3Sgavinm 4427aec1d6eScindi return (cmi); 4437aec1d6eScindi } 4447aec1d6eScindi 44520c794b3Sgavinm cmi_hdl_t 44620c794b3Sgavinm cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid, 447e4b86885SCheng Sean Ye uint_t strandid) 4487aec1d6eScindi { 44920c794b3Sgavinm cmi_t *cmi = NULL; 45020c794b3Sgavinm cmi_hdl_t hdl; 4517aec1d6eScindi void *data; 4527aec1d6eScindi 45320c794b3Sgavinm if (cmi_no_init) { 45420c794b3Sgavinm cmi_no_mca_init = 1; 45520c794b3Sgavinm return (NULL); 45620c794b3Sgavinm } 45720c794b3Sgavinm 4587aec1d6eScindi mutex_enter(&cmi_load_lock); 4597aec1d6eScindi 460e4b86885SCheng Sean Ye if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) { 4617aec1d6eScindi mutex_exit(&cmi_load_lock); 46220c794b3Sgavinm cmn_err(CE_WARN, "There will be no MCA support on chip %d " 46320c794b3Sgavinm "core %d strand %d (cmi_hdl_create returned NULL)\n", 46420c794b3Sgavinm chipid, coreid, strandid); 46520c794b3Sgavinm return (NULL); 4667aec1d6eScindi } 4677aec1d6eScindi 46820c794b3Sgavinm if (!cmi_force_generic) 46920c794b3Sgavinm cmi = cmi_load_specific(hdl, &data); 47020c794b3Sgavinm 47120c794b3Sgavinm if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) { 47220c794b3Sgavinm cmn_err(CE_WARN, "There will be no MCA support on chip %d " 47320c794b3Sgavinm "core %d strand %d\n", chipid, coreid, strandid); 47420c794b3Sgavinm cmi_hdl_rele(hdl); 4757aec1d6eScindi mutex_exit(&cmi_load_lock); 47620c794b3Sgavinm return (NULL); 4777aec1d6eScindi } 4787aec1d6eScindi 47920c794b3Sgavinm cmi_hdl_setcmi(hdl, cmi, data); 4807aec1d6eScindi 48120c794b3Sgavinm cms_init(hdl); 4827aec1d6eScindi 483074bb90dSTom Pothier cmi_read_smbios(hdl); 484074bb90dSTom Pothier 48520c794b3Sgavinm mutex_exit(&cmi_load_lock); 4867aec1d6eScindi 48720c794b3Sgavinm return (hdl); 4887aec1d6eScindi } 4897aec1d6eScindi 49020c794b3Sgavinm /* 491a3114836SGerry Liu * cmi_fini is called on DR deconfigure of a cpu resource. 492a3114836SGerry Liu * It should not be called at simple offline of a cpu. 49320c794b3Sgavinm */ 4947aec1d6eScindi void 49520c794b3Sgavinm cmi_fini(cmi_hdl_t hdl) 4967aec1d6eScindi { 49720c794b3Sgavinm cmi_t *cmi = HDL2CMI(hdl); 49820c794b3Sgavinm 49920c794b3Sgavinm if (cms_present(hdl)) 50020c794b3Sgavinm cms_fini(hdl); 50120c794b3Sgavinm 50220c794b3Sgavinm if (CMI_OP_PRESENT(cmi, cmi_fini)) 50320c794b3Sgavinm CMI_OPS(cmi)->cmi_fini(hdl); 50420c794b3Sgavinm 505a3114836SGerry Liu cmi_hdl_destroy(hdl); 5067aec1d6eScindi } 5077aec1d6eScindi 50820c794b3Sgavinm /* 509e4b86885SCheng Sean Ye * cmi_post_startup is called from post_startup for the boot cpu only (no 510e4b86885SCheng Sean Ye * other cpus are started yet). 51120c794b3Sgavinm */ 5127aec1d6eScindi void 51320c794b3Sgavinm cmi_post_startup(void) 5147aec1d6eScindi { 51520c794b3Sgavinm cmi_hdl_t hdl; 51620c794b3Sgavinm cmi_t *cmi; 51720c794b3Sgavinm 51820c794b3Sgavinm if (cmi_no_mca_init != 0 || 51920c794b3Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 52020c794b3Sgavinm return; 52120c794b3Sgavinm 52220c794b3Sgavinm cmi = HDL2CMI(hdl); 52320c794b3Sgavinm 52420c794b3Sgavinm if (CMI_OP_PRESENT(cmi, cmi_post_startup)) 52520c794b3Sgavinm CMI_OPS(cmi)->cmi_post_startup(hdl); 52620c794b3Sgavinm 52720c794b3Sgavinm cmi_hdl_rele(hdl); 5287aec1d6eScindi } 5297aec1d6eScindi 5308a40a695Sgavinm /* 5318a40a695Sgavinm * Called just once from start_other_cpus when all processors are started. 5328a40a695Sgavinm * This will not be called for each cpu, so the registered op must not 533e4b86885SCheng Sean Ye * assume it is called as such. We are not necessarily executing on 534e4b86885SCheng Sean Ye * the boot cpu. 5358a40a695Sgavinm */ 5363ad553a7Sgavinm void 5373ad553a7Sgavinm cmi_post_mpstartup(void) 5383ad553a7Sgavinm { 53920c794b3Sgavinm cmi_hdl_t hdl; 54020c794b3Sgavinm cmi_t *cmi; 54120c794b3Sgavinm 54220c794b3Sgavinm if (cmi_no_mca_init != 0 || 54320c794b3Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 54420c794b3Sgavinm return; 54520c794b3Sgavinm 54620c794b3Sgavinm cmi = HDL2CMI(hdl); 54720c794b3Sgavinm 54820c794b3Sgavinm if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup)) 54920c794b3Sgavinm CMI_OPS(cmi)->cmi_post_mpstartup(hdl); 55020c794b3Sgavinm 55120c794b3Sgavinm cmi_hdl_rele(hdl); 55220c794b3Sgavinm } 55320c794b3Sgavinm 55420c794b3Sgavinm void 55520c794b3Sgavinm cmi_faulted_enter(cmi_hdl_t hdl) 55620c794b3Sgavinm { 55720c794b3Sgavinm cmi_t *cmi = HDL2CMI(hdl); 55820c794b3Sgavinm 55920c794b3Sgavinm if (cmi_no_mca_init != 0) 56020c794b3Sgavinm return; 56120c794b3Sgavinm 56220c794b3Sgavinm if (CMI_OP_PRESENT(cmi, cmi_faulted_enter)) 56320c794b3Sgavinm CMI_OPS(cmi)->cmi_faulted_enter(hdl); 5643ad553a7Sgavinm } 5653ad553a7Sgavinm 5667aec1d6eScindi void 56720c794b3Sgavinm cmi_faulted_exit(cmi_hdl_t hdl) 5687aec1d6eScindi { 56920c794b3Sgavinm cmi_t *cmi = HDL2CMI(hdl); 57020c794b3Sgavinm 57120c794b3Sgavinm if (cmi_no_mca_init != 0) 57220c794b3Sgavinm return; 57320c794b3Sgavinm 57420c794b3Sgavinm if (CMI_OP_PRESENT(cmi, cmi_faulted_exit)) 57520c794b3Sgavinm CMI_OPS(cmi)->cmi_faulted_exit(hdl); 5767aec1d6eScindi } 5777aec1d6eScindi 5787aec1d6eScindi void 57920c794b3Sgavinm cmi_mca_init(cmi_hdl_t hdl) 5807aec1d6eScindi { 58120c794b3Sgavinm cmi_t *cmi; 58220c794b3Sgavinm 58320c794b3Sgavinm if (cmi_no_mca_init != 0) 58420c794b3Sgavinm return; 58520c794b3Sgavinm 58620c794b3Sgavinm cmi = HDL2CMI(hdl); 58720c794b3Sgavinm 58820c794b3Sgavinm if (CMI_OP_PRESENT(cmi, cmi_mca_init)) 58920c794b3Sgavinm CMI_OPS(cmi)->cmi_mca_init(hdl); 5907aec1d6eScindi } 5917aec1d6eScindi 59220c794b3Sgavinm #define CMI_RESPONSE_PANIC 0x0 /* panic must have value 0 */ 59320c794b3Sgavinm #define CMI_RESPONSE_NONE 0x1 59420c794b3Sgavinm #define CMI_RESPONSE_CKILL 0x2 59520c794b3Sgavinm #define CMI_RESPONSE_REBOOT 0x3 /* not implemented */ 59620c794b3Sgavinm #define CMI_RESPONSE_ONTRAP_PROT 0x4 59720c794b3Sgavinm #define CMI_RESPONSE_LOFAULT_PROT 0x5 59820c794b3Sgavinm 59920c794b3Sgavinm /* 60020c794b3Sgavinm * Return 0 if we will panic in response to this machine check, otherwise 60120c794b3Sgavinm * non-zero. If the caller is cmi_mca_trap in this file then the nonzero 60220c794b3Sgavinm * return values are to be interpreted from CMI_RESPONSE_* above. 60320c794b3Sgavinm * 60420c794b3Sgavinm * This function must just return what will be done without actually 60520c794b3Sgavinm * doing anything; this includes not changing the regs. 60620c794b3Sgavinm */ 6077aec1d6eScindi int 60820c794b3Sgavinm cmi_mce_response(struct regs *rp, uint64_t disp) 6097aec1d6eScindi { 61020c794b3Sgavinm int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC : 61120c794b3Sgavinm CMI_RESPONSE_NONE; 61220c794b3Sgavinm on_trap_data_t *otp; 61320c794b3Sgavinm 61420c794b3Sgavinm ASSERT(rp != NULL); /* don't call for polling, only on #MC */ 61520c794b3Sgavinm 61620c794b3Sgavinm /* 61720c794b3Sgavinm * If no bits are set in the disposition then there is nothing to 61820c794b3Sgavinm * worry about and we do not need to trampoline to ontrap or 61920c794b3Sgavinm * lofault handlers. 62020c794b3Sgavinm */ 62120c794b3Sgavinm if (disp == 0) 62220c794b3Sgavinm return (CMI_RESPONSE_NONE); 62320c794b3Sgavinm 62420c794b3Sgavinm /* 62520c794b3Sgavinm * Unconstrained errors cannot be forgiven, even by ontrap or 62620c794b3Sgavinm * lofault protection. The data is not poisoned and may not 62720c794b3Sgavinm * even belong to the trapped context - eg a writeback of 62820c794b3Sgavinm * data that is found to be bad. 62920c794b3Sgavinm */ 63020c794b3Sgavinm if (disp & CMI_ERRDISP_UC_UNCONSTRAINED) 63120c794b3Sgavinm return (panicrsp); 63220c794b3Sgavinm 63320c794b3Sgavinm /* 63420c794b3Sgavinm * ontrap OT_DATA_EC and lofault protection forgive any disposition 63520c794b3Sgavinm * other than unconstrained, even those normally forced fatal. 63620c794b3Sgavinm */ 63720c794b3Sgavinm if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC) 63820c794b3Sgavinm return (CMI_RESPONSE_ONTRAP_PROT); 63920c794b3Sgavinm else if (curthread->t_lofault) 64020c794b3Sgavinm return (CMI_RESPONSE_LOFAULT_PROT); 64120c794b3Sgavinm 64220c794b3Sgavinm /* 64320c794b3Sgavinm * Forced-fatal errors are terminal even in user mode. 64420c794b3Sgavinm */ 64520c794b3Sgavinm if (disp & CMI_ERRDISP_FORCEFATAL) 64620c794b3Sgavinm return (panicrsp); 64720c794b3Sgavinm 64820c794b3Sgavinm /* 64920c794b3Sgavinm * If the trapped context is corrupt or we have no instruction pointer 65020c794b3Sgavinm * to resume at (and aren't trampolining to a fault handler) 65120c794b3Sgavinm * then in the kernel case we must panic and in usermode we 65220c794b3Sgavinm * kill the affected contract. 65320c794b3Sgavinm */ 65420c794b3Sgavinm if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID)) 65520c794b3Sgavinm return (USERMODE(rp->r_cs) ? CMI_RESPONSE_CKILL : panicrsp); 65620c794b3Sgavinm 65720c794b3Sgavinm /* 65820c794b3Sgavinm * Anything else is harmless 65920c794b3Sgavinm */ 66020c794b3Sgavinm return (CMI_RESPONSE_NONE); 6617aec1d6eScindi } 6627aec1d6eScindi 66320c794b3Sgavinm int cma_mca_trap_panic_suppressed = 0; 66420c794b3Sgavinm 66520c794b3Sgavinm static void 66620c794b3Sgavinm cmi_mca_panic(void) 6677aec1d6eScindi { 66820c794b3Sgavinm if (cmi_panic_on_uncorrectable_error) { 66920c794b3Sgavinm fm_panic("Unrecoverable Machine-Check Exception"); 67020c794b3Sgavinm } else { 67120c794b3Sgavinm cmn_err(CE_WARN, "suppressing panic from fatal #mc"); 67220c794b3Sgavinm cma_mca_trap_panic_suppressed++; 67320c794b3Sgavinm } 6747aec1d6eScindi } 6757aec1d6eScindi 67620c794b3Sgavinm 67720c794b3Sgavinm int cma_mca_trap_contract_kills = 0; 67820c794b3Sgavinm int cma_mca_trap_ontrap_forgiven = 0; 67920c794b3Sgavinm int cma_mca_trap_lofault_forgiven = 0; 68020c794b3Sgavinm 68120c794b3Sgavinm /* 68220c794b3Sgavinm * Native #MC handler - we branch to here from mcetrap 68320c794b3Sgavinm */ 68420c794b3Sgavinm /*ARGSUSED*/ 6857aec1d6eScindi void 6867aec1d6eScindi cmi_mca_trap(struct regs *rp) 6877aec1d6eScindi { 68820c794b3Sgavinm #ifndef __xpv 68920c794b3Sgavinm cmi_hdl_t hdl = NULL; 69020c794b3Sgavinm uint64_t disp; 69120c794b3Sgavinm cmi_t *cmi; 69220c794b3Sgavinm int s; 69320c794b3Sgavinm 69420c794b3Sgavinm if (cmi_no_mca_init != 0) 69520c794b3Sgavinm return; 69620c794b3Sgavinm 69720c794b3Sgavinm /* 69820c794b3Sgavinm * This function can call cmn_err, and the cpu module cmi_mca_trap 69920c794b3Sgavinm * entry point may also elect to call cmn_err (e.g., if it can't 70020c794b3Sgavinm * log the error onto an errorq, say very early in boot). 70120c794b3Sgavinm * We need to let cprintf know that we must not block. 70220c794b3Sgavinm */ 70320c794b3Sgavinm s = spl8(); 70420c794b3Sgavinm 70520c794b3Sgavinm if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU), 70620c794b3Sgavinm cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL || 70720c794b3Sgavinm (cmi = HDL2CMI(hdl)) == NULL || 70820c794b3Sgavinm !CMI_OP_PRESENT(cmi, cmi_mca_trap)) { 70920c794b3Sgavinm 71020c794b3Sgavinm cmn_err(CE_WARN, "#MC exception on cpuid %d: %s", 71120c794b3Sgavinm CPU->cpu_id, 71220c794b3Sgavinm hdl ? "handle lookup ok but no #MC handler found" : 71320c794b3Sgavinm "handle lookup failed"); 71420c794b3Sgavinm 71520c794b3Sgavinm if (hdl != NULL) 71620c794b3Sgavinm cmi_hdl_rele(hdl); 71720c794b3Sgavinm 71820c794b3Sgavinm splx(s); 71920c794b3Sgavinm return; 7207aec1d6eScindi } 7217aec1d6eScindi 72220c794b3Sgavinm disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp); 72320c794b3Sgavinm 72420c794b3Sgavinm switch (cmi_mce_response(rp, disp)) { 72520c794b3Sgavinm default: 72620c794b3Sgavinm cmn_err(CE_WARN, "Invalid response from cmi_mce_response"); 72720c794b3Sgavinm /*FALLTHRU*/ 7287aec1d6eScindi 72920c794b3Sgavinm case CMI_RESPONSE_PANIC: 73020c794b3Sgavinm cmi_mca_panic(); 73120c794b3Sgavinm break; 7327aec1d6eScindi 73320c794b3Sgavinm case CMI_RESPONSE_NONE: 73420c794b3Sgavinm break; 73520c794b3Sgavinm 73620c794b3Sgavinm case CMI_RESPONSE_CKILL: 73720c794b3Sgavinm ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR; 73820c794b3Sgavinm aston(curthread); 73920c794b3Sgavinm cma_mca_trap_contract_kills++; 74020c794b3Sgavinm break; 74120c794b3Sgavinm 74220c794b3Sgavinm case CMI_RESPONSE_ONTRAP_PROT: { 74320c794b3Sgavinm on_trap_data_t *otp = curthread->t_ontrap; 74420c794b3Sgavinm otp->ot_trap = OT_DATA_EC; 74520c794b3Sgavinm rp->r_pc = otp->ot_trampoline; 74620c794b3Sgavinm cma_mca_trap_ontrap_forgiven++; 74720c794b3Sgavinm break; 74820c794b3Sgavinm } 74920c794b3Sgavinm 75020c794b3Sgavinm case CMI_RESPONSE_LOFAULT_PROT: 75120c794b3Sgavinm rp->r_r0 = EFAULT; 75220c794b3Sgavinm rp->r_pc = curthread->t_lofault; 75320c794b3Sgavinm cma_mca_trap_lofault_forgiven++; 75420c794b3Sgavinm break; 75520c794b3Sgavinm } 75620c794b3Sgavinm 75720c794b3Sgavinm cmi_hdl_rele(hdl); 75820c794b3Sgavinm splx(s); 75920c794b3Sgavinm #endif /* __xpv */ 7607aec1d6eScindi } 7617aec1d6eScindi 7627aec1d6eScindi void 76320c794b3Sgavinm cmi_hdl_poke(cmi_hdl_t hdl) 7647aec1d6eScindi { 76520c794b3Sgavinm cmi_t *cmi = HDL2CMI(hdl); 76620c794b3Sgavinm 76720c794b3Sgavinm if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke)) 76820c794b3Sgavinm return; 76920c794b3Sgavinm 77020c794b3Sgavinm CMI_OPS(cmi)->cmi_hdl_poke(hdl); 7717aec1d6eScindi } 7727aec1d6eScindi 773e4b86885SCheng Sean Ye #ifndef __xpv 774e3d60c9bSAdrian Frost void 775e3d60c9bSAdrian Frost cmi_cmci_trap() 776e3d60c9bSAdrian Frost { 777e3d60c9bSAdrian Frost cmi_hdl_t hdl = NULL; 778e3d60c9bSAdrian Frost cmi_t *cmi; 779e3d60c9bSAdrian Frost 780e3d60c9bSAdrian Frost if (cmi_no_mca_init != 0) 781e3d60c9bSAdrian Frost return; 782e3d60c9bSAdrian Frost 783e3d60c9bSAdrian Frost if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU), 784e3d60c9bSAdrian Frost cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL || 785e3d60c9bSAdrian Frost (cmi = HDL2CMI(hdl)) == NULL || 786e3d60c9bSAdrian Frost !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) { 787e3d60c9bSAdrian Frost 788e3d60c9bSAdrian Frost cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s", 789e3d60c9bSAdrian Frost CPU->cpu_id, 790e3d60c9bSAdrian Frost hdl ? "handle lookup ok but no CMCI handler found" : 791e3d60c9bSAdrian Frost "handle lookup failed"); 792e3d60c9bSAdrian Frost 793e3d60c9bSAdrian Frost if (hdl != NULL) 794e3d60c9bSAdrian Frost cmi_hdl_rele(hdl); 795e3d60c9bSAdrian Frost 796e3d60c9bSAdrian Frost return; 797e3d60c9bSAdrian Frost } 798e3d60c9bSAdrian Frost 799e3d60c9bSAdrian Frost CMI_OPS(cmi)->cmi_cmci_trap(hdl); 800e3d60c9bSAdrian Frost 801e3d60c9bSAdrian Frost cmi_hdl_rele(hdl); 802e3d60c9bSAdrian Frost } 803e4b86885SCheng Sean Ye #endif /* __xpv */ 804e3d60c9bSAdrian Frost 8057aec1d6eScindi void 80620c794b3Sgavinm cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata) 8077aec1d6eScindi { 80820c794b3Sgavinm if (!cmi_no_mca_init) 80920c794b3Sgavinm cmi_hdl_setmc(hdl, mcops, mcdata); 8107aec1d6eScindi } 8117aec1d6eScindi 812a3114836SGerry Liu cmi_errno_t 813a3114836SGerry Liu cmi_mc_register_global(const cmi_mc_ops_t *mcops, void *mcdata) 814a3114836SGerry Liu { 815a3114836SGerry Liu if (!cmi_no_mca_init) { 816a3114836SGerry Liu if (cmi_mc_global_ops != NULL || cmi_mc_global_data != NULL || 817a3114836SGerry Liu mcops == NULL || mcops->cmi_mc_patounum == NULL || 818a3114836SGerry Liu mcops->cmi_mc_unumtopa == NULL) { 819a3114836SGerry Liu return (CMIERR_UNKNOWN); 820a3114836SGerry Liu } 821a3114836SGerry Liu cmi_mc_global_data = mcdata; 822a3114836SGerry Liu cmi_mc_global_ops = mcops; 823a3114836SGerry Liu } 824a3114836SGerry Liu return (CMI_SUCCESS); 825a3114836SGerry Liu } 826a3114836SGerry Liu 827e4b86885SCheng Sean Ye void 828e4b86885SCheng Sean Ye cmi_mc_sw_memscrub_disable(void) 829e4b86885SCheng Sean Ye { 830e4b86885SCheng Sean Ye memscrub_disable(); 831e4b86885SCheng Sean Ye } 832e4b86885SCheng Sean Ye 83320c794b3Sgavinm cmi_errno_t 8344156fc34Sgavinm cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd, 8354156fc34Sgavinm int syndtype, mc_unum_t *up) 8367aec1d6eScindi { 8377aec1d6eScindi const struct cmi_mc_ops *mcops; 83820c794b3Sgavinm cmi_hdl_t hdl; 83920c794b3Sgavinm cmi_errno_t rv; 84020c794b3Sgavinm 841a3114836SGerry Liu if (cmi_no_mca_init) 842a3114836SGerry Liu return (CMIERR_MC_ABSENT); 843a3114836SGerry Liu 844a3114836SGerry Liu if (cmi_mc_global_ops != NULL) { 845a3114836SGerry Liu if (cmi_mc_global_ops->cmi_mc_patounum == NULL) 846a3114836SGerry Liu return (CMIERR_MC_NOTSUP); 847a3114836SGerry Liu return (cmi_mc_global_ops->cmi_mc_patounum(cmi_mc_global_data, 848a3114836SGerry Liu pa, valid_hi, valid_lo, synd, syndtype, up)); 849a3114836SGerry Liu } 850a3114836SGerry Liu 851a3114836SGerry Liu if ((hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 85220c794b3Sgavinm return (CMIERR_MC_ABSENT); 85320c794b3Sgavinm 85420c794b3Sgavinm if ((mcops = cmi_hdl_getmcops(hdl)) == NULL || 85520c794b3Sgavinm mcops->cmi_mc_patounum == NULL) { 85620c794b3Sgavinm cmi_hdl_rele(hdl); 85720c794b3Sgavinm return (CMIERR_MC_NOTSUP); 85820c794b3Sgavinm } 8597aec1d6eScindi 86020c794b3Sgavinm rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi, 86120c794b3Sgavinm valid_lo, synd, syndtype, up); 8627aec1d6eScindi 86320c794b3Sgavinm cmi_hdl_rele(hdl); 86420c794b3Sgavinm 86520c794b3Sgavinm return (rv); 8667aec1d6eScindi } 8677aec1d6eScindi 86820c794b3Sgavinm cmi_errno_t 8697aec1d6eScindi cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap) 8707aec1d6eScindi { 8717aec1d6eScindi const struct cmi_mc_ops *mcops; 87220c794b3Sgavinm cmi_hdl_t hdl; 87320c794b3Sgavinm cmi_errno_t rv; 874e4b86885SCheng Sean Ye nvlist_t *hcsp; 8757aec1d6eScindi 8767aec1d6eScindi if (up != NULL && nvl != NULL) 87720c794b3Sgavinm return (CMIERR_API); /* convert from just one form */ 87820c794b3Sgavinm 879a3114836SGerry Liu if (cmi_no_mca_init) 880a3114836SGerry Liu return (CMIERR_MC_ABSENT); 881a3114836SGerry Liu 882a3114836SGerry Liu if (cmi_mc_global_ops != NULL) { 883a3114836SGerry Liu if (cmi_mc_global_ops->cmi_mc_unumtopa == NULL) 884a3114836SGerry Liu return (CMIERR_MC_NOTSUP); 885a3114836SGerry Liu return (cmi_mc_global_ops->cmi_mc_unumtopa(cmi_mc_global_data, 886a3114836SGerry Liu up, nvl, pap)); 887a3114836SGerry Liu } 888a3114836SGerry Liu 889a3114836SGerry Liu if ((hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 89020c794b3Sgavinm return (CMIERR_MC_ABSENT); 89120c794b3Sgavinm 89220c794b3Sgavinm if ((mcops = cmi_hdl_getmcops(hdl)) == NULL || 89320c794b3Sgavinm mcops->cmi_mc_unumtopa == NULL) { 89420c794b3Sgavinm cmi_hdl_rele(hdl); 89520c794b3Sgavinm 896e4b86885SCheng Sean Ye if (nvl != NULL && nvlist_lookup_nvlist(nvl, 897e4b86885SCheng Sean Ye FM_FMRI_HC_SPECIFIC, &hcsp) == 0 && 898e4b86885SCheng Sean Ye (nvlist_lookup_uint64(hcsp, 899e4b86885SCheng Sean Ye "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, pap) == 0 || 900e4b86885SCheng Sean Ye nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR, 901e4b86885SCheng Sean Ye pap) == 0)) { 90220c794b3Sgavinm return (CMIERR_MC_PARTIALUNUMTOPA); 90320c794b3Sgavinm } else { 904a3114836SGerry Liu return (mcops && mcops->cmi_mc_unumtopa == NULL ? 90520c794b3Sgavinm CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT); 90620c794b3Sgavinm } 90720c794b3Sgavinm } 9087aec1d6eScindi 90920c794b3Sgavinm rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap); 9107aec1d6eScindi 91120c794b3Sgavinm cmi_hdl_rele(hdl); 91220c794b3Sgavinm 91320c794b3Sgavinm return (rv); 91420c794b3Sgavinm } 91520c794b3Sgavinm 91620c794b3Sgavinm void 91720c794b3Sgavinm cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync) 91820c794b3Sgavinm { 91920c794b3Sgavinm const struct cmi_mc_ops *mcops; 92020c794b3Sgavinm 921a3114836SGerry Liu if (cmi_no_mca_init) 92220c794b3Sgavinm return; 92320c794b3Sgavinm 924a3114836SGerry Liu if (cmi_mc_global_ops != NULL) 925a3114836SGerry Liu mcops = cmi_mc_global_ops; 926a3114836SGerry Liu else 927a3114836SGerry Liu mcops = cmi_hdl_getmcops(hdl); 928a3114836SGerry Liu 929a3114836SGerry Liu if (mcops != NULL && mcops->cmi_mc_logout != NULL) 93020c794b3Sgavinm mcops->cmi_mc_logout(hdl, ismc, sync); 93120c794b3Sgavinm } 93220c794b3Sgavinm 93320c794b3Sgavinm cmi_errno_t 93420c794b3Sgavinm cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs, 93520c794b3Sgavinm int force) 93620c794b3Sgavinm { 93720c794b3Sgavinm cmi_t *cmi = cmi_hdl_getcmi(hdl); 938e4b86885SCheng Sean Ye cmi_errno_t rc; 93920c794b3Sgavinm 94020c794b3Sgavinm if (!CMI_OP_PRESENT(cmi, cmi_msrinject)) 94120c794b3Sgavinm return (CMIERR_NOTSUP); 94220c794b3Sgavinm 943e4b86885SCheng Sean Ye cmi_hdl_inj_begin(hdl); 944e4b86885SCheng Sean Ye rc = CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force); 945e4b86885SCheng Sean Ye cmi_hdl_inj_end(hdl); 946e4b86885SCheng Sean Ye 947e4b86885SCheng Sean Ye return (rc); 94820c794b3Sgavinm } 94920c794b3Sgavinm 95020c794b3Sgavinm boolean_t 95120c794b3Sgavinm cmi_panic_on_ue(void) 95220c794b3Sgavinm { 95320c794b3Sgavinm return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE); 9547aec1d6eScindi } 955e4b86885SCheng Sean Ye 956e4b86885SCheng Sean Ye void 957e4b86885SCheng Sean Ye cmi_panic_callback(void) 958e4b86885SCheng Sean Ye { 959e4b86885SCheng Sean Ye cmi_hdl_t hdl; 960e4b86885SCheng Sean Ye cmi_t *cmi; 961e4b86885SCheng Sean Ye 962e4b86885SCheng Sean Ye if (cmi_no_mca_init || (hdl = cmi_hdl_any()) == NULL) 963e4b86885SCheng Sean Ye return; 964e4b86885SCheng Sean Ye 965e4b86885SCheng Sean Ye cmi = cmi_hdl_getcmi(hdl); 966e4b86885SCheng Sean Ye if (CMI_OP_PRESENT(cmi, cmi_panic_callback)) 967e4b86885SCheng Sean Ye CMI_OPS(cmi)->cmi_panic_callback(); 968e4b86885SCheng Sean Ye 969e4b86885SCheng Sean Ye cmi_hdl_rele(hdl); 970e4b86885SCheng Sean Ye } 971*2a613b59SRobert Mustacchi 972*2a613b59SRobert Mustacchi 973*2a613b59SRobert Mustacchi const char * 974*2a613b59SRobert Mustacchi cmi_hdl_chipident(cmi_hdl_t hdl) 975*2a613b59SRobert Mustacchi { 976*2a613b59SRobert Mustacchi cmi_t *cmi = cmi_hdl_getcmi(hdl); 977*2a613b59SRobert Mustacchi 978*2a613b59SRobert Mustacchi if (!CMI_OP_PRESENT(cmi, cmi_ident)) 979*2a613b59SRobert Mustacchi return (NULL); 980*2a613b59SRobert Mustacchi 981*2a613b59SRobert Mustacchi return (CMI_OPS(cmi)->cmi_ident(hdl)); 982*2a613b59SRobert Mustacchi } 983