xref: /onnv-gate/usr/src/uts/i86pc/os/cms.c (revision 12437:76e2c024699d)
15254Sgavinm /*
25254Sgavinm  * CDDL HEADER START
35254Sgavinm  *
45254Sgavinm  * The contents of this file are subject to the terms of the
55254Sgavinm  * Common Development and Distribution License (the "License").
65254Sgavinm  * You may not use this file except in compliance with the License.
75254Sgavinm  *
85254Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95254Sgavinm  * or http://www.opensolaris.org/os/licensing.
105254Sgavinm  * See the License for the specific language governing permissions
115254Sgavinm  * and limitations under the License.
125254Sgavinm  *
135254Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
145254Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155254Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
165254Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
175254Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
185254Sgavinm  *
195254Sgavinm  * CDDL HEADER END
205254Sgavinm  */
215254Sgavinm 
225254Sgavinm /*
23*12437SAdrian.Frost@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245254Sgavinm  */
2512004Sjiang.liu@intel.com /*
2612004Sjiang.liu@intel.com  * Copyright (c) 2010, Intel Corporation.
2712004Sjiang.liu@intel.com  * All rights reserved.
2812004Sjiang.liu@intel.com  */
295254Sgavinm 
305254Sgavinm #include <sys/types.h>
315254Sgavinm #include <sys/cpu_module_ms_impl.h>
325254Sgavinm #include <sys/cpuvar.h>
335254Sgavinm #include <sys/ksynch.h>
345254Sgavinm #include <sys/modctl.h>
355254Sgavinm #include <sys/x86_archext.h>
365254Sgavinm #include <sys/systm.h>
375254Sgavinm #include <sys/cmn_err.h>
385254Sgavinm #include <sys/param.h>
395254Sgavinm #include <sys/reboot.h>
405254Sgavinm 
415254Sgavinm /*
425254Sgavinm  * Set to prevent model-specific support from initialising.
435254Sgavinm  */
445254Sgavinm int cms_no_model_specific = 0;
455254Sgavinm 
465254Sgavinm /*
475254Sgavinm  * Subdirectory (relative to the module search path) in which we will
485254Sgavinm  * look for model-specific modules.
495254Sgavinm  */
505254Sgavinm #define	CPUMOD_MS_SUBDIR	"cpu"
515254Sgavinm 
525254Sgavinm /*
535254Sgavinm  * Cpu model-specific modules have filenames beginning with the following.
545254Sgavinm  */
555254Sgavinm #define	CPUMOD_MS_PREFIX	"cpu_ms"
565254Sgavinm 
575254Sgavinm #define	HDL2CMS(hdl)		cms_hdl_getcms(hdl)
585254Sgavinm 
595254Sgavinm #define	CMS_OPS(cms)		(cms)->cms_ops
605254Sgavinm #define	CMS_OP_PRESENT(cms, op)	((cms) && CMS_OPS(cms)->op != NULL)
615254Sgavinm 
625254Sgavinm struct cms_cpuid {
635254Sgavinm 	const char *vendor;
645254Sgavinm 	uint_t family;
655254Sgavinm 	uint_t model;
665254Sgavinm 	uint_t stepping;
675254Sgavinm };
685254Sgavinm 
695254Sgavinm #define	CMS_MATCH_VENDOR	0	/* Just match on vendor */
705254Sgavinm #define	CMS_MATCH_FAMILY	1	/* Match down to family */
715254Sgavinm #define	CMS_MATCH_MODEL		2	/* Match down to model */
725254Sgavinm #define	CMS_MATCH_STEPPING	3	/* Match down to stepping */
735254Sgavinm 
745254Sgavinm /*
755254Sgavinm  * Structure used to keep track of modules we have loaded.
765254Sgavinm  */
775254Sgavinm typedef struct cms {
785254Sgavinm 	struct cms *cms_next;
795254Sgavinm 	struct cms *cms_prev;
805254Sgavinm 	const cms_ops_t *cms_ops;
815254Sgavinm 	struct modctl *cms_modp;
825254Sgavinm 	uint_t cms_refcnt;
835254Sgavinm } cms_t;
845254Sgavinm 
855254Sgavinm static cms_t *cms_list;
865254Sgavinm static kmutex_t cms_load_lock;
875254Sgavinm 
885254Sgavinm /*
895254Sgavinm  * We stash a cms_t and associated private data via cmi_hdl_setspecific.
905254Sgavinm  */
915254Sgavinm struct cms_ctl {
925254Sgavinm 	cms_t *cs_cms;
935254Sgavinm 	void *cs_cmsdata;
945254Sgavinm };
955254Sgavinm 
965254Sgavinm static cms_t *
cms_hdl_getcms(cmi_hdl_t hdl)975254Sgavinm cms_hdl_getcms(cmi_hdl_t hdl)
985254Sgavinm {
995254Sgavinm 	struct cms_ctl *cdp = cmi_hdl_getspecific(hdl);
1005254Sgavinm 
1015254Sgavinm 	return (cdp != NULL ? cdp->cs_cms : NULL);
1025254Sgavinm }
1035254Sgavinm 
1045254Sgavinm void *
cms_hdl_getcmsdata(cmi_hdl_t hdl)1055254Sgavinm cms_hdl_getcmsdata(cmi_hdl_t hdl)
1065254Sgavinm {
1075254Sgavinm 	struct cms_ctl *cdp = cmi_hdl_getspecific(hdl);
1085254Sgavinm 
1095254Sgavinm 	return (cdp != NULL ? cdp->cs_cmsdata : NULL);
1105254Sgavinm }
1115254Sgavinm 
1125254Sgavinm static void
cms_link(cms_t * cms)1135254Sgavinm cms_link(cms_t *cms)
1145254Sgavinm {
1155254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
1165254Sgavinm 
1175254Sgavinm 	cms->cms_prev = NULL;
1185254Sgavinm 	cms->cms_next = cms_list;
1195254Sgavinm 	if (cms_list != NULL)
1205254Sgavinm 		cms_list->cms_prev = cms;
1215254Sgavinm 	cms_list = cms;
1225254Sgavinm }
1235254Sgavinm 
1245254Sgavinm static void
cms_unlink(cms_t * cms)1255254Sgavinm cms_unlink(cms_t *cms)
1265254Sgavinm {
1275254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
1285254Sgavinm 	ASSERT(cms->cms_refcnt == 0);
1295254Sgavinm 
1305254Sgavinm 	if (cms->cms_prev != NULL)
1315254Sgavinm 		cms->cms_prev->cms_next = cms->cms_next;
1325254Sgavinm 
1335254Sgavinm 	if (cms->cms_next != NULL)
1345254Sgavinm 		cms->cms_next->cms_prev = cms->cms_prev;
1355254Sgavinm 
1365254Sgavinm 	if (cms_list == cms)
1375254Sgavinm 		cms_list = cms->cms_next;
1385254Sgavinm }
1395254Sgavinm 
1405254Sgavinm /*
1415254Sgavinm  * Hold the module in memory.  We call to CPU modules without using the
1425254Sgavinm  * stubs mechanism, so these modules must be manually held in memory.
1435254Sgavinm  * The mod_ref acts as if another loaded module has a dependency on us.
1445254Sgavinm  */
1455254Sgavinm static void
cms_hold(cms_t * cms)1465254Sgavinm cms_hold(cms_t *cms)
1475254Sgavinm {
1485254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
1495254Sgavinm 
1505254Sgavinm 	mutex_enter(&mod_lock);
1515254Sgavinm 	cms->cms_modp->mod_ref++;
1525254Sgavinm 	mutex_exit(&mod_lock);
1535254Sgavinm 	cms->cms_refcnt++;
1545254Sgavinm }
1555254Sgavinm 
1565254Sgavinm static void
cms_rele(cms_t * cms)1575254Sgavinm cms_rele(cms_t *cms)
1585254Sgavinm {
1595254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
1605254Sgavinm 
1615254Sgavinm 	mutex_enter(&mod_lock);
1625254Sgavinm 	cms->cms_modp->mod_ref--;
1635254Sgavinm 	mutex_exit(&mod_lock);
1645254Sgavinm 
1655254Sgavinm 	if (--cms->cms_refcnt == 0) {
1665254Sgavinm 		cms_unlink(cms);
1675254Sgavinm 		kmem_free(cms, sizeof (cms_t));
1685254Sgavinm 	}
1695254Sgavinm }
1705254Sgavinm 
1715254Sgavinm static cms_ops_t *
cms_getops(modctl_t * modp)1725254Sgavinm cms_getops(modctl_t *modp)
1735254Sgavinm {
1745254Sgavinm 	cms_ops_t *ops;
1755254Sgavinm 
1765254Sgavinm 	if ((ops = (cms_ops_t *)modlookup_by_modctl(modp, "_cms_ops")) ==
1775254Sgavinm 	    NULL) {
1785254Sgavinm 		cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no _cms_ops "
1795254Sgavinm 		    "found", modp->mod_modname);
1805254Sgavinm 		return (NULL);
1815254Sgavinm 	}
1825254Sgavinm 
1835254Sgavinm 	if (ops->cms_init == NULL) {
1845254Sgavinm 		cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no cms_init "
1855254Sgavinm 		    "entry point", modp->mod_modname);
1865254Sgavinm 		return (NULL);
1875254Sgavinm 	}
1885254Sgavinm 
1895254Sgavinm 	return (ops);
1905254Sgavinm }
1915254Sgavinm 
1925254Sgavinm static cms_t *
cms_load_modctl(modctl_t * modp)1935254Sgavinm cms_load_modctl(modctl_t *modp)
1945254Sgavinm {
1955254Sgavinm 	cms_ops_t *ops;
1965254Sgavinm 	uintptr_t ver;
1975254Sgavinm 	cms_t *cms;
1985254Sgavinm 	cms_api_ver_t apiver;
1995254Sgavinm 
2005254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
2015254Sgavinm 
2025254Sgavinm 	for (cms = cms_list; cms != NULL; cms = cms->cms_next) {
2035254Sgavinm 		if (cms->cms_modp == modp)
2045254Sgavinm 			return (cms);
2055254Sgavinm 	}
2065254Sgavinm 
2075254Sgavinm 	if ((ver = modlookup_by_modctl(modp, "_cms_api_version")) == NULL) {
2085254Sgavinm 		cmn_err(CE_WARN, "cpu model-specific module '%s' is invalid:  "
2095254Sgavinm 		    "no _cms_api_version", modp->mod_modname);
2105254Sgavinm 		return (NULL);
2115254Sgavinm 	} else {
2125254Sgavinm 		apiver = *((cms_api_ver_t *)ver);
2135254Sgavinm 		if (!CMS_API_VERSION_CHKMAGIC(apiver)) {
2145254Sgavinm 			cmn_err(CE_WARN, "cpu model-specific module '%s' is "
2155254Sgavinm 			    "invalid: _cms_api_version 0x%x has bad magic",
2165254Sgavinm 			    modp->mod_modname, apiver);
2175254Sgavinm 			return (NULL);
2185254Sgavinm 		}
2195254Sgavinm 	}
2205254Sgavinm 
2215254Sgavinm 	if (apiver != CMS_API_VERSION) {
2225254Sgavinm 		cmn_err(CE_WARN, "cpu model-specific module '%s' has API "
2235254Sgavinm 		    "version %d, kernel requires API version %d",
2245254Sgavinm 		    modp->mod_modname, CMS_API_VERSION_TOPRINT(apiver),
2255254Sgavinm 		    CMS_API_VERSION_TOPRINT(CMS_API_VERSION));
2265254Sgavinm 	return (NULL);
2275254Sgavinm 	}
2285254Sgavinm 
2295254Sgavinm 	if ((ops = cms_getops(modp)) == NULL)
2305254Sgavinm 		return (NULL);
2315254Sgavinm 
2325254Sgavinm 	cms = kmem_zalloc(sizeof (cms_t), KM_SLEEP);
2335254Sgavinm 	cms->cms_ops = ops;
2345254Sgavinm 	cms->cms_modp = modp;
2355254Sgavinm 
2365254Sgavinm 	cms_link(cms);
2375254Sgavinm 
2385254Sgavinm 	return (cms);
2395254Sgavinm }
2405254Sgavinm 
2415254Sgavinm static int
cms_cpu_match(cmi_hdl_t hdl1,cmi_hdl_t hdl2,int match)2425254Sgavinm cms_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match)
2435254Sgavinm {
2445254Sgavinm 	if (match >= CMS_MATCH_VENDOR &&
2455254Sgavinm 	    cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2))
2465254Sgavinm 		return (0);
2475254Sgavinm 
2485254Sgavinm 	if (match >= CMS_MATCH_FAMILY &&
2495254Sgavinm 	    cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
2505254Sgavinm 		return (0);
2515254Sgavinm 
2525254Sgavinm 	if (match >= CMS_MATCH_MODEL &&
2535254Sgavinm 	    cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
2545254Sgavinm 		return (0);
2555254Sgavinm 
2565254Sgavinm 	if (match >= CMS_MATCH_STEPPING &&
2575254Sgavinm 	    cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
2585254Sgavinm 		return (0);
2595254Sgavinm 
2605254Sgavinm 	return (1);
2615254Sgavinm }
2625254Sgavinm 
2635254Sgavinm static int
cms_search_list_cb(cmi_hdl_t whdl,void * arg1,void * arg2,void * arg3)2645254Sgavinm cms_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3)
2655254Sgavinm {
2665254Sgavinm 	cmi_hdl_t thdl = (cmi_hdl_t)arg1;
2675254Sgavinm 	int match = *((int *)arg2);
2685254Sgavinm 	cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3;
2695254Sgavinm 
2705254Sgavinm 	if (cms_cpu_match(thdl, whdl, match)) {
2715254Sgavinm 		cmi_hdl_hold(whdl);	/* short-term hold */
2725254Sgavinm 		*rsltp = whdl;
2735254Sgavinm 		return (CMI_HDL_WALK_DONE);
2745254Sgavinm 	} else {
2755254Sgavinm 		return (CMI_HDL_WALK_NEXT);
2765254Sgavinm 	}
2775254Sgavinm }
2785254Sgavinm 
2795254Sgavinm /*
2805254Sgavinm  * Look to see if we've already got a module loaded for a CPU just
2815254Sgavinm  * like this one.  If we do, then we'll re-use it.
2825254Sgavinm  */
2835254Sgavinm static cms_t *
cms_search_list(cmi_hdl_t hdl,int match)2845254Sgavinm cms_search_list(cmi_hdl_t hdl, int match)
2855254Sgavinm {
2865254Sgavinm 	cmi_hdl_t dhdl = NULL;
2875254Sgavinm 	cms_t *cms = NULL;
2885254Sgavinm 
2895254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
2905254Sgavinm 
2915254Sgavinm 	cmi_hdl_walk(cms_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
2925254Sgavinm 	if (dhdl) {
2935254Sgavinm 		cms = HDL2CMS(dhdl);
2945254Sgavinm 		cmi_hdl_rele(dhdl);	/* held in cms_search_list_cb */
2955254Sgavinm 	}
2965254Sgavinm 
2975254Sgavinm 	return (cms);
2985254Sgavinm }
2995254Sgavinm 
3005254Sgavinm /*
3015254Sgavinm  * Try to find or load a module that offers model-specific support for
3025254Sgavinm  * this vendor/family/model/stepping combination.  When attempting to load
3035254Sgavinm  * a module we look in CPUMOD_MS_SUBDIR first for a match on
3045254Sgavinm  * vendor/family/model/stepping, then on vendor/family/model (ignoring
3055254Sgavinm  * stepping), then on vendor/family (ignoring model and stepping), then
3065254Sgavinm  * on vendor alone.
3075254Sgavinm  */
3085254Sgavinm static cms_t *
cms_load_module(cmi_hdl_t hdl,int match,int * chosenp)3095254Sgavinm cms_load_module(cmi_hdl_t hdl, int match, int *chosenp)
3105254Sgavinm {
3115254Sgavinm 	modctl_t *modp;
3125254Sgavinm 	cms_t *cms;
3135254Sgavinm 	int modid;
3145254Sgavinm 	uint_t s[3];
3155254Sgavinm 
3165254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
3175254Sgavinm 	ASSERT(match == CMS_MATCH_STEPPING || match == CMS_MATCH_MODEL ||
3185254Sgavinm 	    match == CMS_MATCH_FAMILY || match == CMS_MATCH_VENDOR);
3195254Sgavinm 
3205254Sgavinm 	s[0] = cmi_hdl_family(hdl);
3215254Sgavinm 	s[1] = cmi_hdl_model(hdl);
3225254Sgavinm 	s[2] = cmi_hdl_stepping(hdl);
3235254Sgavinm 
3245254Sgavinm 	/*
3255254Sgavinm 	 * Have we already loaded a module for a cpu with the same
3265254Sgavinm 	 * vendor/family/model/stepping?
3275254Sgavinm 	 */
3285254Sgavinm 	if ((cms = cms_search_list(hdl, match)) != NULL) {
3295254Sgavinm 		cms_hold(cms);
3305254Sgavinm 		return (cms);
3315254Sgavinm 	}
3325254Sgavinm 
3335254Sgavinm 	modid = modload_qualified(CPUMOD_MS_SUBDIR, CPUMOD_MS_PREFIX,
3345254Sgavinm 	    cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
3355254Sgavinm 
3365254Sgavinm 	if (modid == -1)
3375254Sgavinm 		return (NULL);
3385254Sgavinm 
3395254Sgavinm 	modp = mod_hold_by_id(modid);
3405254Sgavinm 	cms = cms_load_modctl(modp);
3415254Sgavinm 	if (cms)
3425254Sgavinm 		cms_hold(cms);
3435254Sgavinm 	mod_release_mod(modp);
3445254Sgavinm 
3455254Sgavinm 	return (cms);
3465254Sgavinm }
3475254Sgavinm 
3485254Sgavinm static cms_t *
cms_load_specific(cmi_hdl_t hdl,void ** datap)3495254Sgavinm cms_load_specific(cmi_hdl_t hdl, void **datap)
3505254Sgavinm {
3515254Sgavinm 	cms_t *cms;
3525254Sgavinm 	int err;
3535254Sgavinm 	int i;
3545254Sgavinm 
3555254Sgavinm 	ASSERT(MUTEX_HELD(&cms_load_lock));
3565254Sgavinm 
3575254Sgavinm 	for (i = CMS_MATCH_STEPPING; i >= CMS_MATCH_VENDOR; i--) {
3585254Sgavinm 		int suffixlevel;
3595254Sgavinm 
3605254Sgavinm 		if ((cms = cms_load_module(hdl, i, &suffixlevel)) == NULL)
3615254Sgavinm 			return (NULL);
3625254Sgavinm 
3635254Sgavinm 		/*
3645254Sgavinm 		 * A module has loaded and has a _cms_ops structure, and the
3655254Sgavinm 		 * module has been held for this instance.  Call the cms_init
3665254Sgavinm 		 * entry point - we expect success (0) or ENOTSUP.
3675254Sgavinm 		 */
3685254Sgavinm 		if ((err = cms->cms_ops->cms_init(hdl, datap)) == 0) {
3695254Sgavinm 			if (boothowto & RB_VERBOSE) {
3705254Sgavinm 				printf("initialized model-specific "
3715254Sgavinm 				    "module '%s' on chip %d core %d "
3725254Sgavinm 				    "strand %d\n",
3735254Sgavinm 				    cms->cms_modp->mod_modname,
3745254Sgavinm 				    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
3755254Sgavinm 				    cmi_hdl_strandid(hdl));
3765254Sgavinm 			}
3775254Sgavinm 			return (cms);
3785254Sgavinm 		} else if (err != ENOTSUP) {
3795254Sgavinm 			cmn_err(CE_WARN, "failed to init model-specific "
3805254Sgavinm 			    "module '%s' on chip %d core %d strand %d: err=%d",
3815254Sgavinm 			    cms->cms_modp->mod_modname,
3825254Sgavinm 			    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
3835254Sgavinm 			    cmi_hdl_strandid(hdl), err);
3845254Sgavinm 		}
3855254Sgavinm 
3865254Sgavinm 		/*
3875254Sgavinm 		 * The module failed or declined to init, so release
3885254Sgavinm 		 * it and potentially change i to be equal to he number
3895254Sgavinm 		 * of suffices actually used in the last module path.
3905254Sgavinm 		 */
3915254Sgavinm 		cms_rele(cms);
3925254Sgavinm 		i = suffixlevel;
3935254Sgavinm 	}
3945254Sgavinm 
3955254Sgavinm 	return (NULL);
3965254Sgavinm }
3975254Sgavinm 
3985254Sgavinm void
cms_init(cmi_hdl_t hdl)3995254Sgavinm cms_init(cmi_hdl_t hdl)
4005254Sgavinm {
4015254Sgavinm 	cms_t *cms;
4025254Sgavinm 	void *data;
4035254Sgavinm 
4045254Sgavinm 	if (cms_no_model_specific != 0)
4055254Sgavinm 		return;
4065254Sgavinm 
4075254Sgavinm 	mutex_enter(&cms_load_lock);
4085254Sgavinm 
4095254Sgavinm 	if ((cms = cms_load_specific(hdl, &data)) != NULL) {
4105254Sgavinm 		struct cms_ctl *cdp;
4115254Sgavinm 
4125254Sgavinm 		ASSERT(cmi_hdl_getspecific(hdl) == NULL);
4135254Sgavinm 
4145254Sgavinm 		cdp = kmem_alloc(sizeof (*cdp), KM_SLEEP);
4155254Sgavinm 		cdp->cs_cms = cms;
4165254Sgavinm 		cdp->cs_cmsdata = data;
4175254Sgavinm 		cmi_hdl_setspecific(hdl, cdp);
4185254Sgavinm 	}
4195254Sgavinm 
4205254Sgavinm 	mutex_exit(&cms_load_lock);
4215254Sgavinm }
4225254Sgavinm 
4235254Sgavinm void
cms_fini(cmi_hdl_t hdl)4245254Sgavinm cms_fini(cmi_hdl_t hdl)
4255254Sgavinm {
4265254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
42712004Sjiang.liu@intel.com 	struct cms_ctl *cdp;
4285254Sgavinm 
4295254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_fini))
4305254Sgavinm 		CMS_OPS(cms)->cms_fini(hdl);
43112004Sjiang.liu@intel.com 
43212004Sjiang.liu@intel.com 	mutex_enter(&cms_load_lock);
43312004Sjiang.liu@intel.com 	cdp = (struct cms_ctl *)cmi_hdl_getspecific(hdl);
43412004Sjiang.liu@intel.com 	if (cdp != NULL) {
43512004Sjiang.liu@intel.com 		if (cdp->cs_cms != NULL)
43612004Sjiang.liu@intel.com 			cms_rele(cdp->cs_cms);
43712004Sjiang.liu@intel.com 		kmem_free(cdp, sizeof (*cdp));
43812004Sjiang.liu@intel.com 	}
43912004Sjiang.liu@intel.com 	mutex_exit(&cms_load_lock);
4405254Sgavinm }
4415254Sgavinm 
4425254Sgavinm boolean_t
cms_present(cmi_hdl_t hdl)4435254Sgavinm cms_present(cmi_hdl_t hdl)
4445254Sgavinm {
4455254Sgavinm 	return (HDL2CMS(hdl) != NULL ? B_TRUE : B_FALSE);
4465254Sgavinm }
4475254Sgavinm 
4485254Sgavinm void
cms_post_startup(cmi_hdl_t hdl)4495254Sgavinm cms_post_startup(cmi_hdl_t hdl)
4505254Sgavinm {
4515254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
4525254Sgavinm 
4535254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_post_startup))
4545254Sgavinm 		CMS_OPS(cms)->cms_post_startup(hdl);
4555254Sgavinm }
4565254Sgavinm 
4575254Sgavinm void
cms_post_mpstartup(cmi_hdl_t hdl)4585254Sgavinm cms_post_mpstartup(cmi_hdl_t hdl)
4595254Sgavinm {
4605254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
4615254Sgavinm 
4625254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_post_mpstartup))
4635254Sgavinm 		CMS_OPS(cms)->cms_post_mpstartup(hdl);
4645254Sgavinm }
4655254Sgavinm 
4665254Sgavinm size_t
cms_logout_size(cmi_hdl_t hdl)4675254Sgavinm cms_logout_size(cmi_hdl_t hdl)
4685254Sgavinm {
4695254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
4705254Sgavinm 
4715254Sgavinm 	if (!CMS_OP_PRESENT(cms, cms_logout_size))
4725254Sgavinm 		return (0);
4735254Sgavinm 
4745254Sgavinm 	return (CMS_OPS(cms)->cms_logout_size(hdl));
4755254Sgavinm }
4765254Sgavinm 
4775254Sgavinm uint64_t
cms_mcgctl_val(cmi_hdl_t hdl,int nbanks,uint64_t def)4785254Sgavinm cms_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t def)
4795254Sgavinm {
4805254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
4815254Sgavinm 
4825254Sgavinm 	if (!CMS_OP_PRESENT(cms, cms_mcgctl_val))
4835254Sgavinm 		return (def);
4845254Sgavinm 
4855254Sgavinm 	return (CMS_OPS(cms)->cms_mcgctl_val(hdl, nbanks, def));
4865254Sgavinm }
4875254Sgavinm 
4885254Sgavinm boolean_t
cms_bankctl_skipinit(cmi_hdl_t hdl,int banknum)4895254Sgavinm cms_bankctl_skipinit(cmi_hdl_t hdl, int banknum)
4905254Sgavinm {
4915254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
4925254Sgavinm 
4935254Sgavinm 	if (!CMS_OP_PRESENT(cms, cms_bankctl_skipinit))
4945254Sgavinm 		return (B_FALSE);
4955254Sgavinm 
4965254Sgavinm 	return (CMS_OPS(cms)->cms_bankctl_skipinit(hdl, banknum));
4975254Sgavinm }
4985254Sgavinm 
4995254Sgavinm uint64_t
cms_bankctl_val(cmi_hdl_t hdl,int banknum,uint64_t def)5005254Sgavinm cms_bankctl_val(cmi_hdl_t hdl, int banknum, uint64_t def)
5015254Sgavinm {
5025254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5035254Sgavinm 
5045254Sgavinm 	if (!CMS_OP_PRESENT(cms, cms_bankctl_val))
5055254Sgavinm 		return (def);
5065254Sgavinm 
5075254Sgavinm 	return (CMS_OPS(cms)->cms_bankctl_val(hdl, banknum, def));
5085254Sgavinm }
5095254Sgavinm 
5105254Sgavinm boolean_t
cms_bankstatus_skipinit(cmi_hdl_t hdl,int banknum)5115254Sgavinm cms_bankstatus_skipinit(cmi_hdl_t hdl, int banknum)
5125254Sgavinm {
5135254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5145254Sgavinm 
5155254Sgavinm 	if (!CMS_OP_PRESENT(cms, cms_bankstatus_skipinit))
5165254Sgavinm 		return (B_FALSE);
5175254Sgavinm 
5185254Sgavinm 	return (CMS_OPS(cms)->cms_bankstatus_skipinit(hdl, banknum));
5195254Sgavinm }
5205254Sgavinm 
5215254Sgavinm uint64_t
cms_bankstatus_val(cmi_hdl_t hdl,int banknum,uint64_t def)5225254Sgavinm cms_bankstatus_val(cmi_hdl_t hdl, int banknum, uint64_t def)
5235254Sgavinm {
5245254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5255254Sgavinm 
5265254Sgavinm 	if (!CMS_OP_PRESENT(cms, cms_bankstatus_val))
5275254Sgavinm 		return (def);
5285254Sgavinm 
5295254Sgavinm 	return (CMS_OPS(cms)->cms_bankstatus_val(hdl, banknum, def));
5305254Sgavinm }
5315254Sgavinm 
5325254Sgavinm void
cms_mca_init(cmi_hdl_t hdl,int nbanks)5335254Sgavinm cms_mca_init(cmi_hdl_t hdl, int nbanks)
5345254Sgavinm {
5355254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5365254Sgavinm 
5375254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_mca_init))
5385254Sgavinm 		CMS_OPS(cms)->cms_mca_init(hdl, nbanks);
5395254Sgavinm }
5405254Sgavinm 
5415254Sgavinm uint64_t
cms_poll_ownermask(cmi_hdl_t hdl,hrtime_t poll_interval)5425254Sgavinm cms_poll_ownermask(cmi_hdl_t hdl, hrtime_t poll_interval)
5435254Sgavinm {
5445254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5455254Sgavinm 
5465254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_poll_ownermask))
5475254Sgavinm 		return (CMS_OPS(cms)->cms_poll_ownermask(hdl, poll_interval));
5485254Sgavinm 	else
5495254Sgavinm 		return (-1ULL);		/* poll all banks by default */
5505254Sgavinm }
5515254Sgavinm 
5525254Sgavinm void
cms_bank_logout(cmi_hdl_t hdl,int banknum,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)5535254Sgavinm cms_bank_logout(cmi_hdl_t hdl, int banknum, uint64_t status, uint64_t addr,
5545254Sgavinm     uint64_t misc, void *mslogout)
5555254Sgavinm {
5565254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5575254Sgavinm 
5585254Sgavinm 	if (mslogout != NULL && CMS_OP_PRESENT(cms, cms_bank_logout))
5595254Sgavinm 		CMS_OPS(cms)->cms_bank_logout(hdl, banknum, status, addr,
5605254Sgavinm 		    misc, mslogout);
5615254Sgavinm }
5625254Sgavinm 
5635254Sgavinm cms_errno_t
cms_msrinject(cmi_hdl_t hdl,uint_t msr,uint64_t val)5645254Sgavinm cms_msrinject(cmi_hdl_t hdl, uint_t msr, uint64_t val)
5655254Sgavinm {
5665254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5675254Sgavinm 
5685254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_msrinject))
5695254Sgavinm 		return (CMS_OPS(cms)->cms_msrinject(hdl, msr, val));
5705254Sgavinm 	else
5715254Sgavinm 		return (CMSERR_NOTSUP);
5725254Sgavinm }
5735254Sgavinm 
5745254Sgavinm uint32_t
cms_error_action(cmi_hdl_t hdl,int ismc,int banknum,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)5755254Sgavinm cms_error_action(cmi_hdl_t hdl, int ismc, int banknum, uint64_t status,
5765254Sgavinm     uint64_t addr, uint64_t misc, void *mslogout)
5775254Sgavinm {
5785254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5795254Sgavinm 
5805254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_error_action))
5815254Sgavinm 		return (CMS_OPS(cms)->cms_error_action(hdl, ismc, banknum,
5825254Sgavinm 		    status, addr, misc, mslogout));
5835254Sgavinm 	else
5845254Sgavinm 		return (0);
5855254Sgavinm }
5865254Sgavinm 
5875254Sgavinm cms_cookie_t
cms_disp_match(cmi_hdl_t hdl,int ismc,int banknum,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)588*12437SAdrian.Frost@Sun.COM cms_disp_match(cmi_hdl_t hdl, int ismc, int banknum, uint64_t status,
589*12437SAdrian.Frost@Sun.COM     uint64_t addr, uint64_t misc, void *mslogout)
5905254Sgavinm {
5915254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
5925254Sgavinm 
5935254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_disp_match))
594*12437SAdrian.Frost@Sun.COM 		return (CMS_OPS(cms)->cms_disp_match(hdl, ismc, banknum,
5955254Sgavinm 		    status, addr, misc, mslogout));
5965254Sgavinm 	else
5975254Sgavinm 		return (NULL);
5985254Sgavinm 
5995254Sgavinm }
6005254Sgavinm 
6015254Sgavinm void
cms_ereport_class(cmi_hdl_t hdl,cms_cookie_t mscookie,const char ** cpuclsp,const char ** leafclsp)6025254Sgavinm cms_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie, const char **cpuclsp,
6035254Sgavinm     const char **leafclsp)
6045254Sgavinm {
6055254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
6065254Sgavinm 
6075254Sgavinm 	if (cpuclsp == NULL || leafclsp == NULL)
6085254Sgavinm 		return;
6095254Sgavinm 
6105254Sgavinm 	*cpuclsp = *leafclsp = NULL;
6115254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_ereport_class)) {
6125254Sgavinm 		CMS_OPS(cms)->cms_ereport_class(hdl, mscookie, cpuclsp,
6135254Sgavinm 		    leafclsp);
6145254Sgavinm 	}
6155254Sgavinm }
6165254Sgavinm 
6175254Sgavinm nvlist_t *
cms_ereport_detector(cmi_hdl_t hdl,int bankno,cms_cookie_t mscookie,nv_alloc_t * nva)61810831SYanmin.Sun@Sun.COM cms_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie,
61910831SYanmin.Sun@Sun.COM     nv_alloc_t *nva)
6205254Sgavinm {
6215254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
6225254Sgavinm 
6235254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_ereport_detector))
62410831SYanmin.Sun@Sun.COM 		return (CMS_OPS(cms)->cms_ereport_detector(hdl, bankno,
62510831SYanmin.Sun@Sun.COM 		    mscookie, nva));
6265254Sgavinm 	else
6275254Sgavinm 		return (NULL);
6285254Sgavinm 
6295254Sgavinm }
6305254Sgavinm 
6315254Sgavinm boolean_t
cms_ereport_includestack(cmi_hdl_t hdl,cms_cookie_t mscookie)6325254Sgavinm cms_ereport_includestack(cmi_hdl_t hdl, cms_cookie_t mscookie)
6335254Sgavinm {
6345254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
6355254Sgavinm 
6365254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_ereport_includestack)) {
6375254Sgavinm 		return (CMS_OPS(cms)->cms_ereport_includestack(hdl, mscookie));
6385254Sgavinm 	} else {
6395254Sgavinm 		return (B_FALSE);
6405254Sgavinm 	}
6415254Sgavinm }
6425254Sgavinm 
6435254Sgavinm void
cms_ereport_add_logout(cmi_hdl_t hdl,nvlist_t * nvl,nv_alloc_t * nva,int banknum,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout,cms_cookie_t mscookie)6445254Sgavinm cms_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *nvl, nv_alloc_t *nva,
6455254Sgavinm     int banknum, uint64_t status, uint64_t addr, uint64_t misc, void *mslogout,
6465254Sgavinm     cms_cookie_t mscookie)
6475254Sgavinm {
6485254Sgavinm 	cms_t *cms = HDL2CMS(hdl);
6495254Sgavinm 
6505254Sgavinm 	if (CMS_OP_PRESENT(cms, cms_ereport_add_logout))
6515254Sgavinm 		CMS_OPS(cms)->cms_ereport_add_logout(hdl, nvl, nva, banknum,
6525254Sgavinm 		    status, addr, misc, mslogout, mscookie);
6535254Sgavinm 
6545254Sgavinm }
655