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 /* 233446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241414Scindi * Use is subject to license terms. 251414Scindi */ 261414Scindi 271414Scindi #pragma ident "%Z%%M% %I% %E% SMI" 281414Scindi 291414Scindi /* 301414Scindi * Public interface to routines implemented by CPU modules 311414Scindi */ 321414Scindi 33*5254Sgavinm #include <sys/types.h> 34*5254Sgavinm #include <sys/atomic.h> 351414Scindi #include <sys/x86_archext.h> 361414Scindi #include <sys/cpu_module_impl.h> 37*5254Sgavinm #include <sys/cpu_module_ms.h> 381414Scindi #include <sys/fm/util.h> 391414Scindi #include <sys/reboot.h> 401414Scindi #include <sys/modctl.h> 411414Scindi #include <sys/param.h> 421414Scindi #include <sys/cmn_err.h> 431414Scindi #include <sys/systm.h> 44*5254Sgavinm #include <sys/fm/protocol.h> 45*5254Sgavinm #include <sys/pcb.h> 46*5254Sgavinm #include <sys/ontrap.h> 47*5254Sgavinm #include <sys/psw.h> 48*5254Sgavinm #include <sys/privregs.h> 491414Scindi 50*5254Sgavinm /* 51*5254Sgavinm * Set to force cmi_init to fail. 52*5254Sgavinm */ 53*5254Sgavinm int cmi_no_init = 0; 54*5254Sgavinm 55*5254Sgavinm /* 56*5254Sgavinm * Set to avoid MCA initialization. 57*5254Sgavinm */ 58*5254Sgavinm int cmi_no_mca_init = 0; 591414Scindi 601414Scindi /* 612869Sgavinm * If cleared for debugging we will not attempt to load a model-specific 622869Sgavinm * cpu module but will load the generic cpu module instead. 632869Sgavinm */ 642869Sgavinm int cmi_force_generic = 0; 652869Sgavinm 662869Sgavinm /* 671414Scindi * If cleared for debugging, we will suppress panicking on fatal hardware 681414Scindi * errors. This should *only* be used for debugging; it use can and will 691414Scindi * cause data corruption if actual hardware errors are detected by the system. 701414Scindi */ 711414Scindi int cmi_panic_on_uncorrectable_error = 1; 721414Scindi 73*5254Sgavinm /* 74*5254Sgavinm * Subdirectory (relative to the module search path) in which we will 75*5254Sgavinm * look for cpu modules. 76*5254Sgavinm */ 77*5254Sgavinm #define CPUMOD_SUBDIR "cpu" 78*5254Sgavinm 79*5254Sgavinm /* 80*5254Sgavinm * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and 81*5254Sgavinm * "cpu.generic" - the "cpu" prefix is specified by the following. 82*5254Sgavinm */ 83*5254Sgavinm #define CPUMOD_PREFIX "cpu" 84*5254Sgavinm 85*5254Sgavinm /* 86*5254Sgavinm * Structure used to keep track of cpu modules we have loaded and their ops 87*5254Sgavinm */ 88*5254Sgavinm typedef struct cmi { 89*5254Sgavinm struct cmi *cmi_next; 90*5254Sgavinm struct cmi *cmi_prev; 91*5254Sgavinm const cmi_ops_t *cmi_ops; 92*5254Sgavinm struct modctl *cmi_modp; 93*5254Sgavinm uint_t cmi_refcnt; 94*5254Sgavinm } cmi_t; 95*5254Sgavinm 961414Scindi static cmi_t *cmi_list; 971414Scindi static kmutex_t cmi_load_lock; 981414Scindi 99*5254Sgavinm /* 100*5254Sgavinm * Functions we need from cmi_hw.c that are not part of the cpu_module.h 101*5254Sgavinm * interface. 102*5254Sgavinm */ 103*5254Sgavinm extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t); 104*5254Sgavinm extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *); 105*5254Sgavinm extern void *cmi_hdl_getcmi(cmi_hdl_t); 106*5254Sgavinm extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *); 107*5254Sgavinm 108*5254Sgavinm #define HDL2CMI(hdl) cmi_hdl_getcmi(hdl) 109*5254Sgavinm 110*5254Sgavinm #define CMI_OPS(cmi) (cmi)->cmi_ops 111*5254Sgavinm #define CMI_OP_PRESENT(cmi, op) ((cmi) && CMI_OPS(cmi)->op != NULL) 112*5254Sgavinm 113*5254Sgavinm #define CMI_MATCH_VENDOR 0 /* Just match on vendor */ 114*5254Sgavinm #define CMI_MATCH_FAMILY 1 /* Match down to family */ 115*5254Sgavinm #define CMI_MATCH_MODEL 2 /* Match down to model */ 116*5254Sgavinm #define CMI_MATCH_STEPPING 3 /* Match down to stepping */ 117*5254Sgavinm 118*5254Sgavinm static void 119*5254Sgavinm cmi_link(cmi_t *cmi) 120*5254Sgavinm { 121*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 122*5254Sgavinm 123*5254Sgavinm cmi->cmi_prev = NULL; 124*5254Sgavinm cmi->cmi_next = cmi_list; 125*5254Sgavinm if (cmi_list != NULL) 126*5254Sgavinm cmi_list->cmi_prev = cmi; 127*5254Sgavinm cmi_list = cmi; 128*5254Sgavinm } 129*5254Sgavinm 130*5254Sgavinm static void 131*5254Sgavinm cmi_unlink(cmi_t *cmi) 1321414Scindi { 133*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 134*5254Sgavinm ASSERT(cmi->cmi_refcnt == 0); 135*5254Sgavinm 136*5254Sgavinm if (cmi->cmi_prev != NULL) 137*5254Sgavinm cmi->cmi_prev = cmi->cmi_next; 138*5254Sgavinm 139*5254Sgavinm if (cmi->cmi_next != NULL) 140*5254Sgavinm cmi->cmi_next->cmi_prev = cmi->cmi_prev; 141*5254Sgavinm 142*5254Sgavinm if (cmi_list == cmi) 143*5254Sgavinm cmi_list = cmi->cmi_next; 144*5254Sgavinm } 145*5254Sgavinm 146*5254Sgavinm /* 147*5254Sgavinm * Hold the module in memory. We call to CPU modules without using the 148*5254Sgavinm * stubs mechanism, so these modules must be manually held in memory. 149*5254Sgavinm * The mod_ref acts as if another loaded module has a dependency on us. 150*5254Sgavinm */ 151*5254Sgavinm static void 152*5254Sgavinm cmi_hold(cmi_t *cmi) 153*5254Sgavinm { 154*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 155*5254Sgavinm 156*5254Sgavinm mutex_enter(&mod_lock); 157*5254Sgavinm cmi->cmi_modp->mod_ref++; 158*5254Sgavinm mutex_exit(&mod_lock); 159*5254Sgavinm cmi->cmi_refcnt++; 160*5254Sgavinm } 161*5254Sgavinm 162*5254Sgavinm static void 163*5254Sgavinm cmi_rele(cmi_t *cmi) 164*5254Sgavinm { 165*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 166*5254Sgavinm 167*5254Sgavinm mutex_enter(&mod_lock); 168*5254Sgavinm cmi->cmi_modp->mod_ref--; 169*5254Sgavinm mutex_exit(&mod_lock); 170*5254Sgavinm 171*5254Sgavinm if (--cmi->cmi_refcnt == 0) { 172*5254Sgavinm cmi_unlink(cmi); 173*5254Sgavinm kmem_free(cmi, sizeof (cmi_t)); 174*5254Sgavinm } 175*5254Sgavinm } 176*5254Sgavinm 177*5254Sgavinm static cmi_ops_t * 178*5254Sgavinm cmi_getops(modctl_t *modp) 179*5254Sgavinm { 180*5254Sgavinm cmi_ops_t *ops; 181*5254Sgavinm 182*5254Sgavinm if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) == 183*5254Sgavinm NULL) { 184*5254Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops " 185*5254Sgavinm "found", modp->mod_modname); 186*5254Sgavinm return (NULL); 187*5254Sgavinm } 188*5254Sgavinm 189*5254Sgavinm if (ops->cmi_init == NULL) { 190*5254Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init " 191*5254Sgavinm "entry point", modp->mod_modname); 192*5254Sgavinm return (NULL); 193*5254Sgavinm } 194*5254Sgavinm 195*5254Sgavinm return (ops); 1961414Scindi } 1971414Scindi 1981414Scindi static cmi_t * 1991414Scindi cmi_load_modctl(modctl_t *modp) 2001414Scindi { 201*5254Sgavinm cmi_ops_t *ops; 202*5254Sgavinm uintptr_t ver; 2031414Scindi cmi_t *cmi; 204*5254Sgavinm cmi_api_ver_t apiver; 2051414Scindi 2061414Scindi ASSERT(MUTEX_HELD(&cmi_load_lock)); 2071414Scindi 2081414Scindi for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) { 2091414Scindi if (cmi->cmi_modp == modp) 2101414Scindi return (cmi); 2111414Scindi } 2121414Scindi 213*5254Sgavinm if ((ver = modlookup_by_modctl(modp, "_cmi_api_version")) == NULL) { 214*5254Sgavinm /* 215*5254Sgavinm * Apparently a cpu module before versioning was introduced - 216*5254Sgavinm * we call this version 0. 217*5254Sgavinm */ 218*5254Sgavinm apiver = CMI_API_VERSION_0; 219*5254Sgavinm } else { 220*5254Sgavinm apiver = *((cmi_api_ver_t *)ver); 221*5254Sgavinm if (!CMI_API_VERSION_CHKMAGIC(apiver)) { 222*5254Sgavinm cmn_err(CE_WARN, "cpu module '%s' is invalid: " 223*5254Sgavinm "_cmi_api_version 0x%x has bad magic", 224*5254Sgavinm modp->mod_modname, apiver); 225*5254Sgavinm return (NULL); 226*5254Sgavinm } 227*5254Sgavinm } 228*5254Sgavinm 229*5254Sgavinm if (apiver != CMI_API_VERSION) { 230*5254Sgavinm cmn_err(CE_WARN, "cpu module '%s' has API version %d, " 231*5254Sgavinm "kernel requires API version %d", modp->mod_modname, 232*5254Sgavinm CMI_API_VERSION_TOPRINT(apiver), 233*5254Sgavinm CMI_API_VERSION_TOPRINT(CMI_API_VERSION)); 2341414Scindi return (NULL); 2351414Scindi } 2361414Scindi 237*5254Sgavinm if ((ops = cmi_getops(modp)) == NULL) 238*5254Sgavinm return (NULL); 2391414Scindi 240*5254Sgavinm cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP); 241*5254Sgavinm cmi->cmi_ops = ops; 2421414Scindi cmi->cmi_modp = modp; 2431414Scindi 244*5254Sgavinm cmi_link(cmi); 245*5254Sgavinm 246*5254Sgavinm return (cmi); 247*5254Sgavinm } 248*5254Sgavinm 249*5254Sgavinm static int 250*5254Sgavinm cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match) 251*5254Sgavinm { 252*5254Sgavinm if (match >= CMI_MATCH_VENDOR && 253*5254Sgavinm cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2)) 254*5254Sgavinm return (0); 255*5254Sgavinm 256*5254Sgavinm if (match >= CMI_MATCH_FAMILY && 257*5254Sgavinm cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2)) 258*5254Sgavinm return (0); 259*5254Sgavinm 260*5254Sgavinm if (match >= CMI_MATCH_MODEL && 261*5254Sgavinm cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2)) 262*5254Sgavinm return (0); 263*5254Sgavinm 264*5254Sgavinm if (match >= CMI_MATCH_STEPPING && 265*5254Sgavinm cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2)) 266*5254Sgavinm return (0); 267*5254Sgavinm 268*5254Sgavinm return (1); 269*5254Sgavinm } 270*5254Sgavinm 271*5254Sgavinm static int 272*5254Sgavinm cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3) 273*5254Sgavinm { 274*5254Sgavinm cmi_hdl_t thdl = (cmi_hdl_t)arg1; 275*5254Sgavinm int match = *((int *)arg2); 276*5254Sgavinm cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3; 277*5254Sgavinm 278*5254Sgavinm if (cmi_cpu_match(thdl, whdl, match)) { 279*5254Sgavinm cmi_hdl_hold(whdl); /* short-term hold */ 280*5254Sgavinm *rsltp = whdl; 281*5254Sgavinm return (CMI_HDL_WALK_DONE); 282*5254Sgavinm } else { 283*5254Sgavinm return (CMI_HDL_WALK_NEXT); 284*5254Sgavinm } 285*5254Sgavinm } 286*5254Sgavinm 287*5254Sgavinm static cmi_t * 288*5254Sgavinm cmi_search_list(cmi_hdl_t hdl, int match) 289*5254Sgavinm { 290*5254Sgavinm cmi_hdl_t dhdl = NULL; 291*5254Sgavinm cmi_t *cmi = NULL; 292*5254Sgavinm 293*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 294*5254Sgavinm 295*5254Sgavinm cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl); 296*5254Sgavinm if (dhdl) { 297*5254Sgavinm cmi = HDL2CMI(dhdl); 298*5254Sgavinm cmi_hdl_rele(dhdl); /* held in cmi_search_list_cb */ 299*5254Sgavinm } 3001414Scindi 3011414Scindi return (cmi); 3021414Scindi } 3031414Scindi 3041414Scindi static cmi_t * 305*5254Sgavinm cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp) 3061414Scindi { 3071414Scindi modctl_t *modp; 3081414Scindi cmi_t *cmi; 309*5254Sgavinm int modid; 3101414Scindi uint_t s[3]; 3111414Scindi 312*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 313*5254Sgavinm ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL || 314*5254Sgavinm match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR); 315*5254Sgavinm 3161414Scindi /* 317*5254Sgavinm * Have we already loaded a module for a cpu with the same 318*5254Sgavinm * vendor/family/model/stepping? 3191414Scindi */ 320*5254Sgavinm if ((cmi = cmi_search_list(hdl, match)) != NULL) { 321*5254Sgavinm cmi_hold(cmi); 322*5254Sgavinm return (cmi); 3231414Scindi } 3241414Scindi 325*5254Sgavinm s[0] = cmi_hdl_family(hdl); 326*5254Sgavinm s[1] = cmi_hdl_model(hdl); 327*5254Sgavinm s[2] = cmi_hdl_stepping(hdl); 3281414Scindi modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX, 329*5254Sgavinm cmi_hdl_vendorstr(hdl), ".", s, match, chosenp); 3301414Scindi 3311414Scindi if (modid == -1) 3321414Scindi return (NULL); 3331414Scindi 3341414Scindi modp = mod_hold_by_id(modid); 3351414Scindi cmi = cmi_load_modctl(modp); 336*5254Sgavinm if (cmi) 337*5254Sgavinm cmi_hold(cmi); 3381414Scindi mod_release_mod(modp); 3391414Scindi 3401414Scindi return (cmi); 3411414Scindi } 3421414Scindi 3431414Scindi /* 344*5254Sgavinm * Try to load a cpu module with specific support for this chip type. 3451414Scindi */ 346*5254Sgavinm static cmi_t * 347*5254Sgavinm cmi_load_specific(cmi_hdl_t hdl, void **datap) 3481414Scindi { 3491414Scindi cmi_t *cmi; 350*5254Sgavinm int err; 351*5254Sgavinm int i; 352*5254Sgavinm 353*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 354*5254Sgavinm 355*5254Sgavinm for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) { 356*5254Sgavinm int suffixlevel; 357*5254Sgavinm 358*5254Sgavinm if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL) 359*5254Sgavinm return (NULL); 360*5254Sgavinm 361*5254Sgavinm /* 362*5254Sgavinm * A module has loaded and has a _cmi_ops structure, and the 363*5254Sgavinm * module has been held for this instance. Call its cmi_init 364*5254Sgavinm * entry point - we expect success (0) or ENOTSUP. 365*5254Sgavinm */ 366*5254Sgavinm if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) { 367*5254Sgavinm if (boothowto & RB_VERBOSE) { 368*5254Sgavinm printf("initialized cpu module '%s' on " 369*5254Sgavinm "chip %d core %d strand %d\n", 370*5254Sgavinm cmi->cmi_modp->mod_modname, 371*5254Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 372*5254Sgavinm cmi_hdl_strandid(hdl)); 373*5254Sgavinm } 374*5254Sgavinm return (cmi); 375*5254Sgavinm } else if (err != ENOTSUP) { 376*5254Sgavinm cmn_err(CE_WARN, "failed to init cpu module '%s' on " 377*5254Sgavinm "chip %d core %d strand %d: err=%d\n", 378*5254Sgavinm cmi->cmi_modp->mod_modname, 379*5254Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 380*5254Sgavinm cmi_hdl_strandid(hdl), err); 381*5254Sgavinm } 382*5254Sgavinm 383*5254Sgavinm /* 384*5254Sgavinm * The module failed or declined to init, so release 385*5254Sgavinm * it and update i to be equal to the number 386*5254Sgavinm * of suffices actually used in the last module path. 387*5254Sgavinm */ 388*5254Sgavinm cmi_rele(cmi); 389*5254Sgavinm i = suffixlevel; 390*5254Sgavinm } 391*5254Sgavinm 392*5254Sgavinm return (NULL); 393*5254Sgavinm } 394*5254Sgavinm 395*5254Sgavinm /* 396*5254Sgavinm * Load the generic IA32 MCA cpu module, which may still supplement 397*5254Sgavinm * itself with model-specific support through cpu model-specific modules. 398*5254Sgavinm */ 399*5254Sgavinm static cmi_t * 400*5254Sgavinm cmi_load_generic(cmi_hdl_t hdl, void **datap) 401*5254Sgavinm { 402*5254Sgavinm modctl_t *modp; 403*5254Sgavinm cmi_t *cmi; 404*5254Sgavinm int modid; 405*5254Sgavinm int err; 406*5254Sgavinm 407*5254Sgavinm ASSERT(MUTEX_HELD(&cmi_load_lock)); 408*5254Sgavinm 409*5254Sgavinm if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1) 410*5254Sgavinm return (NULL); 411*5254Sgavinm 412*5254Sgavinm modp = mod_hold_by_id(modid); 413*5254Sgavinm cmi = cmi_load_modctl(modp); 414*5254Sgavinm if (cmi) 415*5254Sgavinm cmi_hold(cmi); 416*5254Sgavinm mod_release_mod(modp); 417*5254Sgavinm 418*5254Sgavinm if (cmi == NULL) 419*5254Sgavinm return (NULL); 420*5254Sgavinm 421*5254Sgavinm if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) { 422*5254Sgavinm if (err != ENOTSUP) 423*5254Sgavinm cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to " 424*5254Sgavinm "init: err=%d", err); 425*5254Sgavinm cmi_rele(cmi); 426*5254Sgavinm return (NULL); 427*5254Sgavinm } 428*5254Sgavinm 429*5254Sgavinm return (cmi); 430*5254Sgavinm } 431*5254Sgavinm 432*5254Sgavinm cmi_hdl_t 433*5254Sgavinm cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid, 434*5254Sgavinm uint_t strandid) 435*5254Sgavinm { 436*5254Sgavinm cmi_t *cmi = NULL; 437*5254Sgavinm cmi_hdl_t hdl; 4381414Scindi void *data; 4391414Scindi 440*5254Sgavinm if (cmi_no_init) { 441*5254Sgavinm cmi_no_mca_init = 1; 442*5254Sgavinm return (NULL); 443*5254Sgavinm } 444*5254Sgavinm 4451414Scindi mutex_enter(&cmi_load_lock); 4461414Scindi 447*5254Sgavinm if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) { 4481414Scindi mutex_exit(&cmi_load_lock); 449*5254Sgavinm cmn_err(CE_WARN, "There will be no MCA support on chip %d " 450*5254Sgavinm "core %d strand %d (cmi_hdl_create returned NULL)\n", 451*5254Sgavinm chipid, coreid, strandid); 452*5254Sgavinm return (NULL); 4531414Scindi } 4541414Scindi 455*5254Sgavinm if (!cmi_force_generic) 456*5254Sgavinm cmi = cmi_load_specific(hdl, &data); 457*5254Sgavinm 458*5254Sgavinm if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) { 459*5254Sgavinm cmn_err(CE_WARN, "There will be no MCA support on chip %d " 460*5254Sgavinm "core %d strand %d\n", chipid, coreid, strandid); 461*5254Sgavinm cmi_hdl_rele(hdl); 4621414Scindi mutex_exit(&cmi_load_lock); 463*5254Sgavinm return (NULL); 4641414Scindi } 4651414Scindi 466*5254Sgavinm cmi_hdl_setcmi(hdl, cmi, data); 4671414Scindi 468*5254Sgavinm cms_init(hdl); 469*5254Sgavinm 4701414Scindi mutex_exit(&cmi_load_lock); 4711414Scindi 472*5254Sgavinm return (hdl); 4731414Scindi } 4741414Scindi 475*5254Sgavinm /* 476*5254Sgavinm * cmi_fini is not called at the moment. It is intended to be called 477*5254Sgavinm * on DR deconfigure of a cpu resource. It should not be called at 478*5254Sgavinm * simple offline of a cpu. 479*5254Sgavinm */ 4801414Scindi void 481*5254Sgavinm cmi_fini(cmi_hdl_t hdl) 4821414Scindi { 483*5254Sgavinm cmi_t *cmi = HDL2CMI(hdl); 484*5254Sgavinm 485*5254Sgavinm if (cms_present(hdl)) 486*5254Sgavinm cms_fini(hdl); 487*5254Sgavinm 488*5254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_fini)) 489*5254Sgavinm CMI_OPS(cmi)->cmi_fini(hdl); 490*5254Sgavinm 491*5254Sgavinm cmi_hdl_rele(hdl); /* release hold obtained in cmi_hdl_create */ 4921414Scindi } 4931414Scindi 494*5254Sgavinm /* 495*5254Sgavinm * cmi_post_startup is called from post_startup for the boot cpu only. 496*5254Sgavinm */ 4971414Scindi void 498*5254Sgavinm cmi_post_startup(void) 4991414Scindi { 500*5254Sgavinm cmi_hdl_t hdl; 501*5254Sgavinm cmi_t *cmi; 502*5254Sgavinm 503*5254Sgavinm if (cmi_no_mca_init != 0 || 504*5254Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 505*5254Sgavinm return; 506*5254Sgavinm 507*5254Sgavinm cmi = HDL2CMI(hdl); 508*5254Sgavinm 509*5254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_post_startup)) 510*5254Sgavinm CMI_OPS(cmi)->cmi_post_startup(hdl); 511*5254Sgavinm 512*5254Sgavinm cmi_hdl_rele(hdl); 5131414Scindi } 5141414Scindi 5152869Sgavinm /* 5162869Sgavinm * Called just once from start_other_cpus when all processors are started. 5172869Sgavinm * This will not be called for each cpu, so the registered op must not 5182869Sgavinm * assume it is called as such. 5192869Sgavinm */ 5201414Scindi void 5211642Sgavinm cmi_post_mpstartup(void) 5221642Sgavinm { 523*5254Sgavinm cmi_hdl_t hdl; 524*5254Sgavinm cmi_t *cmi; 525*5254Sgavinm 526*5254Sgavinm if (cmi_no_mca_init != 0 || 527*5254Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 528*5254Sgavinm return; 529*5254Sgavinm 530*5254Sgavinm cmi = HDL2CMI(hdl); 531*5254Sgavinm 532*5254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup)) 533*5254Sgavinm CMI_OPS(cmi)->cmi_post_mpstartup(hdl); 534*5254Sgavinm 535*5254Sgavinm cmi_hdl_rele(hdl); 5361642Sgavinm } 5371642Sgavinm 5381642Sgavinm void 539*5254Sgavinm cmi_faulted_enter(cmi_hdl_t hdl) 5401414Scindi { 541*5254Sgavinm cmi_t *cmi = HDL2CMI(hdl); 542*5254Sgavinm 543*5254Sgavinm if (cmi_no_mca_init != 0) 544*5254Sgavinm return; 545*5254Sgavinm 546*5254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_faulted_enter)) 547*5254Sgavinm CMI_OPS(cmi)->cmi_faulted_enter(hdl); 548*5254Sgavinm } 549*5254Sgavinm 550*5254Sgavinm void 551*5254Sgavinm cmi_faulted_exit(cmi_hdl_t hdl) 552*5254Sgavinm { 553*5254Sgavinm cmi_t *cmi = HDL2CMI(hdl); 554*5254Sgavinm 555*5254Sgavinm if (cmi_no_mca_init != 0) 556*5254Sgavinm return; 557*5254Sgavinm 558*5254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_faulted_exit)) 559*5254Sgavinm CMI_OPS(cmi)->cmi_faulted_exit(hdl); 5601414Scindi } 5611414Scindi 5621414Scindi void 563*5254Sgavinm cmi_mca_init(cmi_hdl_t hdl) 5641414Scindi { 565*5254Sgavinm cmi_t *cmi; 566*5254Sgavinm 567*5254Sgavinm if (cmi_no_mca_init != 0) 568*5254Sgavinm return; 569*5254Sgavinm 570*5254Sgavinm cmi = HDL2CMI(hdl); 571*5254Sgavinm 572*5254Sgavinm if (CMI_OP_PRESENT(cmi, cmi_mca_init)) 573*5254Sgavinm CMI_OPS(cmi)->cmi_mca_init(hdl); 5741414Scindi } 5751414Scindi 576*5254Sgavinm #define CMI_RESPONSE_PANIC 0x0 /* panic must have value 0 */ 577*5254Sgavinm #define CMI_RESPONSE_NONE 0x1 578*5254Sgavinm #define CMI_RESPONSE_CKILL 0x2 579*5254Sgavinm #define CMI_RESPONSE_REBOOT 0x3 /* not implemented */ 580*5254Sgavinm #define CMI_RESPONSE_ONTRAP_PROT 0x4 581*5254Sgavinm #define CMI_RESPONSE_LOFAULT_PROT 0x5 582*5254Sgavinm 583*5254Sgavinm /* 584*5254Sgavinm * Return 0 if we will panic in response to this machine check, otherwise 585*5254Sgavinm * non-zero. If the caller is cmi_mca_trap in this file then the nonzero 586*5254Sgavinm * return values are to be interpreted from CMI_RESPONSE_* above. 587*5254Sgavinm * 588*5254Sgavinm * This function must just return what will be done without actually 589*5254Sgavinm * doing anything; this includes not changing the regs. 590*5254Sgavinm */ 5911414Scindi int 592*5254Sgavinm cmi_mce_response(struct regs *rp, uint64_t disp) 5931414Scindi { 594*5254Sgavinm int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC : 595*5254Sgavinm CMI_RESPONSE_NONE; 596*5254Sgavinm on_trap_data_t *otp; 597*5254Sgavinm 598*5254Sgavinm ASSERT(rp != NULL); /* don't call for polling, only on #MC */ 599*5254Sgavinm 600*5254Sgavinm /* 601*5254Sgavinm * If no bits are set in the disposition then there is nothing to 602*5254Sgavinm * worry about and we do not need to trampoline to ontrap or 603*5254Sgavinm * lofault handlers. 604*5254Sgavinm */ 605*5254Sgavinm if (disp == 0) 606*5254Sgavinm return (CMI_RESPONSE_NONE); 607*5254Sgavinm 608*5254Sgavinm /* 609*5254Sgavinm * Unconstrained errors cannot be forgiven, even by ontrap or 610*5254Sgavinm * lofault protection. The data is not poisoned and may not 611*5254Sgavinm * even belong to the trapped context - eg a writeback of 612*5254Sgavinm * data that is found to be bad. 613*5254Sgavinm */ 614*5254Sgavinm if (disp & CMI_ERRDISP_UC_UNCONSTRAINED) 615*5254Sgavinm return (panicrsp); 616*5254Sgavinm 617*5254Sgavinm /* 618*5254Sgavinm * ontrap OT_DATA_EC and lofault protection forgive any disposition 619*5254Sgavinm * other than unconstrained, even those normally forced fatal. 620*5254Sgavinm */ 621*5254Sgavinm if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC) 622*5254Sgavinm return (CMI_RESPONSE_ONTRAP_PROT); 623*5254Sgavinm else if (curthread->t_lofault) 624*5254Sgavinm return (CMI_RESPONSE_LOFAULT_PROT); 625*5254Sgavinm 626*5254Sgavinm /* 627*5254Sgavinm * Forced-fatal errors are terminal even in user mode. 628*5254Sgavinm */ 629*5254Sgavinm if (disp & CMI_ERRDISP_FORCEFATAL) 630*5254Sgavinm return (panicrsp); 631*5254Sgavinm 632*5254Sgavinm /* 633*5254Sgavinm * If the trapped context is corrupt or we have no instruction pointer 634*5254Sgavinm * to resume at (and aren't trampolining to a fault handler) 635*5254Sgavinm * then in the kernel case we must panic and in usermode we 636*5254Sgavinm * kill the affected contract. 637*5254Sgavinm */ 638*5254Sgavinm if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID)) 639*5254Sgavinm return (USERMODE(rp->r_cs) ? CMI_RESPONSE_CKILL : panicrsp); 640*5254Sgavinm 641*5254Sgavinm /* 642*5254Sgavinm * Anything else is harmless 643*5254Sgavinm */ 644*5254Sgavinm return (CMI_RESPONSE_NONE); 6451414Scindi } 6461414Scindi 647*5254Sgavinm int cma_mca_trap_panic_suppressed = 0; 648*5254Sgavinm 649*5254Sgavinm static void 650*5254Sgavinm cmi_mca_panic(void) 6511414Scindi { 652*5254Sgavinm if (cmi_panic_on_uncorrectable_error) { 653*5254Sgavinm fm_panic("Unrecoverable Machine-Check Exception"); 654*5254Sgavinm } else { 655*5254Sgavinm cmn_err(CE_WARN, "suppressing panic from fatal #mc"); 656*5254Sgavinm cma_mca_trap_panic_suppressed++; 657*5254Sgavinm } 6581414Scindi } 6591414Scindi 660*5254Sgavinm 661*5254Sgavinm int cma_mca_trap_contract_kills = 0; 662*5254Sgavinm int cma_mca_trap_ontrap_forgiven = 0; 663*5254Sgavinm int cma_mca_trap_lofault_forgiven = 0; 664*5254Sgavinm 665*5254Sgavinm /* 666*5254Sgavinm * Native #MC handler - we branch to here from mcetrap 667*5254Sgavinm */ 668*5254Sgavinm /*ARGSUSED*/ 6691414Scindi void 6701414Scindi cmi_mca_trap(struct regs *rp) 6711414Scindi { 672*5254Sgavinm #ifndef __xpv 673*5254Sgavinm cmi_hdl_t hdl = NULL; 674*5254Sgavinm uint64_t disp; 675*5254Sgavinm cmi_t *cmi; 676*5254Sgavinm int s; 677*5254Sgavinm 678*5254Sgavinm if (cmi_no_mca_init != 0) 679*5254Sgavinm return; 680*5254Sgavinm 681*5254Sgavinm /* 682*5254Sgavinm * This function can call cmn_err, and the cpu module cmi_mca_trap 683*5254Sgavinm * entry point may also elect to call cmn_err (e.g., if it can't 684*5254Sgavinm * log the error onto an errorq, say very early in boot). 685*5254Sgavinm * We need to let cprintf know that we must not block. 686*5254Sgavinm */ 687*5254Sgavinm s = spl8(); 688*5254Sgavinm 689*5254Sgavinm if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU), 690*5254Sgavinm cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL || 691*5254Sgavinm (cmi = HDL2CMI(hdl)) == NULL || 692*5254Sgavinm !CMI_OP_PRESENT(cmi, cmi_mca_trap)) { 693*5254Sgavinm 694*5254Sgavinm cmn_err(CE_WARN, "#MC exception on cpuid %d: %s", 695*5254Sgavinm CPU->cpu_id, 696*5254Sgavinm hdl ? "handle lookup ok but no #MC handler found" : 697*5254Sgavinm "handle lookup failed"); 698*5254Sgavinm 699*5254Sgavinm if (hdl != NULL) 700*5254Sgavinm cmi_hdl_rele(hdl); 701*5254Sgavinm 702*5254Sgavinm splx(s); 703*5254Sgavinm return; 7041414Scindi } 705*5254Sgavinm 706*5254Sgavinm disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp); 7071414Scindi 708*5254Sgavinm switch (cmi_mce_response(rp, disp)) { 709*5254Sgavinm default: 710*5254Sgavinm cmn_err(CE_WARN, "Invalid response from cmi_mce_response"); 711*5254Sgavinm /*FALLTHRU*/ 712*5254Sgavinm 713*5254Sgavinm case CMI_RESPONSE_PANIC: 714*5254Sgavinm cmi_mca_panic(); 715*5254Sgavinm break; 716*5254Sgavinm 717*5254Sgavinm case CMI_RESPONSE_NONE: 718*5254Sgavinm break; 719*5254Sgavinm 720*5254Sgavinm case CMI_RESPONSE_CKILL: 721*5254Sgavinm ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR; 722*5254Sgavinm aston(curthread); 723*5254Sgavinm cma_mca_trap_contract_kills++; 724*5254Sgavinm break; 7251414Scindi 726*5254Sgavinm case CMI_RESPONSE_ONTRAP_PROT: { 727*5254Sgavinm on_trap_data_t *otp = curthread->t_ontrap; 728*5254Sgavinm otp->ot_trap = OT_DATA_EC; 729*5254Sgavinm rp->r_pc = otp->ot_trampoline; 730*5254Sgavinm cma_mca_trap_ontrap_forgiven++; 731*5254Sgavinm break; 732*5254Sgavinm } 7331414Scindi 734*5254Sgavinm case CMI_RESPONSE_LOFAULT_PROT: 735*5254Sgavinm rp->r_r0 = EFAULT; 736*5254Sgavinm rp->r_pc = curthread->t_lofault; 737*5254Sgavinm cma_mca_trap_lofault_forgiven++; 738*5254Sgavinm break; 739*5254Sgavinm } 740*5254Sgavinm 741*5254Sgavinm cmi_hdl_rele(hdl); 742*5254Sgavinm splx(s); 743*5254Sgavinm #endif /* __xpv */ 7441414Scindi } 7451414Scindi 7461414Scindi void 747*5254Sgavinm cmi_hdl_poke(cmi_hdl_t hdl) 7481414Scindi { 749*5254Sgavinm cmi_t *cmi = HDL2CMI(hdl); 750*5254Sgavinm 751*5254Sgavinm if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke)) 752*5254Sgavinm return; 753*5254Sgavinm 754*5254Sgavinm CMI_OPS(cmi)->cmi_hdl_poke(hdl); 7551414Scindi } 7561414Scindi 7571414Scindi void 758*5254Sgavinm cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata) 7591414Scindi { 760*5254Sgavinm if (!cmi_no_mca_init) 761*5254Sgavinm cmi_hdl_setmc(hdl, mcops, mcdata); 7621414Scindi } 7631414Scindi 764*5254Sgavinm cmi_errno_t 7653164Sgavinm cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd, 7663164Sgavinm int syndtype, mc_unum_t *up) 7671414Scindi { 7681414Scindi const struct cmi_mc_ops *mcops; 769*5254Sgavinm cmi_hdl_t hdl; 770*5254Sgavinm cmi_errno_t rv; 771*5254Sgavinm 772*5254Sgavinm if (cmi_no_mca_init || 773*5254Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 774*5254Sgavinm return (CMIERR_MC_ABSENT); 7751414Scindi 776*5254Sgavinm if ((mcops = cmi_hdl_getmcops(hdl)) == NULL || 777*5254Sgavinm mcops->cmi_mc_patounum == NULL) { 778*5254Sgavinm cmi_hdl_rele(hdl); 779*5254Sgavinm return (CMIERR_MC_NOTSUP); 780*5254Sgavinm } 7811414Scindi 782*5254Sgavinm rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi, 783*5254Sgavinm valid_lo, synd, syndtype, up); 784*5254Sgavinm 785*5254Sgavinm cmi_hdl_rele(hdl); 786*5254Sgavinm 787*5254Sgavinm return (rv); 7881414Scindi } 7891414Scindi 790*5254Sgavinm cmi_errno_t 7911414Scindi cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap) 7921414Scindi { 7931414Scindi const struct cmi_mc_ops *mcops; 794*5254Sgavinm cmi_hdl_t hdl; 795*5254Sgavinm cmi_errno_t rv; 7961414Scindi 7971414Scindi if (up != NULL && nvl != NULL) 798*5254Sgavinm return (CMIERR_API); /* convert from just one form */ 799*5254Sgavinm 800*5254Sgavinm if (cmi_no_mca_init || 801*5254Sgavinm (hdl = cmi_hdl_any()) == NULL) /* short-term hold */ 802*5254Sgavinm return (CMIERR_MC_ABSENT); 803*5254Sgavinm 804*5254Sgavinm if ((mcops = cmi_hdl_getmcops(hdl)) == NULL || 805*5254Sgavinm mcops->cmi_mc_unumtopa == NULL) { 806*5254Sgavinm cmi_hdl_rele(hdl); 807*5254Sgavinm 808*5254Sgavinm if (nvl != NULL && nvlist_lookup_uint64(nvl, 809*5254Sgavinm FM_FMRI_MEM_PHYSADDR, pap) == 0) { 810*5254Sgavinm return (CMIERR_MC_PARTIALUNUMTOPA); 811*5254Sgavinm } else { 812*5254Sgavinm return (mcops && mcops->cmi_mc_unumtopa ? 813*5254Sgavinm CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT); 814*5254Sgavinm } 815*5254Sgavinm } 816*5254Sgavinm 817*5254Sgavinm rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap); 818*5254Sgavinm 819*5254Sgavinm cmi_hdl_rele(hdl); 820*5254Sgavinm 821*5254Sgavinm return (rv); 822*5254Sgavinm } 8231414Scindi 824*5254Sgavinm void 825*5254Sgavinm cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync) 826*5254Sgavinm { 827*5254Sgavinm const struct cmi_mc_ops *mcops; 828*5254Sgavinm 829*5254Sgavinm if (cmi_no_mca_init || (mcops = cmi_hdl_getmcops(hdl)) == NULL) 830*5254Sgavinm return; 831*5254Sgavinm 832*5254Sgavinm if (mcops->cmi_mc_logout != NULL) 833*5254Sgavinm mcops->cmi_mc_logout(hdl, ismc, sync); 834*5254Sgavinm } 8351414Scindi 836*5254Sgavinm cmi_errno_t 837*5254Sgavinm cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs, 838*5254Sgavinm int force) 839*5254Sgavinm { 840*5254Sgavinm cmi_t *cmi = cmi_hdl_getcmi(hdl); 841*5254Sgavinm 842*5254Sgavinm if (!CMI_OP_PRESENT(cmi, cmi_msrinject)) 843*5254Sgavinm return (CMIERR_NOTSUP); 844*5254Sgavinm 845*5254Sgavinm return (CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force)); 8461414Scindi } 847*5254Sgavinm 848*5254Sgavinm boolean_t 849*5254Sgavinm cmi_panic_on_ue(void) 850*5254Sgavinm { 851*5254Sgavinm return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE); 852*5254Sgavinm } 853