4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright (c) 2010, Intel Corporation.
27 * All rights reserved.
30 #include <sys/types.h>
31 #include <sys/cpu_module_ms_impl.h>
32 #include <sys/cpuvar.h>
33 #include <sys/ksynch.h>
34 #include <sys/modctl.h>
35 #include <sys/x86_archext.h>
36 #include <sys/systm.h>
37 #include <sys/cmn_err.h>
38 #include <sys/param.h>
39 #include <sys/reboot.h>
42 * Set to prevent model-specific support from initialising.
44 int cms_no_model_specific
= 0;
47 * Subdirectory (relative to the module search path) in which we will
48 * look for model-specific modules.
50 #define CPUMOD_MS_SUBDIR "cpu"
53 * Cpu model-specific modules have filenames beginning with the following.
55 #define CPUMOD_MS_PREFIX "cpu_ms"
57 #define HDL2CMS(hdl) cms_hdl_getcms(hdl)
59 #define CMS_OPS(cms) (cms)->cms_ops
60 #define CMS_OP_PRESENT(cms, op) ((cms) && CMS_OPS(cms)->op != NULL)
69 #define CMS_MATCH_VENDOR 0 /* Just match on vendor */
70 #define CMS_MATCH_FAMILY 1 /* Match down to family */
71 #define CMS_MATCH_MODEL 2 /* Match down to model */
72 #define CMS_MATCH_STEPPING 3 /* Match down to stepping */
75 * Structure used to keep track of modules we have loaded.
80 const cms_ops_t
*cms_ops
;
81 struct modctl
*cms_modp
;
85 static cms_t
*cms_list
;
86 static kmutex_t cms_load_lock
;
89 * We stash a cms_t and associated private data via cmi_hdl_setspecific.
97 cms_hdl_getcms(cmi_hdl_t hdl
)
99 struct cms_ctl
*cdp
= cmi_hdl_getspecific(hdl
);
101 return (cdp
!= NULL
? cdp
->cs_cms
: NULL
);
105 cms_hdl_getcmsdata(cmi_hdl_t hdl
)
107 struct cms_ctl
*cdp
= cmi_hdl_getspecific(hdl
);
109 return (cdp
!= NULL
? cdp
->cs_cmsdata
: NULL
);
115 ASSERT(MUTEX_HELD(&cms_load_lock
));
117 cms
->cms_prev
= NULL
;
118 cms
->cms_next
= cms_list
;
119 if (cms_list
!= NULL
)
120 cms_list
->cms_prev
= cms
;
125 cms_unlink(cms_t
*cms
)
127 ASSERT(MUTEX_HELD(&cms_load_lock
));
128 ASSERT(cms
->cms_refcnt
== 0);
130 if (cms
->cms_prev
!= NULL
)
131 cms
->cms_prev
->cms_next
= cms
->cms_next
;
133 if (cms
->cms_next
!= NULL
)
134 cms
->cms_next
->cms_prev
= cms
->cms_prev
;
137 cms_list
= cms
->cms_next
;
141 * Hold the module in memory. We call to CPU modules without using the
142 * stubs mechanism, so these modules must be manually held in memory.
143 * The mod_ref acts as if another loaded module has a dependency on us.
148 ASSERT(MUTEX_HELD(&cms_load_lock
));
150 mutex_enter(&mod_lock
);
151 cms
->cms_modp
->mod_ref
++;
152 mutex_exit(&mod_lock
);
159 ASSERT(MUTEX_HELD(&cms_load_lock
));
161 mutex_enter(&mod_lock
);
162 cms
->cms_modp
->mod_ref
--;
163 mutex_exit(&mod_lock
);
165 if (--cms
->cms_refcnt
== 0) {
167 kmem_free(cms
, sizeof (cms_t
));
172 cms_getops(modctl_t
*modp
)
176 if ((ops
= (cms_ops_t
*)modlookup_by_modctl(modp
, "_cms_ops")) ==
178 cmn_err(CE_WARN
, "cpu_ms module '%s' is invalid: no _cms_ops "
179 "found", modp
->mod_modname
);
183 if (ops
->cms_init
== NULL
) {
184 cmn_err(CE_WARN
, "cpu_ms module '%s' is invalid: no cms_init "
185 "entry point", modp
->mod_modname
);
193 cms_load_modctl(modctl_t
*modp
)
198 cms_api_ver_t apiver
;
200 ASSERT(MUTEX_HELD(&cms_load_lock
));
202 for (cms
= cms_list
; cms
!= NULL
; cms
= cms
->cms_next
) {
203 if (cms
->cms_modp
== modp
)
207 if ((ver
= modlookup_by_modctl(modp
, "_cms_api_version")) == NULL
) {
208 cmn_err(CE_WARN
, "cpu model-specific module '%s' is invalid: "
209 "no _cms_api_version", modp
->mod_modname
);
212 apiver
= *((cms_api_ver_t
*)ver
);
213 if (!CMS_API_VERSION_CHKMAGIC(apiver
)) {
214 cmn_err(CE_WARN
, "cpu model-specific module '%s' is "
215 "invalid: _cms_api_version 0x%x has bad magic",
216 modp
->mod_modname
, apiver
);
221 if (apiver
!= CMS_API_VERSION
) {
222 cmn_err(CE_WARN
, "cpu model-specific module '%s' has API "
223 "version %d, kernel requires API version %d",
224 modp
->mod_modname
, CMS_API_VERSION_TOPRINT(apiver
),
225 CMS_API_VERSION_TOPRINT(CMS_API_VERSION
));
229 if ((ops
= cms_getops(modp
)) == NULL
)
232 cms
= kmem_zalloc(sizeof (cms_t
), KM_SLEEP
);
234 cms
->cms_modp
= modp
;
242 cms_cpu_match(cmi_hdl_t hdl1
, cmi_hdl_t hdl2
, int match
)
244 if (match
>= CMS_MATCH_VENDOR
&&
245 cmi_hdl_vendor(hdl1
) != cmi_hdl_vendor(hdl2
))
248 if (match
>= CMS_MATCH_FAMILY
&&
249 cmi_hdl_family(hdl1
) != cmi_hdl_family(hdl2
))
252 if (match
>= CMS_MATCH_MODEL
&&
253 cmi_hdl_model(hdl1
) != cmi_hdl_model(hdl2
))
256 if (match
>= CMS_MATCH_STEPPING
&&
257 cmi_hdl_stepping(hdl1
) != cmi_hdl_stepping(hdl2
))
264 cms_search_list_cb(cmi_hdl_t whdl
, void *arg1
, void *arg2
, void *arg3
)
266 cmi_hdl_t thdl
= (cmi_hdl_t
)arg1
;
267 int match
= *((int *)arg2
);
268 cmi_hdl_t
*rsltp
= (cmi_hdl_t
*)arg3
;
270 if (cms_cpu_match(thdl
, whdl
, match
)) {
271 cmi_hdl_hold(whdl
); /* short-term hold */
273 return (CMI_HDL_WALK_DONE
);
275 return (CMI_HDL_WALK_NEXT
);
280 * Look to see if we've already got a module loaded for a CPU just
281 * like this one. If we do, then we'll re-use it.
284 cms_search_list(cmi_hdl_t hdl
, int match
)
286 cmi_hdl_t dhdl
= NULL
;
289 ASSERT(MUTEX_HELD(&cms_load_lock
));
291 cmi_hdl_walk(cms_search_list_cb
, (void *)hdl
, (void *)&match
, &dhdl
);
294 cmi_hdl_rele(dhdl
); /* held in cms_search_list_cb */
301 * Try to find or load a module that offers model-specific support for
302 * this vendor/family/model/stepping combination. When attempting to load
303 * a module we look in CPUMOD_MS_SUBDIR first for a match on
304 * vendor/family/model/stepping, then on vendor/family/model (ignoring
305 * stepping), then on vendor/family (ignoring model and stepping), then
309 cms_load_module(cmi_hdl_t hdl
, int match
, int *chosenp
)
316 ASSERT(MUTEX_HELD(&cms_load_lock
));
317 ASSERT(match
== CMS_MATCH_STEPPING
|| match
== CMS_MATCH_MODEL
||
318 match
== CMS_MATCH_FAMILY
|| match
== CMS_MATCH_VENDOR
);
320 s
[0] = cmi_hdl_family(hdl
);
321 s
[1] = cmi_hdl_model(hdl
);
322 s
[2] = cmi_hdl_stepping(hdl
);
325 * Have we already loaded a module for a cpu with the same
326 * vendor/family/model/stepping?
328 if ((cms
= cms_search_list(hdl
, match
)) != NULL
) {
333 modid
= modload_qualified(CPUMOD_MS_SUBDIR
, CPUMOD_MS_PREFIX
,
334 cmi_hdl_vendorstr(hdl
), ".", s
, match
, chosenp
);
339 modp
= mod_hold_by_id(modid
);
340 cms
= cms_load_modctl(modp
);
343 mod_release_mod(modp
);
349 cms_load_specific(cmi_hdl_t hdl
, void **datap
)
355 ASSERT(MUTEX_HELD(&cms_load_lock
));
357 for (i
= CMS_MATCH_STEPPING
; i
>= CMS_MATCH_VENDOR
; i
--) {
360 if ((cms
= cms_load_module(hdl
, i
, &suffixlevel
)) == NULL
)
364 * A module has loaded and has a _cms_ops structure, and the
365 * module has been held for this instance. Call the cms_init
366 * entry point - we expect success (0) or ENOTSUP.
368 if ((err
= cms
->cms_ops
->cms_init(hdl
, datap
)) == 0) {
369 if (boothowto
& RB_VERBOSE
) {
370 printf("initialized model-specific "
371 "module '%s' on chip %d core %d "
373 cms
->cms_modp
->mod_modname
,
374 cmi_hdl_chipid(hdl
), cmi_hdl_coreid(hdl
),
375 cmi_hdl_strandid(hdl
));
378 } else if (err
!= ENOTSUP
) {
379 cmn_err(CE_WARN
, "failed to init model-specific "
380 "module '%s' on chip %d core %d strand %d: err=%d",
381 cms
->cms_modp
->mod_modname
,
382 cmi_hdl_chipid(hdl
), cmi_hdl_coreid(hdl
),
383 cmi_hdl_strandid(hdl
), err
);
387 * The module failed or declined to init, so release
388 * it and potentially change i to be equal to he number
389 * of suffices actually used in the last module path.
399 cms_init(cmi_hdl_t hdl
)
404 if (cms_no_model_specific
!= 0)
407 mutex_enter(&cms_load_lock
);
409 if ((cms
= cms_load_specific(hdl
, &data
)) != NULL
) {
412 ASSERT(cmi_hdl_getspecific(hdl
) == NULL
);
414 cdp
= kmem_alloc(sizeof (*cdp
), KM_SLEEP
);
416 cdp
->cs_cmsdata
= data
;
417 cmi_hdl_setspecific(hdl
, cdp
);
420 mutex_exit(&cms_load_lock
);
424 cms_fini(cmi_hdl_t hdl
)
426 cms_t
*cms
= HDL2CMS(hdl
);
429 if (CMS_OP_PRESENT(cms
, cms_fini
))
430 CMS_OPS(cms
)->cms_fini(hdl
);
432 mutex_enter(&cms_load_lock
);
433 cdp
= (struct cms_ctl
*)cmi_hdl_getspecific(hdl
);
435 if (cdp
->cs_cms
!= NULL
)
436 cms_rele(cdp
->cs_cms
);
437 kmem_free(cdp
, sizeof (*cdp
));
439 mutex_exit(&cms_load_lock
);
443 cms_present(cmi_hdl_t hdl
)
445 return (HDL2CMS(hdl
) != NULL
? B_TRUE
: B_FALSE
);
449 cms_post_startup(cmi_hdl_t hdl
)
451 cms_t
*cms
= HDL2CMS(hdl
);
453 if (CMS_OP_PRESENT(cms
, cms_post_startup
))
454 CMS_OPS(cms
)->cms_post_startup(hdl
);
458 cms_post_mpstartup(cmi_hdl_t hdl
)
460 cms_t
*cms
= HDL2CMS(hdl
);
462 if (CMS_OP_PRESENT(cms
, cms_post_mpstartup
))
463 CMS_OPS(cms
)->cms_post_mpstartup(hdl
);
467 cms_logout_size(cmi_hdl_t hdl
)
469 cms_t
*cms
= HDL2CMS(hdl
);
471 if (!CMS_OP_PRESENT(cms
, cms_logout_size
))
474 return (CMS_OPS(cms
)->cms_logout_size(hdl
));
478 cms_mcgctl_val(cmi_hdl_t hdl
, int nbanks
, uint64_t def
)
480 cms_t
*cms
= HDL2CMS(hdl
);
482 if (!CMS_OP_PRESENT(cms
, cms_mcgctl_val
))
485 return (CMS_OPS(cms
)->cms_mcgctl_val(hdl
, nbanks
, def
));
489 cms_bankctl_skipinit(cmi_hdl_t hdl
, int banknum
)
491 cms_t
*cms
= HDL2CMS(hdl
);
493 if (!CMS_OP_PRESENT(cms
, cms_bankctl_skipinit
))
496 return (CMS_OPS(cms
)->cms_bankctl_skipinit(hdl
, banknum
));
500 cms_bankctl_val(cmi_hdl_t hdl
, int banknum
, uint64_t def
)
502 cms_t
*cms
= HDL2CMS(hdl
);
504 if (!CMS_OP_PRESENT(cms
, cms_bankctl_val
))
507 return (CMS_OPS(cms
)->cms_bankctl_val(hdl
, banknum
, def
));
511 cms_bankstatus_skipinit(cmi_hdl_t hdl
, int banknum
)
513 cms_t
*cms
= HDL2CMS(hdl
);
515 if (!CMS_OP_PRESENT(cms
, cms_bankstatus_skipinit
))
518 return (CMS_OPS(cms
)->cms_bankstatus_skipinit(hdl
, banknum
));
522 cms_bankstatus_val(cmi_hdl_t hdl
, int banknum
, uint64_t def
)
524 cms_t
*cms
= HDL2CMS(hdl
);
526 if (!CMS_OP_PRESENT(cms
, cms_bankstatus_val
))
529 return (CMS_OPS(cms
)->cms_bankstatus_val(hdl
, banknum
, def
));
533 cms_mca_init(cmi_hdl_t hdl
, int nbanks
)
535 cms_t
*cms
= HDL2CMS(hdl
);
537 if (CMS_OP_PRESENT(cms
, cms_mca_init
))
538 CMS_OPS(cms
)->cms_mca_init(hdl
, nbanks
);
542 cms_poll_ownermask(cmi_hdl_t hdl
, hrtime_t poll_interval
)
544 cms_t
*cms
= HDL2CMS(hdl
);
546 if (CMS_OP_PRESENT(cms
, cms_poll_ownermask
))
547 return (CMS_OPS(cms
)->cms_poll_ownermask(hdl
, poll_interval
));
549 return (-1ULL); /* poll all banks by default */
553 cms_bank_logout(cmi_hdl_t hdl
, int banknum
, uint64_t status
, uint64_t addr
,
554 uint64_t misc
, void *mslogout
)
556 cms_t
*cms
= HDL2CMS(hdl
);
558 if (mslogout
!= NULL
&& CMS_OP_PRESENT(cms
, cms_bank_logout
))
559 CMS_OPS(cms
)->cms_bank_logout(hdl
, banknum
, status
, addr
,
564 cms_msrinject(cmi_hdl_t hdl
, uint_t msr
, uint64_t val
)
566 cms_t
*cms
= HDL2CMS(hdl
);
568 if (CMS_OP_PRESENT(cms
, cms_msrinject
))
569 return (CMS_OPS(cms
)->cms_msrinject(hdl
, msr
, val
));
571 return (CMSERR_NOTSUP
);
575 cms_error_action(cmi_hdl_t hdl
, int ismc
, int banknum
, uint64_t status
,
576 uint64_t addr
, uint64_t misc
, void *mslogout
)
578 cms_t
*cms
= HDL2CMS(hdl
);
580 if (CMS_OP_PRESENT(cms
, cms_error_action
))
581 return (CMS_OPS(cms
)->cms_error_action(hdl
, ismc
, banknum
,
582 status
, addr
, misc
, mslogout
));
588 cms_disp_match(cmi_hdl_t hdl
, int ismc
, int banknum
, uint64_t status
,
589 uint64_t addr
, uint64_t misc
, void *mslogout
)
591 cms_t
*cms
= HDL2CMS(hdl
);
593 if (CMS_OP_PRESENT(cms
, cms_disp_match
))
594 return (CMS_OPS(cms
)->cms_disp_match(hdl
, ismc
, banknum
,
595 status
, addr
, misc
, mslogout
));
602 cms_ereport_class(cmi_hdl_t hdl
, cms_cookie_t mscookie
, const char **cpuclsp
,
603 const char **leafclsp
)
605 cms_t
*cms
= HDL2CMS(hdl
);
607 if (cpuclsp
== NULL
|| leafclsp
== NULL
)
610 *cpuclsp
= *leafclsp
= NULL
;
611 if (CMS_OP_PRESENT(cms
, cms_ereport_class
)) {
612 CMS_OPS(cms
)->cms_ereport_class(hdl
, mscookie
, cpuclsp
,
618 cms_ereport_detector(cmi_hdl_t hdl
, int bankno
, cms_cookie_t mscookie
,
621 cms_t
*cms
= HDL2CMS(hdl
);
623 if (CMS_OP_PRESENT(cms
, cms_ereport_detector
))
624 return (CMS_OPS(cms
)->cms_ereport_detector(hdl
, bankno
,
632 cms_ereport_includestack(cmi_hdl_t hdl
, cms_cookie_t mscookie
)
634 cms_t
*cms
= HDL2CMS(hdl
);
636 if (CMS_OP_PRESENT(cms
, cms_ereport_includestack
)) {
637 return (CMS_OPS(cms
)->cms_ereport_includestack(hdl
, mscookie
));
644 cms_ereport_add_logout(cmi_hdl_t hdl
, nvlist_t
*nvl
, nv_alloc_t
*nva
,
645 int banknum
, uint64_t status
, uint64_t addr
, uint64_t misc
, void *mslogout
,
646 cms_cookie_t mscookie
)
648 cms_t
*cms
= HDL2CMS(hdl
);
650 if (CMS_OP_PRESENT(cms
, cms_ereport_add_logout
))
651 CMS_OPS(cms
)->cms_ereport_add_logout(hdl
, nvl
, nva
, banknum
,
652 status
, addr
, misc
, mslogout
, mscookie
);