120c794b3Sgavinm /* 220c794b3Sgavinm * CDDL HEADER START 320c794b3Sgavinm * 420c794b3Sgavinm * The contents of this file are subject to the terms of the 520c794b3Sgavinm * Common Development and Distribution License (the "License"). 620c794b3Sgavinm * You may not use this file except in compliance with the License. 720c794b3Sgavinm * 820c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 920c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 1020c794b3Sgavinm * See the License for the specific language governing permissions 1120c794b3Sgavinm * and limitations under the License. 1220c794b3Sgavinm * 1320c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 1420c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1520c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 1620c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 1720c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 1820c794b3Sgavinm * 1920c794b3Sgavinm * CDDL HEADER END 2020c794b3Sgavinm */ 2120c794b3Sgavinm 2220c794b3Sgavinm /* 23*c84b7bbeSAdrian Frost * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 2420c794b3Sgavinm */ 25a3114836SGerry Liu /* 26a3114836SGerry Liu * Copyright (c) 2010, Intel Corporation. 27a3114836SGerry Liu * All rights reserved. 28a3114836SGerry Liu */ 2920c794b3Sgavinm 3020c794b3Sgavinm #include <sys/types.h> 3120c794b3Sgavinm #include <sys/cpu_module_ms_impl.h> 3220c794b3Sgavinm #include <sys/cpuvar.h> 3320c794b3Sgavinm #include <sys/ksynch.h> 3420c794b3Sgavinm #include <sys/modctl.h> 3520c794b3Sgavinm #include <sys/x86_archext.h> 3620c794b3Sgavinm #include <sys/systm.h> 3720c794b3Sgavinm #include <sys/cmn_err.h> 3820c794b3Sgavinm #include <sys/param.h> 3920c794b3Sgavinm #include <sys/reboot.h> 4020c794b3Sgavinm 4120c794b3Sgavinm /* 4220c794b3Sgavinm * Set to prevent model-specific support from initialising. 4320c794b3Sgavinm */ 4420c794b3Sgavinm int cms_no_model_specific = 0; 4520c794b3Sgavinm 4620c794b3Sgavinm /* 4720c794b3Sgavinm * Subdirectory (relative to the module search path) in which we will 4820c794b3Sgavinm * look for model-specific modules. 4920c794b3Sgavinm */ 5020c794b3Sgavinm #define CPUMOD_MS_SUBDIR "cpu" 5120c794b3Sgavinm 5220c794b3Sgavinm /* 5320c794b3Sgavinm * Cpu model-specific modules have filenames beginning with the following. 5420c794b3Sgavinm */ 5520c794b3Sgavinm #define CPUMOD_MS_PREFIX "cpu_ms" 5620c794b3Sgavinm 5720c794b3Sgavinm #define HDL2CMS(hdl) cms_hdl_getcms(hdl) 5820c794b3Sgavinm 5920c794b3Sgavinm #define CMS_OPS(cms) (cms)->cms_ops 6020c794b3Sgavinm #define CMS_OP_PRESENT(cms, op) ((cms) && CMS_OPS(cms)->op != NULL) 6120c794b3Sgavinm 6220c794b3Sgavinm struct cms_cpuid { 6320c794b3Sgavinm const char *vendor; 6420c794b3Sgavinm uint_t family; 6520c794b3Sgavinm uint_t model; 6620c794b3Sgavinm uint_t stepping; 6720c794b3Sgavinm }; 6820c794b3Sgavinm 6920c794b3Sgavinm #define CMS_MATCH_VENDOR 0 /* Just match on vendor */ 7020c794b3Sgavinm #define CMS_MATCH_FAMILY 1 /* Match down to family */ 7120c794b3Sgavinm #define CMS_MATCH_MODEL 2 /* Match down to model */ 7220c794b3Sgavinm #define CMS_MATCH_STEPPING 3 /* Match down to stepping */ 7320c794b3Sgavinm 7420c794b3Sgavinm /* 7520c794b3Sgavinm * Structure used to keep track of modules we have loaded. 7620c794b3Sgavinm */ 7720c794b3Sgavinm typedef struct cms { 7820c794b3Sgavinm struct cms *cms_next; 7920c794b3Sgavinm struct cms *cms_prev; 8020c794b3Sgavinm const cms_ops_t *cms_ops; 8120c794b3Sgavinm struct modctl *cms_modp; 8220c794b3Sgavinm uint_t cms_refcnt; 8320c794b3Sgavinm } cms_t; 8420c794b3Sgavinm 8520c794b3Sgavinm static cms_t *cms_list; 8620c794b3Sgavinm static kmutex_t cms_load_lock; 8720c794b3Sgavinm 8820c794b3Sgavinm /* 8920c794b3Sgavinm * We stash a cms_t and associated private data via cmi_hdl_setspecific. 9020c794b3Sgavinm */ 9120c794b3Sgavinm struct cms_ctl { 9220c794b3Sgavinm cms_t *cs_cms; 9320c794b3Sgavinm void *cs_cmsdata; 9420c794b3Sgavinm }; 9520c794b3Sgavinm 9620c794b3Sgavinm static cms_t * 9720c794b3Sgavinm cms_hdl_getcms(cmi_hdl_t hdl) 9820c794b3Sgavinm { 9920c794b3Sgavinm struct cms_ctl *cdp = cmi_hdl_getspecific(hdl); 10020c794b3Sgavinm 10120c794b3Sgavinm return (cdp != NULL ? cdp->cs_cms : NULL); 10220c794b3Sgavinm } 10320c794b3Sgavinm 10420c794b3Sgavinm void * 10520c794b3Sgavinm cms_hdl_getcmsdata(cmi_hdl_t hdl) 10620c794b3Sgavinm { 10720c794b3Sgavinm struct cms_ctl *cdp = cmi_hdl_getspecific(hdl); 10820c794b3Sgavinm 10920c794b3Sgavinm return (cdp != NULL ? cdp->cs_cmsdata : NULL); 11020c794b3Sgavinm } 11120c794b3Sgavinm 11220c794b3Sgavinm static void 11320c794b3Sgavinm cms_link(cms_t *cms) 11420c794b3Sgavinm { 11520c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 11620c794b3Sgavinm 11720c794b3Sgavinm cms->cms_prev = NULL; 11820c794b3Sgavinm cms->cms_next = cms_list; 11920c794b3Sgavinm if (cms_list != NULL) 12020c794b3Sgavinm cms_list->cms_prev = cms; 12120c794b3Sgavinm cms_list = cms; 12220c794b3Sgavinm } 12320c794b3Sgavinm 12420c794b3Sgavinm static void 12520c794b3Sgavinm cms_unlink(cms_t *cms) 12620c794b3Sgavinm { 12720c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 12820c794b3Sgavinm ASSERT(cms->cms_refcnt == 0); 12920c794b3Sgavinm 13020c794b3Sgavinm if (cms->cms_prev != NULL) 13120c794b3Sgavinm cms->cms_prev->cms_next = cms->cms_next; 13220c794b3Sgavinm 13320c794b3Sgavinm if (cms->cms_next != NULL) 13420c794b3Sgavinm cms->cms_next->cms_prev = cms->cms_prev; 13520c794b3Sgavinm 13620c794b3Sgavinm if (cms_list == cms) 13720c794b3Sgavinm cms_list = cms->cms_next; 13820c794b3Sgavinm } 13920c794b3Sgavinm 14020c794b3Sgavinm /* 14120c794b3Sgavinm * Hold the module in memory. We call to CPU modules without using the 14220c794b3Sgavinm * stubs mechanism, so these modules must be manually held in memory. 14320c794b3Sgavinm * The mod_ref acts as if another loaded module has a dependency on us. 14420c794b3Sgavinm */ 14520c794b3Sgavinm static void 14620c794b3Sgavinm cms_hold(cms_t *cms) 14720c794b3Sgavinm { 14820c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 14920c794b3Sgavinm 15020c794b3Sgavinm mutex_enter(&mod_lock); 15120c794b3Sgavinm cms->cms_modp->mod_ref++; 15220c794b3Sgavinm mutex_exit(&mod_lock); 15320c794b3Sgavinm cms->cms_refcnt++; 15420c794b3Sgavinm } 15520c794b3Sgavinm 15620c794b3Sgavinm static void 15720c794b3Sgavinm cms_rele(cms_t *cms) 15820c794b3Sgavinm { 15920c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 16020c794b3Sgavinm 16120c794b3Sgavinm mutex_enter(&mod_lock); 16220c794b3Sgavinm cms->cms_modp->mod_ref--; 16320c794b3Sgavinm mutex_exit(&mod_lock); 16420c794b3Sgavinm 16520c794b3Sgavinm if (--cms->cms_refcnt == 0) { 16620c794b3Sgavinm cms_unlink(cms); 16720c794b3Sgavinm kmem_free(cms, sizeof (cms_t)); 16820c794b3Sgavinm } 16920c794b3Sgavinm } 17020c794b3Sgavinm 17120c794b3Sgavinm static cms_ops_t * 17220c794b3Sgavinm cms_getops(modctl_t *modp) 17320c794b3Sgavinm { 17420c794b3Sgavinm cms_ops_t *ops; 17520c794b3Sgavinm 17620c794b3Sgavinm if ((ops = (cms_ops_t *)modlookup_by_modctl(modp, "_cms_ops")) == 17720c794b3Sgavinm NULL) { 17820c794b3Sgavinm cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no _cms_ops " 17920c794b3Sgavinm "found", modp->mod_modname); 18020c794b3Sgavinm return (NULL); 18120c794b3Sgavinm } 18220c794b3Sgavinm 18320c794b3Sgavinm if (ops->cms_init == NULL) { 18420c794b3Sgavinm cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no cms_init " 18520c794b3Sgavinm "entry point", modp->mod_modname); 18620c794b3Sgavinm return (NULL); 18720c794b3Sgavinm } 18820c794b3Sgavinm 18920c794b3Sgavinm return (ops); 19020c794b3Sgavinm } 19120c794b3Sgavinm 19220c794b3Sgavinm static cms_t * 19320c794b3Sgavinm cms_load_modctl(modctl_t *modp) 19420c794b3Sgavinm { 19520c794b3Sgavinm cms_ops_t *ops; 19620c794b3Sgavinm uintptr_t ver; 19720c794b3Sgavinm cms_t *cms; 19820c794b3Sgavinm cms_api_ver_t apiver; 19920c794b3Sgavinm 20020c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 20120c794b3Sgavinm 20220c794b3Sgavinm for (cms = cms_list; cms != NULL; cms = cms->cms_next) { 20320c794b3Sgavinm if (cms->cms_modp == modp) 20420c794b3Sgavinm return (cms); 20520c794b3Sgavinm } 20620c794b3Sgavinm 20720c794b3Sgavinm if ((ver = modlookup_by_modctl(modp, "_cms_api_version")) == NULL) { 20820c794b3Sgavinm cmn_err(CE_WARN, "cpu model-specific module '%s' is invalid: " 20920c794b3Sgavinm "no _cms_api_version", modp->mod_modname); 21020c794b3Sgavinm return (NULL); 21120c794b3Sgavinm } else { 21220c794b3Sgavinm apiver = *((cms_api_ver_t *)ver); 21320c794b3Sgavinm if (!CMS_API_VERSION_CHKMAGIC(apiver)) { 21420c794b3Sgavinm cmn_err(CE_WARN, "cpu model-specific module '%s' is " 21520c794b3Sgavinm "invalid: _cms_api_version 0x%x has bad magic", 21620c794b3Sgavinm modp->mod_modname, apiver); 21720c794b3Sgavinm return (NULL); 21820c794b3Sgavinm } 21920c794b3Sgavinm } 22020c794b3Sgavinm 22120c794b3Sgavinm if (apiver != CMS_API_VERSION) { 22220c794b3Sgavinm cmn_err(CE_WARN, "cpu model-specific module '%s' has API " 22320c794b3Sgavinm "version %d, kernel requires API version %d", 22420c794b3Sgavinm modp->mod_modname, CMS_API_VERSION_TOPRINT(apiver), 22520c794b3Sgavinm CMS_API_VERSION_TOPRINT(CMS_API_VERSION)); 22620c794b3Sgavinm return (NULL); 22720c794b3Sgavinm } 22820c794b3Sgavinm 22920c794b3Sgavinm if ((ops = cms_getops(modp)) == NULL) 23020c794b3Sgavinm return (NULL); 23120c794b3Sgavinm 23220c794b3Sgavinm cms = kmem_zalloc(sizeof (cms_t), KM_SLEEP); 23320c794b3Sgavinm cms->cms_ops = ops; 23420c794b3Sgavinm cms->cms_modp = modp; 23520c794b3Sgavinm 23620c794b3Sgavinm cms_link(cms); 23720c794b3Sgavinm 23820c794b3Sgavinm return (cms); 23920c794b3Sgavinm } 24020c794b3Sgavinm 24120c794b3Sgavinm static int 24220c794b3Sgavinm cms_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match) 24320c794b3Sgavinm { 24420c794b3Sgavinm if (match >= CMS_MATCH_VENDOR && 24520c794b3Sgavinm cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2)) 24620c794b3Sgavinm return (0); 24720c794b3Sgavinm 24820c794b3Sgavinm if (match >= CMS_MATCH_FAMILY && 24920c794b3Sgavinm cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2)) 25020c794b3Sgavinm return (0); 25120c794b3Sgavinm 25220c794b3Sgavinm if (match >= CMS_MATCH_MODEL && 25320c794b3Sgavinm cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2)) 25420c794b3Sgavinm return (0); 25520c794b3Sgavinm 25620c794b3Sgavinm if (match >= CMS_MATCH_STEPPING && 25720c794b3Sgavinm cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2)) 25820c794b3Sgavinm return (0); 25920c794b3Sgavinm 26020c794b3Sgavinm return (1); 26120c794b3Sgavinm } 26220c794b3Sgavinm 26320c794b3Sgavinm static int 26420c794b3Sgavinm cms_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3) 26520c794b3Sgavinm { 26620c794b3Sgavinm cmi_hdl_t thdl = (cmi_hdl_t)arg1; 26720c794b3Sgavinm int match = *((int *)arg2); 26820c794b3Sgavinm cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3; 26920c794b3Sgavinm 27020c794b3Sgavinm if (cms_cpu_match(thdl, whdl, match)) { 27120c794b3Sgavinm cmi_hdl_hold(whdl); /* short-term hold */ 27220c794b3Sgavinm *rsltp = whdl; 27320c794b3Sgavinm return (CMI_HDL_WALK_DONE); 27420c794b3Sgavinm } else { 27520c794b3Sgavinm return (CMI_HDL_WALK_NEXT); 27620c794b3Sgavinm } 27720c794b3Sgavinm } 27820c794b3Sgavinm 27920c794b3Sgavinm /* 28020c794b3Sgavinm * Look to see if we've already got a module loaded for a CPU just 28120c794b3Sgavinm * like this one. If we do, then we'll re-use it. 28220c794b3Sgavinm */ 28320c794b3Sgavinm static cms_t * 28420c794b3Sgavinm cms_search_list(cmi_hdl_t hdl, int match) 28520c794b3Sgavinm { 28620c794b3Sgavinm cmi_hdl_t dhdl = NULL; 28720c794b3Sgavinm cms_t *cms = NULL; 28820c794b3Sgavinm 28920c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 29020c794b3Sgavinm 29120c794b3Sgavinm cmi_hdl_walk(cms_search_list_cb, (void *)hdl, (void *)&match, &dhdl); 29220c794b3Sgavinm if (dhdl) { 29320c794b3Sgavinm cms = HDL2CMS(dhdl); 29420c794b3Sgavinm cmi_hdl_rele(dhdl); /* held in cms_search_list_cb */ 29520c794b3Sgavinm } 29620c794b3Sgavinm 29720c794b3Sgavinm return (cms); 29820c794b3Sgavinm } 29920c794b3Sgavinm 30020c794b3Sgavinm /* 30120c794b3Sgavinm * Try to find or load a module that offers model-specific support for 30220c794b3Sgavinm * this vendor/family/model/stepping combination. When attempting to load 30320c794b3Sgavinm * a module we look in CPUMOD_MS_SUBDIR first for a match on 30420c794b3Sgavinm * vendor/family/model/stepping, then on vendor/family/model (ignoring 30520c794b3Sgavinm * stepping), then on vendor/family (ignoring model and stepping), then 30620c794b3Sgavinm * on vendor alone. 30720c794b3Sgavinm */ 30820c794b3Sgavinm static cms_t * 30920c794b3Sgavinm cms_load_module(cmi_hdl_t hdl, int match, int *chosenp) 31020c794b3Sgavinm { 31120c794b3Sgavinm modctl_t *modp; 31220c794b3Sgavinm cms_t *cms; 31320c794b3Sgavinm int modid; 31420c794b3Sgavinm uint_t s[3]; 31520c794b3Sgavinm 31620c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 31720c794b3Sgavinm ASSERT(match == CMS_MATCH_STEPPING || match == CMS_MATCH_MODEL || 31820c794b3Sgavinm match == CMS_MATCH_FAMILY || match == CMS_MATCH_VENDOR); 31920c794b3Sgavinm 32020c794b3Sgavinm s[0] = cmi_hdl_family(hdl); 32120c794b3Sgavinm s[1] = cmi_hdl_model(hdl); 32220c794b3Sgavinm s[2] = cmi_hdl_stepping(hdl); 32320c794b3Sgavinm 32420c794b3Sgavinm /* 32520c794b3Sgavinm * Have we already loaded a module for a cpu with the same 32620c794b3Sgavinm * vendor/family/model/stepping? 32720c794b3Sgavinm */ 32820c794b3Sgavinm if ((cms = cms_search_list(hdl, match)) != NULL) { 32920c794b3Sgavinm cms_hold(cms); 33020c794b3Sgavinm return (cms); 33120c794b3Sgavinm } 33220c794b3Sgavinm 33320c794b3Sgavinm modid = modload_qualified(CPUMOD_MS_SUBDIR, CPUMOD_MS_PREFIX, 33420c794b3Sgavinm cmi_hdl_vendorstr(hdl), ".", s, match, chosenp); 33520c794b3Sgavinm 33620c794b3Sgavinm if (modid == -1) 33720c794b3Sgavinm return (NULL); 33820c794b3Sgavinm 33920c794b3Sgavinm modp = mod_hold_by_id(modid); 34020c794b3Sgavinm cms = cms_load_modctl(modp); 34120c794b3Sgavinm if (cms) 34220c794b3Sgavinm cms_hold(cms); 34320c794b3Sgavinm mod_release_mod(modp); 34420c794b3Sgavinm 34520c794b3Sgavinm return (cms); 34620c794b3Sgavinm } 34720c794b3Sgavinm 34820c794b3Sgavinm static cms_t * 34920c794b3Sgavinm cms_load_specific(cmi_hdl_t hdl, void **datap) 35020c794b3Sgavinm { 35120c794b3Sgavinm cms_t *cms; 35220c794b3Sgavinm int err; 35320c794b3Sgavinm int i; 35420c794b3Sgavinm 35520c794b3Sgavinm ASSERT(MUTEX_HELD(&cms_load_lock)); 35620c794b3Sgavinm 35720c794b3Sgavinm for (i = CMS_MATCH_STEPPING; i >= CMS_MATCH_VENDOR; i--) { 35820c794b3Sgavinm int suffixlevel; 35920c794b3Sgavinm 36020c794b3Sgavinm if ((cms = cms_load_module(hdl, i, &suffixlevel)) == NULL) 36120c794b3Sgavinm return (NULL); 36220c794b3Sgavinm 36320c794b3Sgavinm /* 36420c794b3Sgavinm * A module has loaded and has a _cms_ops structure, and the 36520c794b3Sgavinm * module has been held for this instance. Call the cms_init 36620c794b3Sgavinm * entry point - we expect success (0) or ENOTSUP. 36720c794b3Sgavinm */ 36820c794b3Sgavinm if ((err = cms->cms_ops->cms_init(hdl, datap)) == 0) { 36920c794b3Sgavinm if (boothowto & RB_VERBOSE) { 37020c794b3Sgavinm printf("initialized model-specific " 37120c794b3Sgavinm "module '%s' on chip %d core %d " 37220c794b3Sgavinm "strand %d\n", 37320c794b3Sgavinm cms->cms_modp->mod_modname, 37420c794b3Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 37520c794b3Sgavinm cmi_hdl_strandid(hdl)); 37620c794b3Sgavinm } 37720c794b3Sgavinm return (cms); 37820c794b3Sgavinm } else if (err != ENOTSUP) { 37920c794b3Sgavinm cmn_err(CE_WARN, "failed to init model-specific " 38020c794b3Sgavinm "module '%s' on chip %d core %d strand %d: err=%d", 38120c794b3Sgavinm cms->cms_modp->mod_modname, 38220c794b3Sgavinm cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl), 38320c794b3Sgavinm cmi_hdl_strandid(hdl), err); 38420c794b3Sgavinm } 38520c794b3Sgavinm 38620c794b3Sgavinm /* 38720c794b3Sgavinm * The module failed or declined to init, so release 38820c794b3Sgavinm * it and potentially change i to be equal to he number 38920c794b3Sgavinm * of suffices actually used in the last module path. 39020c794b3Sgavinm */ 39120c794b3Sgavinm cms_rele(cms); 39220c794b3Sgavinm i = suffixlevel; 39320c794b3Sgavinm } 39420c794b3Sgavinm 39520c794b3Sgavinm return (NULL); 39620c794b3Sgavinm } 39720c794b3Sgavinm 39820c794b3Sgavinm void 39920c794b3Sgavinm cms_init(cmi_hdl_t hdl) 40020c794b3Sgavinm { 40120c794b3Sgavinm cms_t *cms; 40220c794b3Sgavinm void *data; 40320c794b3Sgavinm 40420c794b3Sgavinm if (cms_no_model_specific != 0) 40520c794b3Sgavinm return; 40620c794b3Sgavinm 40720c794b3Sgavinm mutex_enter(&cms_load_lock); 40820c794b3Sgavinm 40920c794b3Sgavinm if ((cms = cms_load_specific(hdl, &data)) != NULL) { 41020c794b3Sgavinm struct cms_ctl *cdp; 41120c794b3Sgavinm 41220c794b3Sgavinm ASSERT(cmi_hdl_getspecific(hdl) == NULL); 41320c794b3Sgavinm 41420c794b3Sgavinm cdp = kmem_alloc(sizeof (*cdp), KM_SLEEP); 41520c794b3Sgavinm cdp->cs_cms = cms; 41620c794b3Sgavinm cdp->cs_cmsdata = data; 41720c794b3Sgavinm cmi_hdl_setspecific(hdl, cdp); 41820c794b3Sgavinm } 41920c794b3Sgavinm 42020c794b3Sgavinm mutex_exit(&cms_load_lock); 42120c794b3Sgavinm } 42220c794b3Sgavinm 42320c794b3Sgavinm void 42420c794b3Sgavinm cms_fini(cmi_hdl_t hdl) 42520c794b3Sgavinm { 42620c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 427a3114836SGerry Liu struct cms_ctl *cdp; 42820c794b3Sgavinm 42920c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_fini)) 43020c794b3Sgavinm CMS_OPS(cms)->cms_fini(hdl); 431a3114836SGerry Liu 432a3114836SGerry Liu mutex_enter(&cms_load_lock); 433a3114836SGerry Liu cdp = (struct cms_ctl *)cmi_hdl_getspecific(hdl); 434a3114836SGerry Liu if (cdp != NULL) { 435a3114836SGerry Liu if (cdp->cs_cms != NULL) 436a3114836SGerry Liu cms_rele(cdp->cs_cms); 437a3114836SGerry Liu kmem_free(cdp, sizeof (*cdp)); 438a3114836SGerry Liu } 439a3114836SGerry Liu mutex_exit(&cms_load_lock); 44020c794b3Sgavinm } 44120c794b3Sgavinm 44220c794b3Sgavinm boolean_t 44320c794b3Sgavinm cms_present(cmi_hdl_t hdl) 44420c794b3Sgavinm { 44520c794b3Sgavinm return (HDL2CMS(hdl) != NULL ? B_TRUE : B_FALSE); 44620c794b3Sgavinm } 44720c794b3Sgavinm 44820c794b3Sgavinm void 44920c794b3Sgavinm cms_post_startup(cmi_hdl_t hdl) 45020c794b3Sgavinm { 45120c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 45220c794b3Sgavinm 45320c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_post_startup)) 45420c794b3Sgavinm CMS_OPS(cms)->cms_post_startup(hdl); 45520c794b3Sgavinm } 45620c794b3Sgavinm 45720c794b3Sgavinm void 45820c794b3Sgavinm cms_post_mpstartup(cmi_hdl_t hdl) 45920c794b3Sgavinm { 46020c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 46120c794b3Sgavinm 46220c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_post_mpstartup)) 46320c794b3Sgavinm CMS_OPS(cms)->cms_post_mpstartup(hdl); 46420c794b3Sgavinm } 46520c794b3Sgavinm 46620c794b3Sgavinm size_t 46720c794b3Sgavinm cms_logout_size(cmi_hdl_t hdl) 46820c794b3Sgavinm { 46920c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 47020c794b3Sgavinm 47120c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_logout_size)) 47220c794b3Sgavinm return (0); 47320c794b3Sgavinm 47420c794b3Sgavinm return (CMS_OPS(cms)->cms_logout_size(hdl)); 47520c794b3Sgavinm } 47620c794b3Sgavinm 47720c794b3Sgavinm uint64_t 47820c794b3Sgavinm cms_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t def) 47920c794b3Sgavinm { 48020c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 48120c794b3Sgavinm 48220c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_mcgctl_val)) 48320c794b3Sgavinm return (def); 48420c794b3Sgavinm 48520c794b3Sgavinm return (CMS_OPS(cms)->cms_mcgctl_val(hdl, nbanks, def)); 48620c794b3Sgavinm } 48720c794b3Sgavinm 48820c794b3Sgavinm boolean_t 48920c794b3Sgavinm cms_bankctl_skipinit(cmi_hdl_t hdl, int banknum) 49020c794b3Sgavinm { 49120c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 49220c794b3Sgavinm 49320c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankctl_skipinit)) 49420c794b3Sgavinm return (B_FALSE); 49520c794b3Sgavinm 49620c794b3Sgavinm return (CMS_OPS(cms)->cms_bankctl_skipinit(hdl, banknum)); 49720c794b3Sgavinm } 49820c794b3Sgavinm 49920c794b3Sgavinm uint64_t 50020c794b3Sgavinm cms_bankctl_val(cmi_hdl_t hdl, int banknum, uint64_t def) 50120c794b3Sgavinm { 50220c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 50320c794b3Sgavinm 50420c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankctl_val)) 50520c794b3Sgavinm return (def); 50620c794b3Sgavinm 50720c794b3Sgavinm return (CMS_OPS(cms)->cms_bankctl_val(hdl, banknum, def)); 50820c794b3Sgavinm } 50920c794b3Sgavinm 51020c794b3Sgavinm boolean_t 51120c794b3Sgavinm cms_bankstatus_skipinit(cmi_hdl_t hdl, int banknum) 51220c794b3Sgavinm { 51320c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 51420c794b3Sgavinm 51520c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankstatus_skipinit)) 51620c794b3Sgavinm return (B_FALSE); 51720c794b3Sgavinm 51820c794b3Sgavinm return (CMS_OPS(cms)->cms_bankstatus_skipinit(hdl, banknum)); 51920c794b3Sgavinm } 52020c794b3Sgavinm 52120c794b3Sgavinm uint64_t 52220c794b3Sgavinm cms_bankstatus_val(cmi_hdl_t hdl, int banknum, uint64_t def) 52320c794b3Sgavinm { 52420c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 52520c794b3Sgavinm 52620c794b3Sgavinm if (!CMS_OP_PRESENT(cms, cms_bankstatus_val)) 52720c794b3Sgavinm return (def); 52820c794b3Sgavinm 52920c794b3Sgavinm return (CMS_OPS(cms)->cms_bankstatus_val(hdl, banknum, def)); 53020c794b3Sgavinm } 53120c794b3Sgavinm 53220c794b3Sgavinm void 53320c794b3Sgavinm cms_mca_init(cmi_hdl_t hdl, int nbanks) 53420c794b3Sgavinm { 53520c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 53620c794b3Sgavinm 53720c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_mca_init)) 53820c794b3Sgavinm CMS_OPS(cms)->cms_mca_init(hdl, nbanks); 53920c794b3Sgavinm } 54020c794b3Sgavinm 54120c794b3Sgavinm uint64_t 54220c794b3Sgavinm cms_poll_ownermask(cmi_hdl_t hdl, hrtime_t poll_interval) 54320c794b3Sgavinm { 54420c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 54520c794b3Sgavinm 54620c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_poll_ownermask)) 54720c794b3Sgavinm return (CMS_OPS(cms)->cms_poll_ownermask(hdl, poll_interval)); 54820c794b3Sgavinm else 54920c794b3Sgavinm return (-1ULL); /* poll all banks by default */ 55020c794b3Sgavinm } 55120c794b3Sgavinm 55220c794b3Sgavinm void 55320c794b3Sgavinm cms_bank_logout(cmi_hdl_t hdl, int banknum, uint64_t status, uint64_t addr, 55420c794b3Sgavinm uint64_t misc, void *mslogout) 55520c794b3Sgavinm { 55620c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 55720c794b3Sgavinm 55820c794b3Sgavinm if (mslogout != NULL && CMS_OP_PRESENT(cms, cms_bank_logout)) 55920c794b3Sgavinm CMS_OPS(cms)->cms_bank_logout(hdl, banknum, status, addr, 56020c794b3Sgavinm misc, mslogout); 56120c794b3Sgavinm } 56220c794b3Sgavinm 56320c794b3Sgavinm cms_errno_t 56420c794b3Sgavinm cms_msrinject(cmi_hdl_t hdl, uint_t msr, uint64_t val) 56520c794b3Sgavinm { 56620c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 56720c794b3Sgavinm 56820c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_msrinject)) 56920c794b3Sgavinm return (CMS_OPS(cms)->cms_msrinject(hdl, msr, val)); 57020c794b3Sgavinm else 57120c794b3Sgavinm return (CMSERR_NOTSUP); 57220c794b3Sgavinm } 57320c794b3Sgavinm 57420c794b3Sgavinm uint32_t 57520c794b3Sgavinm cms_error_action(cmi_hdl_t hdl, int ismc, int banknum, uint64_t status, 57620c794b3Sgavinm uint64_t addr, uint64_t misc, void *mslogout) 57720c794b3Sgavinm { 57820c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 57920c794b3Sgavinm 58020c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_error_action)) 58120c794b3Sgavinm return (CMS_OPS(cms)->cms_error_action(hdl, ismc, banknum, 58220c794b3Sgavinm status, addr, misc, mslogout)); 58320c794b3Sgavinm else 58420c794b3Sgavinm return (0); 58520c794b3Sgavinm } 58620c794b3Sgavinm 58720c794b3Sgavinm cms_cookie_t 588*c84b7bbeSAdrian Frost cms_disp_match(cmi_hdl_t hdl, int ismc, int banknum, uint64_t status, 589*c84b7bbeSAdrian Frost uint64_t addr, uint64_t misc, void *mslogout) 59020c794b3Sgavinm { 59120c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 59220c794b3Sgavinm 59320c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_disp_match)) 594*c84b7bbeSAdrian Frost return (CMS_OPS(cms)->cms_disp_match(hdl, ismc, banknum, 59520c794b3Sgavinm status, addr, misc, mslogout)); 59620c794b3Sgavinm else 59720c794b3Sgavinm return (NULL); 59820c794b3Sgavinm 59920c794b3Sgavinm } 60020c794b3Sgavinm 60120c794b3Sgavinm void 60220c794b3Sgavinm cms_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie, const char **cpuclsp, 60320c794b3Sgavinm const char **leafclsp) 60420c794b3Sgavinm { 60520c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 60620c794b3Sgavinm 60720c794b3Sgavinm if (cpuclsp == NULL || leafclsp == NULL) 60820c794b3Sgavinm return; 60920c794b3Sgavinm 61020c794b3Sgavinm *cpuclsp = *leafclsp = NULL; 61120c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_class)) { 61220c794b3Sgavinm CMS_OPS(cms)->cms_ereport_class(hdl, mscookie, cpuclsp, 61320c794b3Sgavinm leafclsp); 61420c794b3Sgavinm } 61520c794b3Sgavinm } 61620c794b3Sgavinm 61720c794b3Sgavinm nvlist_t * 618491f61a1SYanmin Sun cms_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie, 619491f61a1SYanmin Sun nv_alloc_t *nva) 62020c794b3Sgavinm { 62120c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 62220c794b3Sgavinm 62320c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_detector)) 624491f61a1SYanmin Sun return (CMS_OPS(cms)->cms_ereport_detector(hdl, bankno, 625491f61a1SYanmin Sun mscookie, nva)); 62620c794b3Sgavinm else 62720c794b3Sgavinm return (NULL); 62820c794b3Sgavinm 62920c794b3Sgavinm } 63020c794b3Sgavinm 63120c794b3Sgavinm boolean_t 63220c794b3Sgavinm cms_ereport_includestack(cmi_hdl_t hdl, cms_cookie_t mscookie) 63320c794b3Sgavinm { 63420c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 63520c794b3Sgavinm 63620c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_includestack)) { 63720c794b3Sgavinm return (CMS_OPS(cms)->cms_ereport_includestack(hdl, mscookie)); 63820c794b3Sgavinm } else { 63920c794b3Sgavinm return (B_FALSE); 64020c794b3Sgavinm } 64120c794b3Sgavinm } 64220c794b3Sgavinm 64320c794b3Sgavinm void 64420c794b3Sgavinm cms_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *nvl, nv_alloc_t *nva, 64520c794b3Sgavinm int banknum, uint64_t status, uint64_t addr, uint64_t misc, void *mslogout, 64620c794b3Sgavinm cms_cookie_t mscookie) 64720c794b3Sgavinm { 64820c794b3Sgavinm cms_t *cms = HDL2CMS(hdl); 64920c794b3Sgavinm 65020c794b3Sgavinm if (CMS_OP_PRESENT(cms, cms_ereport_add_logout)) 65120c794b3Sgavinm CMS_OPS(cms)->cms_ereport_add_logout(hdl, nvl, nva, banknum, 65220c794b3Sgavinm status, addr, misc, mslogout, mscookie); 65320c794b3Sgavinm 65420c794b3Sgavinm } 655