1*20c794b3Sgavinm /* 2*20c794b3Sgavinm * CDDL HEADER START 3*20c794b3Sgavinm * 4*20c794b3Sgavinm * The contents of this file are subject to the terms of the 5*20c794b3Sgavinm * Common Development and Distribution License (the "License"). 6*20c794b3Sgavinm * You may not use this file except in compliance with the License. 7*20c794b3Sgavinm * 8*20c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*20c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 10*20c794b3Sgavinm * See the License for the specific language governing permissions 11*20c794b3Sgavinm * and limitations under the License. 12*20c794b3Sgavinm * 13*20c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 14*20c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*20c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 16*20c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 17*20c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 18*20c794b3Sgavinm * 19*20c794b3Sgavinm * CDDL HEADER END 20*20c794b3Sgavinm */ 21*20c794b3Sgavinm 22*20c794b3Sgavinm /* 23*20c794b3Sgavinm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*20c794b3Sgavinm * Use is subject to license terms. 25*20c794b3Sgavinm */ 26*20c794b3Sgavinm 27*20c794b3Sgavinm #pragma ident "%Z%%M% %I% %E% SMI" 28*20c794b3Sgavinm 29*20c794b3Sgavinm #include <sys/types.h> 30*20c794b3Sgavinm #include <sys/cpu_module_ms_impl.h> 31*20c794b3Sgavinm #include <sys/cpuvar.h> 32*20c794b3Sgavinm #include <sys/ksynch.h> 33*20c794b3Sgavinm #include <sys/modctl.h> 34*20c794b3Sgavinm #include <sys/x86_archext.h> 35*20c794b3Sgavinm #include <sys/systm.h> 36*20c794b3Sgavinm #include <sys/cmn_err.h> 37*20c794b3Sgavinm #include <sys/param.h> 38*20c794b3Sgavinm #include <sys/reboot.h> 39*20c794b3Sgavinm 40*20c794b3Sgavinm /* 41*20c794b3Sgavinm * Set to prevent model-specific support from initialising. 42*20c794b3Sgavinm */ 43*20c794b3Sgavinm int cms_no_model_specific = 0; 44*20c794b3Sgavinm 45*20c794b3Sgavinm /* 46*20c794b3Sgavinm * Subdirectory (relative to the module search path) in which we will 47*20c794b3Sgavinm * look for model-specific modules. 48*20c794b3Sgavinm */ 49*20c794b3Sgavinm #define CPUMOD_MS_SUBDIR "cpu" 50*20c794b3Sgavinm 51*20c794b3Sgavinm /* 52*20c794b3Sgavinm * Cpu model-specific modules have filenames beginning with the following. 53*20c794b3Sgavinm */ 54*20c794b3Sgavinm #define CPUMOD_MS_PREFIX "cpu_ms" 55*20c794b3Sgavinm 56*20c794b3Sgavinm #define HDL2CMS(hdl) cms_hdl_getcms(hdl) 57*20c794b3Sgavinm 58*20c794b3Sgavinm #define CMS_OPS(cms) (cms)->cms_ops 59*20c794b3Sgavinm #define CMS_OP_PRESENT(cms, op) ((cms) && CMS_OPS(cms)->op != NULL) 60*20c794b3Sgavinm 61*20c794b3Sgavinm struct cms_cpuid { 62*20c794b3Sgavinm const char *vendor; 63*20c794b3Sgavinm uint_t family; 64*20c794b3Sgavinm uint_t model; 65*20c794b3Sgavinm uint_t stepping; 66*20c794b3Sgavinm }; 67*20c794b3Sgavinm 68*20c794b3Sgavinm #define CMS_MATCH_VENDOR 0 /* Just match on vendor */ 69*20c794b3Sgavinm #define CMS_MATCH_FAMILY 1 /* Match down to family */ 70*20c794b3Sgavinm #define CMS_MATCH_MODEL 2 /* Match down to model */ 71*20c794b3Sgavinm #define CMS_MATCH_STEPPING 3 /* Match down to stepping */ 72*20c794b3Sgavinm 73*20c794b3Sgavinm /* 74*20c794b3Sgavinm * Structure used to keep track of modules we have loaded. 75*20c794b3Sgavinm */ 76*20c794b3Sgavinm typedef struct cms { 77*20c794b3Sgavinm struct cms *cms_next; 78*20c794b3Sgavinm struct cms *cms_prev; 79*20c794b3Sgavinm const cms_ops_t *cms_ops; 80*20c794b3Sgavinm struct modctl *cms_modp; 81*20c794b3Sgavinm uint_t cms_refcnt; 82*20c794b3Sgavinm } cms_t; 83*20c794b3Sgavinm 84*20c794b3Sgavinm static cms_t *cms_list; 85*20c794b3Sgavinm static kmutex_t cms_load_lock; 86*20c794b3Sgavinm 87*20c794b3Sgavinm /* 88*20c794b3Sgavinm * We stash a cms_t and associated private data via cmi_hdl_setspecific. 89*20c794b3Sgavinm */ 90*20c794b3Sgavinm struct cms_ctl { 91*20c794b3Sgavinm cms_t *cs_cms; 92*20c794b3Sgavinm void *cs_cmsdata; 93*20c794b3Sgavinm }; 94*20c794b3Sgavinm 95*20c794b3Sgavinm static cms_t * 96*20c794b3Sgavinm cms_hdl_getcms(cmi_hdl_t hdl) 97*20c794b3Sgavinm { 98*20c794b3Sgavinm struct cms_ctl *cdp = cmi_hdl_getspecific(hdl); 99*20c794b3Sgavinm 100*20c794b3Sgavinm return (cdp != NULL ? cdp->cs_cms : NULL); 101*20c794b3Sgavinm } 102*20c794b3Sgavinm 103*20c794b3Sgavinm void * 104*20c794b3Sgavinm cms_hdl_getcmsdata(cmi_hdl_t hdl) 105*20c794b3Sgavinm { 106*20c794b3Sgavinm struct cms_ctl *cdp = cmi_hdl_getspecific(hdl); 107*20c794b3Sgavinm 108*20c794b3Sgavinm return (cdp != NULL ? cdp->cs_cmsdata : NULL); 109*20c794b3Sgavinm } 110*20c794b3Sgavinm 111*20c794b3Sgavinm static void 112*20c794b3Sgavinm cms_link(cms_t *cms) 113*20c794b3Sgavinm { 114*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 115*20c794b3Sgavinm 116*20c794b3Sgavinm cms->cms_prev = NULL; 117*20c794b3Sgavinm cms->cms_next = cms_list; 118*20c794b3Sgavinm if (cms_list != NULL) 119*20c794b3Sgavinm cms_list->cms_prev = cms; 120*20c794b3Sgavinm cms_list = cms; 121*20c794b3Sgavinm } 122*20c794b3Sgavinm 123*20c794b3Sgavinm static void 124*20c794b3Sgavinm cms_unlink(cms_t *cms) 125*20c794b3Sgavinm { 126*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 127*20c794b3Sgavinm ASSERT(cms->cms_refcnt == 0); 128*20c794b3Sgavinm 129*20c794b3Sgavinm if (cms->cms_prev != NULL) 130*20c794b3Sgavinm cms->cms_prev->cms_next = cms->cms_next; 131*20c794b3Sgavinm 132*20c794b3Sgavinm if (cms->cms_next != NULL) 133*20c794b3Sgavinm cms->cms_next->cms_prev = cms->cms_prev; 134*20c794b3Sgavinm 135*20c794b3Sgavinm if (cms_list == cms) 136*20c794b3Sgavinm cms_list = cms->cms_next; 137*20c794b3Sgavinm } 138*20c794b3Sgavinm 139*20c794b3Sgavinm /* 140*20c794b3Sgavinm * Hold the module in memory. We call to CPU modules without using the 141*20c794b3Sgavinm * stubs mechanism, so these modules must be manually held in memory. 142*20c794b3Sgavinm * The mod_ref acts as if another loaded module has a dependency on us. 143*20c794b3Sgavinm */ 144*20c794b3Sgavinm static void 145*20c794b3Sgavinm cms_hold(cms_t *cms) 146*20c794b3Sgavinm { 147*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 148*20c794b3Sgavinm 149*20c794b3Sgavinm mutex_enter(&mod_lock); 150*20c794b3Sgavinm cms->cms_modp->mod_ref++; 151*20c794b3Sgavinm mutex_exit(&mod_lock); 152*20c794b3Sgavinm cms->cms_refcnt++; 153*20c794b3Sgavinm } 154*20c794b3Sgavinm 155*20c794b3Sgavinm static void 156*20c794b3Sgavinm cms_rele(cms_t *cms) 157*20c794b3Sgavinm { 158*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 159*20c794b3Sgavinm 160*20c794b3Sgavinm mutex_enter(&mod_lock); 161*20c794b3Sgavinm cms->cms_modp->mod_ref--; 162*20c794b3Sgavinm mutex_exit(&mod_lock); 163*20c794b3Sgavinm 164*20c794b3Sgavinm if (--cms->cms_refcnt == 0) { 165*20c794b3Sgavinm cms_unlink(cms); 166*20c794b3Sgavinm kmem_free(cms, sizeof (cms_t)); 167*20c794b3Sgavinm } 168*20c794b3Sgavinm } 169*20c794b3Sgavinm 170*20c794b3Sgavinm static cms_ops_t * 171*20c794b3Sgavinm cms_getops(modctl_t *modp) 172*20c794b3Sgavinm { 173*20c794b3Sgavinm cms_ops_t *ops; 174*20c794b3Sgavinm 175*20c794b3Sgavinm if ((ops = (cms_ops_t *)modlookup_by_modctl(modp, "_cms_ops")) == 176*20c794b3Sgavinm NULL) { 177*20c794b3Sgavinm cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no _cms_ops " 178*20c794b3Sgavinm "found", modp->mod_modname); 179*20c794b3Sgavinm return (NULL); 180*20c794b3Sgavinm } 181*20c794b3Sgavinm 182*20c794b3Sgavinm if (ops->cms_init == NULL) { 183*20c794b3Sgavinm cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no cms_init " 184*20c794b3Sgavinm "entry point", modp->mod_modname); 185*20c794b3Sgavinm return (NULL); 186*20c794b3Sgavinm } 187*20c794b3Sgavinm 188*20c794b3Sgavinm return (ops); 189*20c794b3Sgavinm } 190*20c794b3Sgavinm 191*20c794b3Sgavinm static cms_t * 192*20c794b3Sgavinm cms_load_modctl(modctl_t *modp) 193*20c794b3Sgavinm { 194*20c794b3Sgavinm cms_ops_t *ops; 195*20c794b3Sgavinm uintptr_t ver; 196*20c794b3Sgavinm cms_t *cms; 197*20c794b3Sgavinm cms_api_ver_t apiver; 198*20c794b3Sgavinm 199*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 200*20c794b3Sgavinm 201*20c794b3Sgavinm for (cms = cms_list; cms != NULL; cms = cms->cms_next) { 202*20c794b3Sgavinm if (cms->cms_modp == modp) 203*20c794b3Sgavinm return (cms); 204*20c794b3Sgavinm } 205*20c794b3Sgavinm 206*20c794b3Sgavinm if ((ver = modlookup_by_modctl(modp, "_cms_api_version")) == NULL) { 207*20c794b3Sgavinm cmn_err(CE_WARN, "cpu model-specific module '%s' is invalid: " 208*20c794b3Sgavinm "no _cms_api_version", modp->mod_modname); 209*20c794b3Sgavinm return (NULL); 210*20c794b3Sgavinm } else { 211*20c794b3Sgavinm apiver = *((cms_api_ver_t *)ver); 212*20c794b3Sgavinm if (!CMS_API_VERSION_CHKMAGIC(apiver)) { 213*20c794b3Sgavinm cmn_err(CE_WARN, "cpu model-specific module '%s' is " 214*20c794b3Sgavinm "invalid: _cms_api_version 0x%x has bad magic", 215*20c794b3Sgavinm modp->mod_modname, apiver); 216*20c794b3Sgavinm return (NULL); 217*20c794b3Sgavinm } 218*20c794b3Sgavinm } 219*20c794b3Sgavinm 220*20c794b3Sgavinm if (apiver != CMS_API_VERSION) { 221*20c794b3Sgavinm cmn_err(CE_WARN, "cpu model-specific module '%s' has API " 222*20c794b3Sgavinm "version %d, kernel requires API version %d", 223*20c794b3Sgavinm modp->mod_modname, CMS_API_VERSION_TOPRINT(apiver), 224*20c794b3Sgavinm CMS_API_VERSION_TOPRINT(CMS_API_VERSION)); 225*20c794b3Sgavinm return (NULL); 226*20c794b3Sgavinm } 227*20c794b3Sgavinm 228*20c794b3Sgavinm if ((ops = cms_getops(modp)) == NULL) 229*20c794b3Sgavinm return (NULL); 230*20c794b3Sgavinm 231*20c794b3Sgavinm cms = kmem_zalloc(sizeof (cms_t), KM_SLEEP); 232*20c794b3Sgavinm cms->cms_ops = ops; 233*20c794b3Sgavinm cms->cms_modp = modp; 234*20c794b3Sgavinm 235*20c794b3Sgavinm cms_link(cms); 236*20c794b3Sgavinm 237*20c794b3Sgavinm return (cms); 238*20c794b3Sgavinm } 239*20c794b3Sgavinm 240*20c794b3Sgavinm static int 241*20c794b3Sgavinm cms_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match) 242*20c794b3Sgavinm { 243*20c794b3Sgavinm if (match >= CMS_MATCH_VENDOR && 244*20c794b3Sgavinm cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2)) 245*20c794b3Sgavinm return (0); 246*20c794b3Sgavinm 247*20c794b3Sgavinm if (match >= CMS_MATCH_FAMILY && 248*20c794b3Sgavinm cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2)) 249*20c794b3Sgavinm return (0); 250*20c794b3Sgavinm 251*20c794b3Sgavinm if (match >= CMS_MATCH_MODEL && 252*20c794b3Sgavinm cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2)) 253*20c794b3Sgavinm return (0); 254*20c794b3Sgavinm 255*20c794b3Sgavinm if (match >= CMS_MATCH_STEPPING && 256*20c794b3Sgavinm cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2)) 257*20c794b3Sgavinm return (0); 258*20c794b3Sgavinm 259*20c794b3Sgavinm return (1); 260*20c794b3Sgavinm } 261*20c794b3Sgavinm 262*20c794b3Sgavinm static int 263*20c794b3Sgavinm cms_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3) 264*20c794b3Sgavinm { 265*20c794b3Sgavinm cmi_hdl_t thdl = (cmi_hdl_t)arg1; 266*20c794b3Sgavinm int match = *((int *)arg2); 267*20c794b3Sgavinm cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3; 268*20c794b3Sgavinm 269*20c794b3Sgavinm if (cms_cpu_match(thdl, whdl, match)) { 270*20c794b3Sgavinm cmi_hdl_hold(whdl); /* short-term hold */ 271*20c794b3Sgavinm *rsltp = whdl; 272*20c794b3Sgavinm return (CMI_HDL_WALK_DONE); 273*20c794b3Sgavinm } else { 274*20c794b3Sgavinm return (CMI_HDL_WALK_NEXT); 275*20c794b3Sgavinm } 276*20c794b3Sgavinm } 277*20c794b3Sgavinm 278*20c794b3Sgavinm /* 279*20c794b3Sgavinm * Look to see if we've already got a module loaded for a CPU just 280*20c794b3Sgavinm * like this one. If we do, then we'll re-use it. 281*20c794b3Sgavinm */ 282*20c794b3Sgavinm static cms_t * 283*20c794b3Sgavinm cms_search_list(cmi_hdl_t hdl, int match) 284*20c794b3Sgavinm { 285*20c794b3Sgavinm cmi_hdl_t dhdl = NULL; 286*20c794b3Sgavinm cms_t *cms = NULL; 287*20c794b3Sgavinm 288*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 289*20c794b3Sgavinm 290*20c794b3Sgavinm cmi_hdl_walk(cms_search_list_cb, (void *)hdl, (void *)&match, &dhdl); 291*20c794b3Sgavinm if (dhdl) { 292*20c794b3Sgavinm cms = HDL2CMS(dhdl); 293*20c794b3Sgavinm cmi_hdl_rele(dhdl); /* held in cms_search_list_cb */ 294*20c794b3Sgavinm } 295*20c794b3Sgavinm 296*20c794b3Sgavinm return (cms); 297*20c794b3Sgavinm } 298*20c794b3Sgavinm 299*20c794b3Sgavinm /* 300*20c794b3Sgavinm * Try to find or load a module that offers model-specific support for 301*20c794b3Sgavinm * this vendor/family/model/stepping combination. When attempting to load 302*20c794b3Sgavinm * a module we look in CPUMOD_MS_SUBDIR first for a match on 303*20c794b3Sgavinm * vendor/family/model/stepping, then on vendor/family/model (ignoring 304*20c794b3Sgavinm * stepping), then on vendor/family (ignoring model and stepping), then 305*20c794b3Sgavinm * on vendor alone. 306*20c794b3Sgavinm */ 307*20c794b3Sgavinm static cms_t * 308*20c794b3Sgavinm cms_load_module(cmi_hdl_t hdl, int match, int *chosenp) 309*20c794b3Sgavinm { 310*20c794b3Sgavinm modctl_t *modp; 311*20c794b3Sgavinm cms_t *cms; 312*20c794b3Sgavinm int modid; 313*20c794b3Sgavinm uint_t s[3]; 314*20c794b3Sgavinm 315*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 316*20c794b3Sgavinm ASSERT(match == CMS_MATCH_STEPPING || match == CMS_MATCH_MODEL || 317*20c794b3Sgavinm match == CMS_MATCH_FAMILY || match == CMS_MATCH_VENDOR); 318*20c794b3Sgavinm 319*20c794b3Sgavinm s[0] = cmi_hdl_family(hdl); 320*20c794b3Sgavinm s[1] = cmi_hdl_model(hdl); 321*20c794b3Sgavinm s[2] = cmi_hdl_stepping(hdl); 322*20c794b3Sgavinm 323*20c794b3Sgavinm /* 324*20c794b3Sgavinm * Have we already loaded a module for a cpu with the same 325*20c794b3Sgavinm * vendor/family/model/stepping? 326*20c794b3Sgavinm */ 327*20c794b3Sgavinm if ((cms = cms_search_list(hdl, match)) != NULL) { 328*20c794b3Sgavinm cms_hold(cms); 329*20c794b3Sgavinm return (cms); 330*20c794b3Sgavinm } 331*20c794b3Sgavinm 332*20c794b3Sgavinm modid = modload_qualified(CPUMOD_MS_SUBDIR, CPUMOD_MS_PREFIX, 333*20c794b3Sgavinm cmi_hdl_vendorstr(hdl), ".", s, match, chosenp); 334*20c794b3Sgavinm 335*20c794b3Sgavinm if (modid == -1) 336*20c794b3Sgavinm return (NULL); 337*20c794b3Sgavinm 338*20c794b3Sgavinm modp = mod_hold_by_id(modid); 339*20c794b3Sgavinm cms = cms_load_modctl(modp); 340*20c794b3Sgavinm if (cms) 341*20c794b3Sgavinm cms_hold(cms); 342*20c794b3Sgavinm mod_release_mod(modp); 343*20c794b3Sgavinm 344*20c794b3Sgavinm return (cms); 345*20c794b3Sgavinm } 346*20c794b3Sgavinm 347*20c794b3Sgavinm static cms_t * 348*20c794b3Sgavinm cms_load_specific(cmi_hdl_t hdl, void **datap) 349*20c794b3Sgavinm { 350*20c794b3Sgavinm cms_t *cms; 351*20c794b3Sgavinm int err; 352*20c794b3Sgavinm int i; 353*20c794b3Sgavinm 354*20c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 355*20c794b3Sgavinm 356*20c794b3Sgavinm for (i = CMS_MATCH_STEPPING; i >= CMS_MATCH_VENDOR; i--) { 357*20c794b3Sgavinm int suffixlevel; 358*20c794b3Sgavinm 359*20c794b3Sgavinm if ((cms = cms_load_module(hdl, i, &suffixlevel)) == NULL) 360*20c794b3Sgavinm return (NULL); 361*20c794b3Sgavinm 362*20c794b3Sgavinm /* 363*20c794b3Sgavinm * A module has loaded and has a _cms_ops structure, and the 364*20c794b3Sgavinm * module has been held for this instance. Call the cms_init 365*20c794b3Sgavinm * entry point - we expect success (0) or ENOTSUP. 366*20c794b3Sgavinm */ 367*20c794b3Sgavinm if ((err = cms->cms_ops->cms_init(hdl, datap)) == 0) { 368*20c794b3Sgavinm if (boothowto & RB_VERBOSE) { 369*20c794b3Sgavinm printf("initialized model-specific " 370*20c794b3Sgavinm "module '%s' on chip %d core %d " 371*20c794b3Sgavinm "strand %d\n", 372*20c794b3Sgavinm cms->cms_modp->mod_modname, 373*20c794b3Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 374*20c794b3Sgavinm cmi_hdl_strandid(hdl)); 375*20c794b3Sgavinm } 376*20c794b3Sgavinm return (cms); 377*20c794b3Sgavinm } else if (err != ENOTSUP) { 378*20c794b3Sgavinm cmn_err(CE_WARN, "failed to init model-specific " 379*20c794b3Sgavinm "module '%s' on chip %d core %d strand %d: err=%d", 380*20c794b3Sgavinm cms->cms_modp->mod_modname, 381*20c794b3Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 382*20c794b3Sgavinm cmi_hdl_strandid(hdl), err); 383*20c794b3Sgavinm } 384*20c794b3Sgavinm 385*20c794b3Sgavinm /* 386*20c794b3Sgavinm * The module failed or declined to init, so release 387*20c794b3Sgavinm * it and potentially change i to be equal to he number 388*20c794b3Sgavinm * of suffices actually used in the last module path. 389*20c794b3Sgavinm */ 390*20c794b3Sgavinm cms_rele(cms); 391*20c794b3Sgavinm i = suffixlevel; 392*20c794b3Sgavinm } 393*20c794b3Sgavinm 394*20c794b3Sgavinm return (NULL); 395*20c794b3Sgavinm } 396*20c794b3Sgavinm 397*20c794b3Sgavinm void 398*20c794b3Sgavinm cms_init(cmi_hdl_t hdl) 399*20c794b3Sgavinm { 400*20c794b3Sgavinm cms_t *cms; 401*20c794b3Sgavinm void *data; 402*20c794b3Sgavinm 403*20c794b3Sgavinm if (cms_no_model_specific != 0) 404*20c794b3Sgavinm return; 405*20c794b3Sgavinm 406*20c794b3Sgavinm mutex_enter(&cms_load_lock); 407*20c794b3Sgavinm 408*20c794b3Sgavinm if ((cms = cms_load_specific(hdl, &data)) != NULL) { 409*20c794b3Sgavinm struct cms_ctl *cdp; 410*20c794b3Sgavinm 411*20c794b3Sgavinm ASSERT(cmi_hdl_getspecific(hdl) == NULL); 412*20c794b3Sgavinm 413*20c794b3Sgavinm cdp = kmem_alloc(sizeof (*cdp), KM_SLEEP); 414*20c794b3Sgavinm cdp->cs_cms = cms; 415*20c794b3Sgavinm cdp->cs_cmsdata = data; 416*20c794b3Sgavinm cmi_hdl_setspecific(hdl, cdp); 417*20c794b3Sgavinm } 418*20c794b3Sgavinm 419*20c794b3Sgavinm mutex_exit(&cms_load_lock); 420*20c794b3Sgavinm } 421*20c794b3Sgavinm 422*20c794b3Sgavinm void 423*20c794b3Sgavinm cms_fini(cmi_hdl_t hdl) 424*20c794b3Sgavinm { 425*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 426*20c794b3Sgavinm 427*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_fini)) 428*20c794b3Sgavinm CMS_OPS(cms)->cms_fini(hdl); 429*20c794b3Sgavinm } 430*20c794b3Sgavinm 431*20c794b3Sgavinm boolean_t 432*20c794b3Sgavinm cms_present(cmi_hdl_t hdl) 433*20c794b3Sgavinm { 434*20c794b3Sgavinm return (HDL2CMS(hdl) != NULL ? B_TRUE : B_FALSE); 435*20c794b3Sgavinm } 436*20c794b3Sgavinm 437*20c794b3Sgavinm void 438*20c794b3Sgavinm cms_post_startup(cmi_hdl_t hdl) 439*20c794b3Sgavinm { 440*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 441*20c794b3Sgavinm 442*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_post_startup)) 443*20c794b3Sgavinm CMS_OPS(cms)->cms_post_startup(hdl); 444*20c794b3Sgavinm } 445*20c794b3Sgavinm 446*20c794b3Sgavinm void 447*20c794b3Sgavinm cms_post_mpstartup(cmi_hdl_t hdl) 448*20c794b3Sgavinm { 449*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 450*20c794b3Sgavinm 451*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_post_mpstartup)) 452*20c794b3Sgavinm CMS_OPS(cms)->cms_post_mpstartup(hdl); 453*20c794b3Sgavinm } 454*20c794b3Sgavinm 455*20c794b3Sgavinm size_t 456*20c794b3Sgavinm cms_logout_size(cmi_hdl_t hdl) 457*20c794b3Sgavinm { 458*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 459*20c794b3Sgavinm 460*20c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_logout_size)) 461*20c794b3Sgavinm return (0); 462*20c794b3Sgavinm 463*20c794b3Sgavinm return (CMS_OPS(cms)->cms_logout_size(hdl)); 464*20c794b3Sgavinm } 465*20c794b3Sgavinm 466*20c794b3Sgavinm uint64_t 467*20c794b3Sgavinm cms_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t def) 468*20c794b3Sgavinm { 469*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 470*20c794b3Sgavinm 471*20c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_mcgctl_val)) 472*20c794b3Sgavinm return (def); 473*20c794b3Sgavinm 474*20c794b3Sgavinm return (CMS_OPS(cms)->cms_mcgctl_val(hdl, nbanks, def)); 475*20c794b3Sgavinm } 476*20c794b3Sgavinm 477*20c794b3Sgavinm boolean_t 478*20c794b3Sgavinm cms_bankctl_skipinit(cmi_hdl_t hdl, int banknum) 479*20c794b3Sgavinm { 480*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 481*20c794b3Sgavinm 482*20c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankctl_skipinit)) 483*20c794b3Sgavinm return (B_FALSE); 484*20c794b3Sgavinm 485*20c794b3Sgavinm return (CMS_OPS(cms)->cms_bankctl_skipinit(hdl, banknum)); 486*20c794b3Sgavinm } 487*20c794b3Sgavinm 488*20c794b3Sgavinm uint64_t 489*20c794b3Sgavinm cms_bankctl_val(cmi_hdl_t hdl, int banknum, uint64_t def) 490*20c794b3Sgavinm { 491*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 492*20c794b3Sgavinm 493*20c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankctl_val)) 494*20c794b3Sgavinm return (def); 495*20c794b3Sgavinm 496*20c794b3Sgavinm return (CMS_OPS(cms)->cms_bankctl_val(hdl, banknum, def)); 497*20c794b3Sgavinm } 498*20c794b3Sgavinm 499*20c794b3Sgavinm boolean_t 500*20c794b3Sgavinm cms_bankstatus_skipinit(cmi_hdl_t hdl, int banknum) 501*20c794b3Sgavinm { 502*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 503*20c794b3Sgavinm 504*20c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankstatus_skipinit)) 505*20c794b3Sgavinm return (B_FALSE); 506*20c794b3Sgavinm 507*20c794b3Sgavinm return (CMS_OPS(cms)->cms_bankstatus_skipinit(hdl, banknum)); 508*20c794b3Sgavinm } 509*20c794b3Sgavinm 510*20c794b3Sgavinm uint64_t 511*20c794b3Sgavinm cms_bankstatus_val(cmi_hdl_t hdl, int banknum, uint64_t def) 512*20c794b3Sgavinm { 513*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 514*20c794b3Sgavinm 515*20c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankstatus_val)) 516*20c794b3Sgavinm return (def); 517*20c794b3Sgavinm 518*20c794b3Sgavinm return (CMS_OPS(cms)->cms_bankstatus_val(hdl, banknum, def)); 519*20c794b3Sgavinm } 520*20c794b3Sgavinm 521*20c794b3Sgavinm void 522*20c794b3Sgavinm cms_mca_init(cmi_hdl_t hdl, int nbanks) 523*20c794b3Sgavinm { 524*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 525*20c794b3Sgavinm 526*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_mca_init)) 527*20c794b3Sgavinm CMS_OPS(cms)->cms_mca_init(hdl, nbanks); 528*20c794b3Sgavinm } 529*20c794b3Sgavinm 530*20c794b3Sgavinm uint64_t 531*20c794b3Sgavinm cms_poll_ownermask(cmi_hdl_t hdl, hrtime_t poll_interval) 532*20c794b3Sgavinm { 533*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 534*20c794b3Sgavinm 535*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_poll_ownermask)) 536*20c794b3Sgavinm return (CMS_OPS(cms)->cms_poll_ownermask(hdl, poll_interval)); 537*20c794b3Sgavinm else 538*20c794b3Sgavinm return (-1ULL); /* poll all banks by default */ 539*20c794b3Sgavinm } 540*20c794b3Sgavinm 541*20c794b3Sgavinm void 542*20c794b3Sgavinm cms_bank_logout(cmi_hdl_t hdl, int banknum, uint64_t status, uint64_t addr, 543*20c794b3Sgavinm uint64_t misc, void *mslogout) 544*20c794b3Sgavinm { 545*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 546*20c794b3Sgavinm 547*20c794b3Sgavinm if (mslogout != NULL && CMS_OP_PRESENT(cms, cms_bank_logout)) 548*20c794b3Sgavinm CMS_OPS(cms)->cms_bank_logout(hdl, banknum, status, addr, 549*20c794b3Sgavinm misc, mslogout); 550*20c794b3Sgavinm } 551*20c794b3Sgavinm 552*20c794b3Sgavinm cms_errno_t 553*20c794b3Sgavinm cms_msrinject(cmi_hdl_t hdl, uint_t msr, uint64_t val) 554*20c794b3Sgavinm { 555*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 556*20c794b3Sgavinm 557*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_msrinject)) 558*20c794b3Sgavinm return (CMS_OPS(cms)->cms_msrinject(hdl, msr, val)); 559*20c794b3Sgavinm else 560*20c794b3Sgavinm return (CMSERR_NOTSUP); 561*20c794b3Sgavinm } 562*20c794b3Sgavinm 563*20c794b3Sgavinm uint32_t 564*20c794b3Sgavinm cms_error_action(cmi_hdl_t hdl, int ismc, int banknum, uint64_t status, 565*20c794b3Sgavinm uint64_t addr, uint64_t misc, void *mslogout) 566*20c794b3Sgavinm { 567*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 568*20c794b3Sgavinm 569*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_error_action)) 570*20c794b3Sgavinm return (CMS_OPS(cms)->cms_error_action(hdl, ismc, banknum, 571*20c794b3Sgavinm status, addr, misc, mslogout)); 572*20c794b3Sgavinm else 573*20c794b3Sgavinm return (0); 574*20c794b3Sgavinm } 575*20c794b3Sgavinm 576*20c794b3Sgavinm cms_cookie_t 577*20c794b3Sgavinm cms_disp_match(cmi_hdl_t hdl, int banknum, uint64_t status, uint64_t addr, 578*20c794b3Sgavinm uint64_t misc, void *mslogout) 579*20c794b3Sgavinm { 580*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 581*20c794b3Sgavinm 582*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_disp_match)) 583*20c794b3Sgavinm return (CMS_OPS(cms)->cms_disp_match(hdl, banknum, 584*20c794b3Sgavinm status, addr, misc, mslogout)); 585*20c794b3Sgavinm else 586*20c794b3Sgavinm return (NULL); 587*20c794b3Sgavinm 588*20c794b3Sgavinm } 589*20c794b3Sgavinm 590*20c794b3Sgavinm void 591*20c794b3Sgavinm cms_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie, const char **cpuclsp, 592*20c794b3Sgavinm const char **leafclsp) 593*20c794b3Sgavinm { 594*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 595*20c794b3Sgavinm 596*20c794b3Sgavinm if (cpuclsp == NULL || leafclsp == NULL) 597*20c794b3Sgavinm return; 598*20c794b3Sgavinm 599*20c794b3Sgavinm *cpuclsp = *leafclsp = NULL; 600*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_class)) { 601*20c794b3Sgavinm CMS_OPS(cms)->cms_ereport_class(hdl, mscookie, cpuclsp, 602*20c794b3Sgavinm leafclsp); 603*20c794b3Sgavinm } 604*20c794b3Sgavinm } 605*20c794b3Sgavinm 606*20c794b3Sgavinm nvlist_t * 607*20c794b3Sgavinm cms_ereport_detector(cmi_hdl_t hdl, cms_cookie_t mscookie, nv_alloc_t *nva) 608*20c794b3Sgavinm { 609*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 610*20c794b3Sgavinm 611*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_detector)) 612*20c794b3Sgavinm return (CMS_OPS(cms)->cms_ereport_detector(hdl, mscookie, nva)); 613*20c794b3Sgavinm else 614*20c794b3Sgavinm return (NULL); 615*20c794b3Sgavinm 616*20c794b3Sgavinm } 617*20c794b3Sgavinm 618*20c794b3Sgavinm boolean_t 619*20c794b3Sgavinm cms_ereport_includestack(cmi_hdl_t hdl, cms_cookie_t mscookie) 620*20c794b3Sgavinm { 621*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 622*20c794b3Sgavinm 623*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_includestack)) { 624*20c794b3Sgavinm return (CMS_OPS(cms)->cms_ereport_includestack(hdl, mscookie)); 625*20c794b3Sgavinm } else { 626*20c794b3Sgavinm return (B_FALSE); 627*20c794b3Sgavinm } 628*20c794b3Sgavinm } 629*20c794b3Sgavinm 630*20c794b3Sgavinm void 631*20c794b3Sgavinm cms_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *nvl, nv_alloc_t *nva, 632*20c794b3Sgavinm int banknum, uint64_t status, uint64_t addr, uint64_t misc, void *mslogout, 633*20c794b3Sgavinm cms_cookie_t mscookie) 634*20c794b3Sgavinm { 635*20c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 636*20c794b3Sgavinm 637*20c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_add_logout)) 638*20c794b3Sgavinm CMS_OPS(cms)->cms_ereport_add_logout(hdl, nvl, nva, banknum, 639*20c794b3Sgavinm status, addr, misc, mslogout, mscookie); 640*20c794b3Sgavinm 641*20c794b3Sgavinm } 642