xref: /titanic_52/usr/src/uts/i86pc/os/cms.c (revision 20c794b39650d115e17a15983b6b82e46238cf45)
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