11642Sgavinm /*
21642Sgavinm * CDDL HEADER START
31642Sgavinm *
41642Sgavinm * The contents of this file are subject to the terms of the
51642Sgavinm * Common Development and Distribution License (the "License").
61642Sgavinm * You may not use this file except in compliance with the License.
71642Sgavinm *
81642Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91642Sgavinm * or http://www.opensolaris.org/os/licensing.
101642Sgavinm * See the License for the specific language governing permissions
111642Sgavinm * and limitations under the License.
121642Sgavinm *
131642Sgavinm * When distributing Covered Code, include this CDDL HEADER in each
141642Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151642Sgavinm * If applicable, add the following below this CDDL HEADER, with the
161642Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying
171642Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner]
181642Sgavinm *
191642Sgavinm * CDDL HEADER END
201642Sgavinm */
211642Sgavinm
221414Scindi /*
23*12004Sjiang.liu@intel.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
241414Scindi * Use is subject to license terms.
251414Scindi */
261414Scindi
271414Scindi /*
281414Scindi * Public interface to routines implemented by CPU modules
291414Scindi */
301414Scindi
315254Sgavinm #include <sys/types.h>
325254Sgavinm #include <sys/atomic.h>
331414Scindi #include <sys/x86_archext.h>
341414Scindi #include <sys/cpu_module_impl.h>
355254Sgavinm #include <sys/cpu_module_ms.h>
361414Scindi #include <sys/fm/util.h>
371414Scindi #include <sys/reboot.h>
381414Scindi #include <sys/modctl.h>
391414Scindi #include <sys/param.h>
401414Scindi #include <sys/cmn_err.h>
411414Scindi #include <sys/systm.h>
425254Sgavinm #include <sys/fm/protocol.h>
435254Sgavinm #include <sys/pcb.h>
445254Sgavinm #include <sys/ontrap.h>
455254Sgavinm #include <sys/psw.h>
465254Sgavinm #include <sys/privregs.h>
477532SSean.Ye@Sun.COM #include <sys/machsystm.h>
481414Scindi
495254Sgavinm /*
505254Sgavinm * Set to force cmi_init to fail.
515254Sgavinm */
525254Sgavinm int cmi_no_init = 0;
535254Sgavinm
545254Sgavinm /*
555254Sgavinm * Set to avoid MCA initialization.
565254Sgavinm */
575254Sgavinm int cmi_no_mca_init = 0;
581414Scindi
591414Scindi /*
602869Sgavinm * If cleared for debugging we will not attempt to load a model-specific
612869Sgavinm * cpu module but will load the generic cpu module instead.
622869Sgavinm */
632869Sgavinm int cmi_force_generic = 0;
642869Sgavinm
652869Sgavinm /*
661414Scindi * If cleared for debugging, we will suppress panicking on fatal hardware
671414Scindi * errors. This should *only* be used for debugging; it use can and will
681414Scindi * cause data corruption if actual hardware errors are detected by the system.
691414Scindi */
701414Scindi int cmi_panic_on_uncorrectable_error = 1;
711414Scindi
727532SSean.Ye@Sun.COM #ifndef __xpv
735254Sgavinm /*
747349SAdrian.Frost@Sun.COM * Set to indicate whether we are able to enable cmci interrupt.
757349SAdrian.Frost@Sun.COM */
767349SAdrian.Frost@Sun.COM int cmi_enable_cmci = 0;
777532SSean.Ye@Sun.COM #endif
787349SAdrian.Frost@Sun.COM
797349SAdrian.Frost@Sun.COM /*
805254Sgavinm * Subdirectory (relative to the module search path) in which we will
815254Sgavinm * look for cpu modules.
825254Sgavinm */
835254Sgavinm #define CPUMOD_SUBDIR "cpu"
845254Sgavinm
855254Sgavinm /*
865254Sgavinm * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and
875254Sgavinm * "cpu.generic" - the "cpu" prefix is specified by the following.
885254Sgavinm */
895254Sgavinm #define CPUMOD_PREFIX "cpu"
905254Sgavinm
915254Sgavinm /*
925254Sgavinm * Structure used to keep track of cpu modules we have loaded and their ops
935254Sgavinm */
945254Sgavinm typedef struct cmi {
955254Sgavinm struct cmi *cmi_next;
965254Sgavinm struct cmi *cmi_prev;
975254Sgavinm const cmi_ops_t *cmi_ops;
985254Sgavinm struct modctl *cmi_modp;
995254Sgavinm uint_t cmi_refcnt;
1005254Sgavinm } cmi_t;
1015254Sgavinm
1021414Scindi static cmi_t *cmi_list;
103*12004Sjiang.liu@intel.com static const cmi_mc_ops_t *cmi_mc_global_ops;
104*12004Sjiang.liu@intel.com static void *cmi_mc_global_data;
1051414Scindi static kmutex_t cmi_load_lock;
1061414Scindi
1075254Sgavinm /*
1085254Sgavinm * Functions we need from cmi_hw.c that are not part of the cpu_module.h
1095254Sgavinm * interface.
1105254Sgavinm */
1117532SSean.Ye@Sun.COM extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t);
112*12004Sjiang.liu@intel.com extern void cmi_hdl_destroy(cmi_hdl_t ophdl);
1135254Sgavinm extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *);
1145254Sgavinm extern void *cmi_hdl_getcmi(cmi_hdl_t);
1155254Sgavinm extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *);
1167532SSean.Ye@Sun.COM extern void cmi_hdl_inj_begin(cmi_hdl_t);
1177532SSean.Ye@Sun.COM extern void cmi_hdl_inj_end(cmi_hdl_t);
11810942STom.Pothier@Sun.COM extern void cmi_read_smbios(cmi_hdl_t);
1195254Sgavinm
1205254Sgavinm #define HDL2CMI(hdl) cmi_hdl_getcmi(hdl)
1215254Sgavinm
1225254Sgavinm #define CMI_OPS(cmi) (cmi)->cmi_ops
1235254Sgavinm #define CMI_OP_PRESENT(cmi, op) ((cmi) && CMI_OPS(cmi)->op != NULL)
1245254Sgavinm
1255254Sgavinm #define CMI_MATCH_VENDOR 0 /* Just match on vendor */
1265254Sgavinm #define CMI_MATCH_FAMILY 1 /* Match down to family */
1275254Sgavinm #define CMI_MATCH_MODEL 2 /* Match down to model */
1285254Sgavinm #define CMI_MATCH_STEPPING 3 /* Match down to stepping */
1295254Sgavinm
1305254Sgavinm static void
cmi_link(cmi_t * cmi)1315254Sgavinm cmi_link(cmi_t *cmi)
1325254Sgavinm {
1335254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
1345254Sgavinm
1355254Sgavinm cmi->cmi_prev = NULL;
1365254Sgavinm cmi->cmi_next = cmi_list;
1375254Sgavinm if (cmi_list != NULL)
1385254Sgavinm cmi_list->cmi_prev = cmi;
1395254Sgavinm cmi_list = cmi;
1405254Sgavinm }
1415254Sgavinm
1425254Sgavinm static void
cmi_unlink(cmi_t * cmi)1435254Sgavinm cmi_unlink(cmi_t *cmi)
1441414Scindi {
1455254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
1465254Sgavinm ASSERT(cmi->cmi_refcnt == 0);
1475254Sgavinm
1485254Sgavinm if (cmi->cmi_prev != NULL)
1495254Sgavinm cmi->cmi_prev = cmi->cmi_next;
1505254Sgavinm
1515254Sgavinm if (cmi->cmi_next != NULL)
1525254Sgavinm cmi->cmi_next->cmi_prev = cmi->cmi_prev;
1535254Sgavinm
1545254Sgavinm if (cmi_list == cmi)
1555254Sgavinm cmi_list = cmi->cmi_next;
1565254Sgavinm }
1575254Sgavinm
1585254Sgavinm /*
1595254Sgavinm * Hold the module in memory. We call to CPU modules without using the
1605254Sgavinm * stubs mechanism, so these modules must be manually held in memory.
1615254Sgavinm * The mod_ref acts as if another loaded module has a dependency on us.
1625254Sgavinm */
1635254Sgavinm static void
cmi_hold(cmi_t * cmi)1645254Sgavinm cmi_hold(cmi_t *cmi)
1655254Sgavinm {
1665254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
1675254Sgavinm
1685254Sgavinm mutex_enter(&mod_lock);
1695254Sgavinm cmi->cmi_modp->mod_ref++;
1705254Sgavinm mutex_exit(&mod_lock);
1715254Sgavinm cmi->cmi_refcnt++;
1725254Sgavinm }
1735254Sgavinm
1745254Sgavinm static void
cmi_rele(cmi_t * cmi)1755254Sgavinm cmi_rele(cmi_t *cmi)
1765254Sgavinm {
1775254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
1785254Sgavinm
1795254Sgavinm mutex_enter(&mod_lock);
1805254Sgavinm cmi->cmi_modp->mod_ref--;
1815254Sgavinm mutex_exit(&mod_lock);
1825254Sgavinm
1835254Sgavinm if (--cmi->cmi_refcnt == 0) {
1845254Sgavinm cmi_unlink(cmi);
1855254Sgavinm kmem_free(cmi, sizeof (cmi_t));
1865254Sgavinm }
1875254Sgavinm }
1885254Sgavinm
1895254Sgavinm static cmi_ops_t *
cmi_getops(modctl_t * modp)1905254Sgavinm cmi_getops(modctl_t *modp)
1915254Sgavinm {
1925254Sgavinm cmi_ops_t *ops;
1935254Sgavinm
1945254Sgavinm if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) ==
1955254Sgavinm NULL) {
1965254Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops "
1975254Sgavinm "found", modp->mod_modname);
1985254Sgavinm return (NULL);
1995254Sgavinm }
2005254Sgavinm
2015254Sgavinm if (ops->cmi_init == NULL) {
2025254Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init "
2035254Sgavinm "entry point", modp->mod_modname);
2045254Sgavinm return (NULL);
2055254Sgavinm }
2065254Sgavinm
2075254Sgavinm return (ops);
2081414Scindi }
2091414Scindi
2101414Scindi static cmi_t *
cmi_load_modctl(modctl_t * modp)2111414Scindi cmi_load_modctl(modctl_t *modp)
2121414Scindi {
2135254Sgavinm cmi_ops_t *ops;
2145254Sgavinm uintptr_t ver;
2151414Scindi cmi_t *cmi;
2165254Sgavinm cmi_api_ver_t apiver;
2171414Scindi
2181414Scindi ASSERT(MUTEX_HELD(&cmi_load_lock));
2191414Scindi
2201414Scindi for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) {
2211414Scindi if (cmi->cmi_modp == modp)
2221414Scindi return (cmi);
2231414Scindi }
2241414Scindi
2255254Sgavinm if ((ver = modlookup_by_modctl(modp, "_cmi_api_version")) == NULL) {
2265254Sgavinm /*
2275254Sgavinm * Apparently a cpu module before versioning was introduced -
2285254Sgavinm * we call this version 0.
2295254Sgavinm */
2305254Sgavinm apiver = CMI_API_VERSION_0;
2315254Sgavinm } else {
2325254Sgavinm apiver = *((cmi_api_ver_t *)ver);
2335254Sgavinm if (!CMI_API_VERSION_CHKMAGIC(apiver)) {
2345254Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: "
2355254Sgavinm "_cmi_api_version 0x%x has bad magic",
2365254Sgavinm modp->mod_modname, apiver);
2375254Sgavinm return (NULL);
2385254Sgavinm }
2395254Sgavinm }
2405254Sgavinm
2415254Sgavinm if (apiver != CMI_API_VERSION) {
2425254Sgavinm cmn_err(CE_WARN, "cpu module '%s' has API version %d, "
2435254Sgavinm "kernel requires API version %d", modp->mod_modname,
2445254Sgavinm CMI_API_VERSION_TOPRINT(apiver),
2455254Sgavinm CMI_API_VERSION_TOPRINT(CMI_API_VERSION));
2461414Scindi return (NULL);
2471414Scindi }
2481414Scindi
2495254Sgavinm if ((ops = cmi_getops(modp)) == NULL)
2505254Sgavinm return (NULL);
2511414Scindi
2525254Sgavinm cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP);
2535254Sgavinm cmi->cmi_ops = ops;
2541414Scindi cmi->cmi_modp = modp;
2551414Scindi
2565254Sgavinm cmi_link(cmi);
2575254Sgavinm
2585254Sgavinm return (cmi);
2595254Sgavinm }
2605254Sgavinm
2615254Sgavinm static int
cmi_cpu_match(cmi_hdl_t hdl1,cmi_hdl_t hdl2,int match)2625254Sgavinm cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match)
2635254Sgavinm {
2645254Sgavinm if (match >= CMI_MATCH_VENDOR &&
2655254Sgavinm cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2))
2665254Sgavinm return (0);
2675254Sgavinm
2685254Sgavinm if (match >= CMI_MATCH_FAMILY &&
2695254Sgavinm cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
2705254Sgavinm return (0);
2715254Sgavinm
2725254Sgavinm if (match >= CMI_MATCH_MODEL &&
2735254Sgavinm cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
2745254Sgavinm return (0);
2755254Sgavinm
2765254Sgavinm if (match >= CMI_MATCH_STEPPING &&
2775254Sgavinm cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
2785254Sgavinm return (0);
2795254Sgavinm
2805254Sgavinm return (1);
2815254Sgavinm }
2825254Sgavinm
2835254Sgavinm static int
cmi_search_list_cb(cmi_hdl_t whdl,void * arg1,void * arg2,void * arg3)2845254Sgavinm cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3)
2855254Sgavinm {
2865254Sgavinm cmi_hdl_t thdl = (cmi_hdl_t)arg1;
2875254Sgavinm int match = *((int *)arg2);
2885254Sgavinm cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3;
2895254Sgavinm
2905254Sgavinm if (cmi_cpu_match(thdl, whdl, match)) {
2915254Sgavinm cmi_hdl_hold(whdl); /* short-term hold */
2925254Sgavinm *rsltp = whdl;
2935254Sgavinm return (CMI_HDL_WALK_DONE);
2945254Sgavinm } else {
2955254Sgavinm return (CMI_HDL_WALK_NEXT);
2965254Sgavinm }
2975254Sgavinm }
2985254Sgavinm
2995254Sgavinm static cmi_t *
cmi_search_list(cmi_hdl_t hdl,int match)3005254Sgavinm cmi_search_list(cmi_hdl_t hdl, int match)
3015254Sgavinm {
3025254Sgavinm cmi_hdl_t dhdl = NULL;
3035254Sgavinm cmi_t *cmi = NULL;
3045254Sgavinm
3055254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
3065254Sgavinm
3075254Sgavinm cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
3085254Sgavinm if (dhdl) {
3095254Sgavinm cmi = HDL2CMI(dhdl);
3105254Sgavinm cmi_hdl_rele(dhdl); /* held in cmi_search_list_cb */
3115254Sgavinm }
3121414Scindi
3131414Scindi return (cmi);
3141414Scindi }
3151414Scindi
3161414Scindi static cmi_t *
cmi_load_module(cmi_hdl_t hdl,int match,int * chosenp)3175254Sgavinm cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp)
3181414Scindi {
3191414Scindi modctl_t *modp;
3201414Scindi cmi_t *cmi;
3215254Sgavinm int modid;
3221414Scindi uint_t s[3];
3231414Scindi
3245254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
3255254Sgavinm ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL ||
3265254Sgavinm match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR);
3275254Sgavinm
3281414Scindi /*
3295254Sgavinm * Have we already loaded a module for a cpu with the same
3305254Sgavinm * vendor/family/model/stepping?
3311414Scindi */
3325254Sgavinm if ((cmi = cmi_search_list(hdl, match)) != NULL) {
3335254Sgavinm cmi_hold(cmi);
3345254Sgavinm return (cmi);
3351414Scindi }
3361414Scindi
3375254Sgavinm s[0] = cmi_hdl_family(hdl);
3385254Sgavinm s[1] = cmi_hdl_model(hdl);
3395254Sgavinm s[2] = cmi_hdl_stepping(hdl);
3401414Scindi modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX,
3415254Sgavinm cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
3421414Scindi
3431414Scindi if (modid == -1)
3441414Scindi return (NULL);
3451414Scindi
3461414Scindi modp = mod_hold_by_id(modid);
3471414Scindi cmi = cmi_load_modctl(modp);
3485254Sgavinm if (cmi)
3495254Sgavinm cmi_hold(cmi);
3501414Scindi mod_release_mod(modp);
3511414Scindi
3521414Scindi return (cmi);
3531414Scindi }
3541414Scindi
3551414Scindi /*
3565254Sgavinm * Try to load a cpu module with specific support for this chip type.
3571414Scindi */
3585254Sgavinm static cmi_t *
cmi_load_specific(cmi_hdl_t hdl,void ** datap)3595254Sgavinm cmi_load_specific(cmi_hdl_t hdl, void **datap)
3601414Scindi {
3611414Scindi cmi_t *cmi;
3625254Sgavinm int err;
3635254Sgavinm int i;
3645254Sgavinm
3655254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
3665254Sgavinm
3675254Sgavinm for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) {
3685254Sgavinm int suffixlevel;
3695254Sgavinm
3705254Sgavinm if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL)
3715254Sgavinm return (NULL);
3725254Sgavinm
3735254Sgavinm /*
3745254Sgavinm * A module has loaded and has a _cmi_ops structure, and the
3755254Sgavinm * module has been held for this instance. Call its cmi_init
3765254Sgavinm * entry point - we expect success (0) or ENOTSUP.
3775254Sgavinm */
3785254Sgavinm if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) {
3795254Sgavinm if (boothowto & RB_VERBOSE) {
3805254Sgavinm printf("initialized cpu module '%s' on "
3815254Sgavinm "chip %d core %d strand %d\n",
3825254Sgavinm cmi->cmi_modp->mod_modname,
3835254Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
3845254Sgavinm cmi_hdl_strandid(hdl));
3855254Sgavinm }
3865254Sgavinm return (cmi);
3875254Sgavinm } else if (err != ENOTSUP) {
3885254Sgavinm cmn_err(CE_WARN, "failed to init cpu module '%s' on "
3895254Sgavinm "chip %d core %d strand %d: err=%d\n",
3905254Sgavinm cmi->cmi_modp->mod_modname,
3915254Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
3925254Sgavinm cmi_hdl_strandid(hdl), err);
3935254Sgavinm }
3945254Sgavinm
3955254Sgavinm /*
3965254Sgavinm * The module failed or declined to init, so release
3975254Sgavinm * it and update i to be equal to the number
3985254Sgavinm * of suffices actually used in the last module path.
3995254Sgavinm */
4005254Sgavinm cmi_rele(cmi);
4015254Sgavinm i = suffixlevel;
4025254Sgavinm }
4035254Sgavinm
4045254Sgavinm return (NULL);
4055254Sgavinm }
4065254Sgavinm
4075254Sgavinm /*
4085254Sgavinm * Load the generic IA32 MCA cpu module, which may still supplement
4095254Sgavinm * itself with model-specific support through cpu model-specific modules.
4105254Sgavinm */
4115254Sgavinm static cmi_t *
cmi_load_generic(cmi_hdl_t hdl,void ** datap)4125254Sgavinm cmi_load_generic(cmi_hdl_t hdl, void **datap)
4135254Sgavinm {
4145254Sgavinm modctl_t *modp;
4155254Sgavinm cmi_t *cmi;
4165254Sgavinm int modid;
4175254Sgavinm int err;
4185254Sgavinm
4195254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock));
4205254Sgavinm
4215254Sgavinm if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1)
4225254Sgavinm return (NULL);
4235254Sgavinm
4245254Sgavinm modp = mod_hold_by_id(modid);
4255254Sgavinm cmi = cmi_load_modctl(modp);
4265254Sgavinm if (cmi)
4275254Sgavinm cmi_hold(cmi);
4285254Sgavinm mod_release_mod(modp);
4295254Sgavinm
4305254Sgavinm if (cmi == NULL)
4315254Sgavinm return (NULL);
4325254Sgavinm
4335254Sgavinm if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) {
4345254Sgavinm if (err != ENOTSUP)
4355254Sgavinm cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to "
4365254Sgavinm "init: err=%d", err);
4375254Sgavinm cmi_rele(cmi);
4385254Sgavinm return (NULL);
4395254Sgavinm }
4405254Sgavinm
4415254Sgavinm return (cmi);
4425254Sgavinm }
4435254Sgavinm
4445254Sgavinm cmi_hdl_t
cmi_init(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)4455254Sgavinm cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
4467532SSean.Ye@Sun.COM uint_t strandid)
4475254Sgavinm {
4485254Sgavinm cmi_t *cmi = NULL;
4495254Sgavinm cmi_hdl_t hdl;
4501414Scindi void *data;
4511414Scindi
4525254Sgavinm if (cmi_no_init) {
4535254Sgavinm cmi_no_mca_init = 1;
4545254Sgavinm return (NULL);
4555254Sgavinm }
4565254Sgavinm
4571414Scindi mutex_enter(&cmi_load_lock);
4581414Scindi
4597532SSean.Ye@Sun.COM if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) {
4601414Scindi mutex_exit(&cmi_load_lock);
4615254Sgavinm cmn_err(CE_WARN, "There will be no MCA support on chip %d "
4625254Sgavinm "core %d strand %d (cmi_hdl_create returned NULL)\n",
4635254Sgavinm chipid, coreid, strandid);
4645254Sgavinm return (NULL);
4651414Scindi }
4661414Scindi
4675254Sgavinm if (!cmi_force_generic)
4685254Sgavinm cmi = cmi_load_specific(hdl, &data);
4695254Sgavinm
4705254Sgavinm if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) {
4715254Sgavinm cmn_err(CE_WARN, "There will be no MCA support on chip %d "
4725254Sgavinm "core %d strand %d\n", chipid, coreid, strandid);
4735254Sgavinm cmi_hdl_rele(hdl);
4741414Scindi mutex_exit(&cmi_load_lock);
4755254Sgavinm return (NULL);
4761414Scindi }
4771414Scindi
4785254Sgavinm cmi_hdl_setcmi(hdl, cmi, data);
4791414Scindi
4805254Sgavinm cms_init(hdl);
4815254Sgavinm
48210942STom.Pothier@Sun.COM cmi_read_smbios(hdl);
48310942STom.Pothier@Sun.COM
4841414Scindi mutex_exit(&cmi_load_lock);
4851414Scindi
4865254Sgavinm return (hdl);
4871414Scindi }
4881414Scindi
4895254Sgavinm /*
490*12004Sjiang.liu@intel.com * cmi_fini is called on DR deconfigure of a cpu resource.
491*12004Sjiang.liu@intel.com * It should not be called at simple offline of a cpu.
4925254Sgavinm */
4931414Scindi void
cmi_fini(cmi_hdl_t hdl)4945254Sgavinm cmi_fini(cmi_hdl_t hdl)
4951414Scindi {
4965254Sgavinm cmi_t *cmi = HDL2CMI(hdl);
4975254Sgavinm
4985254Sgavinm if (cms_present(hdl))
4995254Sgavinm cms_fini(hdl);
5005254Sgavinm
5015254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_fini))
5025254Sgavinm CMI_OPS(cmi)->cmi_fini(hdl);
5035254Sgavinm
504*12004Sjiang.liu@intel.com cmi_hdl_destroy(hdl);
5051414Scindi }
5061414Scindi
5075254Sgavinm /*
5087532SSean.Ye@Sun.COM * cmi_post_startup is called from post_startup for the boot cpu only (no
5097532SSean.Ye@Sun.COM * other cpus are started yet).
5105254Sgavinm */
5111414Scindi void
cmi_post_startup(void)5125254Sgavinm cmi_post_startup(void)
5131414Scindi {
5145254Sgavinm cmi_hdl_t hdl;
5155254Sgavinm cmi_t *cmi;
5165254Sgavinm
5175254Sgavinm if (cmi_no_mca_init != 0 ||
5185254Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */
5195254Sgavinm return;
5205254Sgavinm
5215254Sgavinm cmi = HDL2CMI(hdl);
5225254Sgavinm
5235254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_post_startup))
5245254Sgavinm CMI_OPS(cmi)->cmi_post_startup(hdl);
5255254Sgavinm
5265254Sgavinm cmi_hdl_rele(hdl);
5271414Scindi }
5281414Scindi
5292869Sgavinm /*
5302869Sgavinm * Called just once from start_other_cpus when all processors are started.
5312869Sgavinm * This will not be called for each cpu, so the registered op must not
5327532SSean.Ye@Sun.COM * assume it is called as such. We are not necessarily executing on
5337532SSean.Ye@Sun.COM * the boot cpu.
5342869Sgavinm */
5351414Scindi void
cmi_post_mpstartup(void)5361642Sgavinm cmi_post_mpstartup(void)
5371642Sgavinm {
5385254Sgavinm cmi_hdl_t hdl;
5395254Sgavinm cmi_t *cmi;
5405254Sgavinm
5415254Sgavinm if (cmi_no_mca_init != 0 ||
5425254Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */
5435254Sgavinm return;
5445254Sgavinm
5455254Sgavinm cmi = HDL2CMI(hdl);
5465254Sgavinm
5475254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup))
5485254Sgavinm CMI_OPS(cmi)->cmi_post_mpstartup(hdl);
5495254Sgavinm
5505254Sgavinm cmi_hdl_rele(hdl);
5511642Sgavinm }
5521642Sgavinm
5531642Sgavinm void
cmi_faulted_enter(cmi_hdl_t hdl)5545254Sgavinm cmi_faulted_enter(cmi_hdl_t hdl)
5551414Scindi {
5565254Sgavinm cmi_t *cmi = HDL2CMI(hdl);
5575254Sgavinm
5585254Sgavinm if (cmi_no_mca_init != 0)
5595254Sgavinm return;
5605254Sgavinm
5615254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_faulted_enter))
5625254Sgavinm CMI_OPS(cmi)->cmi_faulted_enter(hdl);
5635254Sgavinm }
5645254Sgavinm
5655254Sgavinm void
cmi_faulted_exit(cmi_hdl_t hdl)5665254Sgavinm cmi_faulted_exit(cmi_hdl_t hdl)
5675254Sgavinm {
5685254Sgavinm cmi_t *cmi = HDL2CMI(hdl);
5695254Sgavinm
5705254Sgavinm if (cmi_no_mca_init != 0)
5715254Sgavinm return;
5725254Sgavinm
5735254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_faulted_exit))
5745254Sgavinm CMI_OPS(cmi)->cmi_faulted_exit(hdl);
5751414Scindi }
5761414Scindi
5771414Scindi void
cmi_mca_init(cmi_hdl_t hdl)5785254Sgavinm cmi_mca_init(cmi_hdl_t hdl)
5791414Scindi {
5805254Sgavinm cmi_t *cmi;
5815254Sgavinm
5825254Sgavinm if (cmi_no_mca_init != 0)
5835254Sgavinm return;
5845254Sgavinm
5855254Sgavinm cmi = HDL2CMI(hdl);
5865254Sgavinm
5875254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_mca_init))
5885254Sgavinm CMI_OPS(cmi)->cmi_mca_init(hdl);
5891414Scindi }
5901414Scindi
5915254Sgavinm #define CMI_RESPONSE_PANIC 0x0 /* panic must have value 0 */
5925254Sgavinm #define CMI_RESPONSE_NONE 0x1
5935254Sgavinm #define CMI_RESPONSE_CKILL 0x2
5945254Sgavinm #define CMI_RESPONSE_REBOOT 0x3 /* not implemented */
5955254Sgavinm #define CMI_RESPONSE_ONTRAP_PROT 0x4
5965254Sgavinm #define CMI_RESPONSE_LOFAULT_PROT 0x5
5975254Sgavinm
5985254Sgavinm /*
5995254Sgavinm * Return 0 if we will panic in response to this machine check, otherwise
6005254Sgavinm * non-zero. If the caller is cmi_mca_trap in this file then the nonzero
6015254Sgavinm * return values are to be interpreted from CMI_RESPONSE_* above.
6025254Sgavinm *
6035254Sgavinm * This function must just return what will be done without actually
6045254Sgavinm * doing anything; this includes not changing the regs.
6055254Sgavinm */
6061414Scindi int
cmi_mce_response(struct regs * rp,uint64_t disp)6075254Sgavinm cmi_mce_response(struct regs *rp, uint64_t disp)
6081414Scindi {
6095254Sgavinm int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC :
6105254Sgavinm CMI_RESPONSE_NONE;
6115254Sgavinm on_trap_data_t *otp;
6125254Sgavinm
6135254Sgavinm ASSERT(rp != NULL); /* don't call for polling, only on #MC */
6145254Sgavinm
6155254Sgavinm /*
6165254Sgavinm * If no bits are set in the disposition then there is nothing to
6175254Sgavinm * worry about and we do not need to trampoline to ontrap or
6185254Sgavinm * lofault handlers.
6195254Sgavinm */
6205254Sgavinm if (disp == 0)
6215254Sgavinm return (CMI_RESPONSE_NONE);
6225254Sgavinm
6235254Sgavinm /*
6245254Sgavinm * Unconstrained errors cannot be forgiven, even by ontrap or
6255254Sgavinm * lofault protection. The data is not poisoned and may not
6265254Sgavinm * even belong to the trapped context - eg a writeback of
6275254Sgavinm * data that is found to be bad.
6285254Sgavinm */
6295254Sgavinm if (disp & CMI_ERRDISP_UC_UNCONSTRAINED)
6305254Sgavinm return (panicrsp);
6315254Sgavinm
6325254Sgavinm /*
6335254Sgavinm * ontrap OT_DATA_EC and lofault protection forgive any disposition
6345254Sgavinm * other than unconstrained, even those normally forced fatal.
6355254Sgavinm */
6365254Sgavinm if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC)
6375254Sgavinm return (CMI_RESPONSE_ONTRAP_PROT);
6385254Sgavinm else if (curthread->t_lofault)
6395254Sgavinm return (CMI_RESPONSE_LOFAULT_PROT);
6405254Sgavinm
6415254Sgavinm /*
6425254Sgavinm * Forced-fatal errors are terminal even in user mode.
6435254Sgavinm */
6445254Sgavinm if (disp & CMI_ERRDISP_FORCEFATAL)
6455254Sgavinm return (panicrsp);
6465254Sgavinm
6475254Sgavinm /*
6485254Sgavinm * If the trapped context is corrupt or we have no instruction pointer
6495254Sgavinm * to resume at (and aren't trampolining to a fault handler)
6505254Sgavinm * then in the kernel case we must panic and in usermode we
6515254Sgavinm * kill the affected contract.
6525254Sgavinm */
6535254Sgavinm if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID))
6545254Sgavinm return (USERMODE(rp->r_cs) ? CMI_RESPONSE_CKILL : panicrsp);
6555254Sgavinm
6565254Sgavinm /*
6575254Sgavinm * Anything else is harmless
6585254Sgavinm */
6595254Sgavinm return (CMI_RESPONSE_NONE);
6601414Scindi }
6611414Scindi
6625254Sgavinm int cma_mca_trap_panic_suppressed = 0;
6635254Sgavinm
6645254Sgavinm static void
cmi_mca_panic(void)6655254Sgavinm cmi_mca_panic(void)
6661414Scindi {
6675254Sgavinm if (cmi_panic_on_uncorrectable_error) {
6685254Sgavinm fm_panic("Unrecoverable Machine-Check Exception");
6695254Sgavinm } else {
6705254Sgavinm cmn_err(CE_WARN, "suppressing panic from fatal #mc");
6715254Sgavinm cma_mca_trap_panic_suppressed++;
6725254Sgavinm }
6731414Scindi }
6741414Scindi
6755254Sgavinm
6765254Sgavinm int cma_mca_trap_contract_kills = 0;
6775254Sgavinm int cma_mca_trap_ontrap_forgiven = 0;
6785254Sgavinm int cma_mca_trap_lofault_forgiven = 0;
6795254Sgavinm
6805254Sgavinm /*
6815254Sgavinm * Native #MC handler - we branch to here from mcetrap
6825254Sgavinm */
6835254Sgavinm /*ARGSUSED*/
6841414Scindi void
cmi_mca_trap(struct regs * rp)6851414Scindi cmi_mca_trap(struct regs *rp)
6861414Scindi {
6875254Sgavinm #ifndef __xpv
6885254Sgavinm cmi_hdl_t hdl = NULL;
6895254Sgavinm uint64_t disp;
6905254Sgavinm cmi_t *cmi;
6915254Sgavinm int s;
6925254Sgavinm
6935254Sgavinm if (cmi_no_mca_init != 0)
6945254Sgavinm return;
6955254Sgavinm
6965254Sgavinm /*
6975254Sgavinm * This function can call cmn_err, and the cpu module cmi_mca_trap
6985254Sgavinm * entry point may also elect to call cmn_err (e.g., if it can't
6995254Sgavinm * log the error onto an errorq, say very early in boot).
7005254Sgavinm * We need to let cprintf know that we must not block.
7015254Sgavinm */
7025254Sgavinm s = spl8();
7035254Sgavinm
7045254Sgavinm if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
7055254Sgavinm cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
7065254Sgavinm (cmi = HDL2CMI(hdl)) == NULL ||
7075254Sgavinm !CMI_OP_PRESENT(cmi, cmi_mca_trap)) {
7085254Sgavinm
7095254Sgavinm cmn_err(CE_WARN, "#MC exception on cpuid %d: %s",
7105254Sgavinm CPU->cpu_id,
7115254Sgavinm hdl ? "handle lookup ok but no #MC handler found" :
7125254Sgavinm "handle lookup failed");
7135254Sgavinm
7145254Sgavinm if (hdl != NULL)
7155254Sgavinm cmi_hdl_rele(hdl);
7165254Sgavinm
7175254Sgavinm splx(s);
7185254Sgavinm return;
7191414Scindi }
7205254Sgavinm
7215254Sgavinm disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp);
7221414Scindi
7235254Sgavinm switch (cmi_mce_response(rp, disp)) {
7245254Sgavinm default:
7255254Sgavinm cmn_err(CE_WARN, "Invalid response from cmi_mce_response");
7265254Sgavinm /*FALLTHRU*/
7275254Sgavinm
7285254Sgavinm case CMI_RESPONSE_PANIC:
7295254Sgavinm cmi_mca_panic();
7305254Sgavinm break;
7315254Sgavinm
7325254Sgavinm case CMI_RESPONSE_NONE:
7335254Sgavinm break;
7345254Sgavinm
7355254Sgavinm case CMI_RESPONSE_CKILL:
7365254Sgavinm ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR;
7375254Sgavinm aston(curthread);
7385254Sgavinm cma_mca_trap_contract_kills++;
7395254Sgavinm break;
7401414Scindi
7415254Sgavinm case CMI_RESPONSE_ONTRAP_PROT: {
7425254Sgavinm on_trap_data_t *otp = curthread->t_ontrap;
7435254Sgavinm otp->ot_trap = OT_DATA_EC;
7445254Sgavinm rp->r_pc = otp->ot_trampoline;
7455254Sgavinm cma_mca_trap_ontrap_forgiven++;
7465254Sgavinm break;
7475254Sgavinm }
7481414Scindi
7495254Sgavinm case CMI_RESPONSE_LOFAULT_PROT:
7505254Sgavinm rp->r_r0 = EFAULT;
7515254Sgavinm rp->r_pc = curthread->t_lofault;
7525254Sgavinm cma_mca_trap_lofault_forgiven++;
7535254Sgavinm break;
7545254Sgavinm }
7555254Sgavinm
7565254Sgavinm cmi_hdl_rele(hdl);
7575254Sgavinm splx(s);
7585254Sgavinm #endif /* __xpv */
7591414Scindi }
7601414Scindi
7611414Scindi void
cmi_hdl_poke(cmi_hdl_t hdl)7625254Sgavinm cmi_hdl_poke(cmi_hdl_t hdl)
7631414Scindi {
7645254Sgavinm cmi_t *cmi = HDL2CMI(hdl);
7655254Sgavinm
7665254Sgavinm if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke))
7675254Sgavinm return;
7685254Sgavinm
7695254Sgavinm CMI_OPS(cmi)->cmi_hdl_poke(hdl);
7701414Scindi }
7711414Scindi
7727532SSean.Ye@Sun.COM #ifndef __xpv
7731414Scindi void
cmi_cmci_trap()7747349SAdrian.Frost@Sun.COM cmi_cmci_trap()
7757349SAdrian.Frost@Sun.COM {
7767349SAdrian.Frost@Sun.COM cmi_hdl_t hdl = NULL;
7777349SAdrian.Frost@Sun.COM cmi_t *cmi;
7787349SAdrian.Frost@Sun.COM
7797349SAdrian.Frost@Sun.COM if (cmi_no_mca_init != 0)
7807349SAdrian.Frost@Sun.COM return;
7817349SAdrian.Frost@Sun.COM
7827349SAdrian.Frost@Sun.COM if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
7837349SAdrian.Frost@Sun.COM cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
7847349SAdrian.Frost@Sun.COM (cmi = HDL2CMI(hdl)) == NULL ||
7857349SAdrian.Frost@Sun.COM !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) {
7867349SAdrian.Frost@Sun.COM
7877349SAdrian.Frost@Sun.COM cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s",
7887349SAdrian.Frost@Sun.COM CPU->cpu_id,
7897349SAdrian.Frost@Sun.COM hdl ? "handle lookup ok but no CMCI handler found" :
7907349SAdrian.Frost@Sun.COM "handle lookup failed");
7917349SAdrian.Frost@Sun.COM
7927349SAdrian.Frost@Sun.COM if (hdl != NULL)
7937349SAdrian.Frost@Sun.COM cmi_hdl_rele(hdl);
7947349SAdrian.Frost@Sun.COM
7957349SAdrian.Frost@Sun.COM return;
7967349SAdrian.Frost@Sun.COM }
7977349SAdrian.Frost@Sun.COM
7987349SAdrian.Frost@Sun.COM CMI_OPS(cmi)->cmi_cmci_trap(hdl);
7997349SAdrian.Frost@Sun.COM
8007349SAdrian.Frost@Sun.COM cmi_hdl_rele(hdl);
8017532SSean.Ye@Sun.COM }
8027349SAdrian.Frost@Sun.COM #endif /* __xpv */
8037349SAdrian.Frost@Sun.COM
8047349SAdrian.Frost@Sun.COM void
cmi_mc_register(cmi_hdl_t hdl,const cmi_mc_ops_t * mcops,void * mcdata)8055254Sgavinm cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata)
8061414Scindi {
8075254Sgavinm if (!cmi_no_mca_init)
8085254Sgavinm cmi_hdl_setmc(hdl, mcops, mcdata);
8091414Scindi }
8101414Scindi
811*12004Sjiang.liu@intel.com cmi_errno_t
cmi_mc_register_global(const cmi_mc_ops_t * mcops,void * mcdata)812*12004Sjiang.liu@intel.com cmi_mc_register_global(const cmi_mc_ops_t *mcops, void *mcdata)
813*12004Sjiang.liu@intel.com {
814*12004Sjiang.liu@intel.com if (!cmi_no_mca_init) {
815*12004Sjiang.liu@intel.com if (cmi_mc_global_ops != NULL || cmi_mc_global_data != NULL ||
816*12004Sjiang.liu@intel.com mcops == NULL || mcops->cmi_mc_patounum == NULL ||
817*12004Sjiang.liu@intel.com mcops->cmi_mc_unumtopa == NULL) {
818*12004Sjiang.liu@intel.com return (CMIERR_UNKNOWN);
819*12004Sjiang.liu@intel.com }
820*12004Sjiang.liu@intel.com cmi_mc_global_data = mcdata;
821*12004Sjiang.liu@intel.com cmi_mc_global_ops = mcops;
822*12004Sjiang.liu@intel.com }
823*12004Sjiang.liu@intel.com return (CMI_SUCCESS);
824*12004Sjiang.liu@intel.com }
825*12004Sjiang.liu@intel.com
8267532SSean.Ye@Sun.COM void
cmi_mc_sw_memscrub_disable(void)8277532SSean.Ye@Sun.COM cmi_mc_sw_memscrub_disable(void)
8287532SSean.Ye@Sun.COM {
8297532SSean.Ye@Sun.COM memscrub_disable();
8307532SSean.Ye@Sun.COM }
8317532SSean.Ye@Sun.COM
8325254Sgavinm cmi_errno_t
cmi_mc_patounum(uint64_t pa,uint8_t valid_hi,uint8_t valid_lo,uint32_t synd,int syndtype,mc_unum_t * up)8333164Sgavinm cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd,
8343164Sgavinm int syndtype, mc_unum_t *up)
8351414Scindi {
8361414Scindi const struct cmi_mc_ops *mcops;
8375254Sgavinm cmi_hdl_t hdl;
8385254Sgavinm cmi_errno_t rv;
8395254Sgavinm
840*12004Sjiang.liu@intel.com if (cmi_no_mca_init)
841*12004Sjiang.liu@intel.com return (CMIERR_MC_ABSENT);
842*12004Sjiang.liu@intel.com
843*12004Sjiang.liu@intel.com if (cmi_mc_global_ops != NULL) {
844*12004Sjiang.liu@intel.com if (cmi_mc_global_ops->cmi_mc_patounum == NULL)
845*12004Sjiang.liu@intel.com return (CMIERR_MC_NOTSUP);
846*12004Sjiang.liu@intel.com return (cmi_mc_global_ops->cmi_mc_patounum(cmi_mc_global_data,
847*12004Sjiang.liu@intel.com pa, valid_hi, valid_lo, synd, syndtype, up));
848*12004Sjiang.liu@intel.com }
849*12004Sjiang.liu@intel.com
850*12004Sjiang.liu@intel.com if ((hdl = cmi_hdl_any()) == NULL) /* short-term hold */
8515254Sgavinm return (CMIERR_MC_ABSENT);
8521414Scindi
8535254Sgavinm if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
8545254Sgavinm mcops->cmi_mc_patounum == NULL) {
8555254Sgavinm cmi_hdl_rele(hdl);
8565254Sgavinm return (CMIERR_MC_NOTSUP);
8575254Sgavinm }
8581414Scindi
8595254Sgavinm rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi,
8605254Sgavinm valid_lo, synd, syndtype, up);
8615254Sgavinm
8625254Sgavinm cmi_hdl_rele(hdl);
8635254Sgavinm
8645254Sgavinm return (rv);
8651414Scindi }
8661414Scindi
8675254Sgavinm cmi_errno_t
cmi_mc_unumtopa(mc_unum_t * up,nvlist_t * nvl,uint64_t * pap)8681414Scindi cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap)
8691414Scindi {
8701414Scindi const struct cmi_mc_ops *mcops;
8715254Sgavinm cmi_hdl_t hdl;
8725254Sgavinm cmi_errno_t rv;
8737532SSean.Ye@Sun.COM nvlist_t *hcsp;
8741414Scindi
8751414Scindi if (up != NULL && nvl != NULL)
8765254Sgavinm return (CMIERR_API); /* convert from just one form */
8775254Sgavinm
878*12004Sjiang.liu@intel.com if (cmi_no_mca_init)
879*12004Sjiang.liu@intel.com return (CMIERR_MC_ABSENT);
880*12004Sjiang.liu@intel.com
881*12004Sjiang.liu@intel.com if (cmi_mc_global_ops != NULL) {
882*12004Sjiang.liu@intel.com if (cmi_mc_global_ops->cmi_mc_unumtopa == NULL)
883*12004Sjiang.liu@intel.com return (CMIERR_MC_NOTSUP);
884*12004Sjiang.liu@intel.com return (cmi_mc_global_ops->cmi_mc_unumtopa(cmi_mc_global_data,
885*12004Sjiang.liu@intel.com up, nvl, pap));
886*12004Sjiang.liu@intel.com }
887*12004Sjiang.liu@intel.com
888*12004Sjiang.liu@intel.com if ((hdl = cmi_hdl_any()) == NULL) /* short-term hold */
8895254Sgavinm return (CMIERR_MC_ABSENT);
8905254Sgavinm
8915254Sgavinm if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
8925254Sgavinm mcops->cmi_mc_unumtopa == NULL) {
8935254Sgavinm cmi_hdl_rele(hdl);
8945254Sgavinm
8957532SSean.Ye@Sun.COM if (nvl != NULL && nvlist_lookup_nvlist(nvl,
8967532SSean.Ye@Sun.COM FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
8977532SSean.Ye@Sun.COM (nvlist_lookup_uint64(hcsp,
8987532SSean.Ye@Sun.COM "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, pap) == 0 ||
8997532SSean.Ye@Sun.COM nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
9007532SSean.Ye@Sun.COM pap) == 0)) {
9015254Sgavinm return (CMIERR_MC_PARTIALUNUMTOPA);
9025254Sgavinm } else {
903*12004Sjiang.liu@intel.com return (mcops && mcops->cmi_mc_unumtopa == NULL ?
9045254Sgavinm CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT);
9055254Sgavinm }
9065254Sgavinm }
9075254Sgavinm
9085254Sgavinm rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap);
9095254Sgavinm
9105254Sgavinm cmi_hdl_rele(hdl);
9115254Sgavinm
9125254Sgavinm return (rv);
9135254Sgavinm }
9141414Scindi
9155254Sgavinm void
cmi_mc_logout(cmi_hdl_t hdl,boolean_t ismc,boolean_t sync)9165254Sgavinm cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync)
9175254Sgavinm {
9185254Sgavinm const struct cmi_mc_ops *mcops;
9195254Sgavinm
920*12004Sjiang.liu@intel.com if (cmi_no_mca_init)
9215254Sgavinm return;
9225254Sgavinm
923*12004Sjiang.liu@intel.com if (cmi_mc_global_ops != NULL)
924*12004Sjiang.liu@intel.com mcops = cmi_mc_global_ops;
925*12004Sjiang.liu@intel.com else
926*12004Sjiang.liu@intel.com mcops = cmi_hdl_getmcops(hdl);
927*12004Sjiang.liu@intel.com
928*12004Sjiang.liu@intel.com if (mcops != NULL && mcops->cmi_mc_logout != NULL)
9295254Sgavinm mcops->cmi_mc_logout(hdl, ismc, sync);
9305254Sgavinm }
9311414Scindi
9325254Sgavinm cmi_errno_t
cmi_hdl_msrinject(cmi_hdl_t hdl,cmi_mca_regs_t * regs,uint_t nregs,int force)9335254Sgavinm cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs,
9345254Sgavinm int force)
9355254Sgavinm {
9365254Sgavinm cmi_t *cmi = cmi_hdl_getcmi(hdl);
9377532SSean.Ye@Sun.COM cmi_errno_t rc;
9385254Sgavinm
9395254Sgavinm if (!CMI_OP_PRESENT(cmi, cmi_msrinject))
9405254Sgavinm return (CMIERR_NOTSUP);
9415254Sgavinm
9427532SSean.Ye@Sun.COM cmi_hdl_inj_begin(hdl);
9437532SSean.Ye@Sun.COM rc = CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force);
9447532SSean.Ye@Sun.COM cmi_hdl_inj_end(hdl);
9457532SSean.Ye@Sun.COM
9467532SSean.Ye@Sun.COM return (rc);
9471414Scindi }
9485254Sgavinm
9495254Sgavinm boolean_t
cmi_panic_on_ue(void)9505254Sgavinm cmi_panic_on_ue(void)
9515254Sgavinm {
9525254Sgavinm return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE);
9535254Sgavinm }
9547532SSean.Ye@Sun.COM
9557532SSean.Ye@Sun.COM void
cmi_panic_callback(void)9567532SSean.Ye@Sun.COM cmi_panic_callback(void)
9577532SSean.Ye@Sun.COM {
9587532SSean.Ye@Sun.COM cmi_hdl_t hdl;
9597532SSean.Ye@Sun.COM cmi_t *cmi;
9607532SSean.Ye@Sun.COM
9617532SSean.Ye@Sun.COM if (cmi_no_mca_init || (hdl = cmi_hdl_any()) == NULL)
9627532SSean.Ye@Sun.COM return;
9637532SSean.Ye@Sun.COM
9647532SSean.Ye@Sun.COM cmi = cmi_hdl_getcmi(hdl);
9657532SSean.Ye@Sun.COM if (CMI_OP_PRESENT(cmi, cmi_panic_callback))
9667532SSean.Ye@Sun.COM CMI_OPS(cmi)->cmi_panic_callback();
9677532SSean.Ye@Sun.COM
9687532SSean.Ye@Sun.COM cmi_hdl_rele(hdl);
9697532SSean.Ye@Sun.COM }
970