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.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * Copyright (c) 2010, Intel Corporation.
28 * All rights reserved.
31 #include <sys/types.h>
32 #include <sys/cpu_module_ms_impl.h>
33 #include <sys/cpuvar.h>
34 #include <sys/ksynch.h>
35 #include <sys/modctl.h>
36 #include <sys/x86_archext.h>
37 #include <sys/systm.h>
38 #include <sys/cmn_err.h>
39 #include <sys/param.h>
40 #include <sys/reboot.h>
43 * Set to prevent model-specific support from initialising.
45 int cms_no_model_specific
= 0;
48 * Subdirectory (relative to the module search path) in which we will
49 * look for model-specific modules.
51 #define CPUMOD_MS_SUBDIR "cpu"
54 * Cpu model-specific modules have filenames beginning with the following.
56 #define CPUMOD_MS_PREFIX "cpu_ms"
58 #define HDL2CMS(hdl) cms_hdl_getcms(hdl)
60 #define CMS_OPS(cms) (cms)->cms_ops
61 #define CMS_OP_PRESENT(cms, op) ((cms) && CMS_OPS(cms)->op != NULL)
70 #define CMS_MATCH_VENDOR 0 /* Just match on vendor */
71 #define CMS_MATCH_FAMILY 1 /* Match down to family */
72 #define CMS_MATCH_MODEL 2 /* Match down to model */
73 #define CMS_MATCH_STEPPING 3 /* Match down to stepping */
76 * Structure used to keep track of modules we have loaded.
81 const cms_ops_t
*cms_ops
;
82 struct modctl
*cms_modp
;
86 static cms_t
*cms_list
;
87 static kmutex_t cms_load_lock
;
90 * We stash a cms_t and associated private data via cmi_hdl_setspecific.
98 cms_hdl_getcms(cmi_hdl_t hdl
)
100 struct cms_ctl
*cdp
= cmi_hdl_getspecific(hdl
);
102 return (cdp
!= NULL
? cdp
->cs_cms
: NULL
);
106 cms_hdl_getcmsdata(cmi_hdl_t hdl
)
108 struct cms_ctl
*cdp
= cmi_hdl_getspecific(hdl
);
110 return (cdp
!= NULL
? cdp
->cs_cmsdata
: NULL
);
116 ASSERT(MUTEX_HELD(&cms_load_lock
));
118 cms
->cms_prev
= NULL
;
119 cms
->cms_next
= cms_list
;
120 if (cms_list
!= NULL
)
121 cms_list
->cms_prev
= cms
;
126 cms_unlink(cms_t
*cms
)
128 ASSERT(MUTEX_HELD(&cms_load_lock
));
129 ASSERT(cms
->cms_refcnt
== 0);
131 if (cms
->cms_prev
!= NULL
)
132 cms
->cms_prev
->cms_next
= cms
->cms_next
;
134 if (cms
->cms_next
!= NULL
)
135 cms
->cms_next
->cms_prev
= cms
->cms_prev
;
138 cms_list
= cms
->cms_next
;
142 * Hold the module in memory. We call to CPU modules without using the
143 * stubs mechanism, so these modules must be manually held in memory.
144 * The mod_ref acts as if another loaded module has a dependency on us.
149 ASSERT(MUTEX_HELD(&cms_load_lock
));
151 mutex_enter(&mod_lock
);
152 cms
->cms_modp
->mod_ref
++;
153 mutex_exit(&mod_lock
);
160 ASSERT(MUTEX_HELD(&cms_load_lock
));
162 mutex_enter(&mod_lock
);
163 cms
->cms_modp
->mod_ref
--;
164 mutex_exit(&mod_lock
);
166 if (--cms
->cms_refcnt
== 0) {
168 kmem_free(cms
, sizeof (cms_t
));
173 cms_getops(modctl_t
*modp
)
177 if ((ops
= (cms_ops_t
*)modlookup_by_modctl(modp
, "_cms_ops")) ==
179 cmn_err(CE_WARN
, "cpu_ms module '%s' is invalid: no _cms_ops "
180 "found", modp
->mod_modname
);
184 if (ops
->cms_init
== NULL
) {
185 cmn_err(CE_WARN
, "cpu_ms module '%s' is invalid: no cms_init "
186 "entry point", modp
->mod_modname
);
194 cms_load_modctl(modctl_t
*modp
)
199 cms_api_ver_t apiver
;
201 ASSERT(MUTEX_HELD(&cms_load_lock
));
203 for (cms
= cms_list
; cms
!= NULL
; cms
= cms
->cms_next
) {
204 if (cms
->cms_modp
== modp
)
208 if ((ver
= modlookup_by_modctl(modp
, "_cms_api_version")) == NULL
) {
209 cmn_err(CE_WARN
, "cpu model-specific module '%s' is invalid: "
210 "no _cms_api_version", modp
->mod_modname
);
213 apiver
= *((cms_api_ver_t
*)ver
);
214 if (!CMS_API_VERSION_CHKMAGIC(apiver
)) {
215 cmn_err(CE_WARN
, "cpu model-specific module '%s' is "
216 "invalid: _cms_api_version 0x%x has bad magic",
217 modp
->mod_modname
, apiver
);
222 if (apiver
!= CMS_API_VERSION
) {
223 cmn_err(CE_WARN
, "cpu model-specific module '%s' has API "
224 "version %d, kernel requires API version %d",
225 modp
->mod_modname
, CMS_API_VERSION_TOPRINT(apiver
),
226 CMS_API_VERSION_TOPRINT(CMS_API_VERSION
));
230 if ((ops
= cms_getops(modp
)) == NULL
)
233 cms
= kmem_zalloc(sizeof (cms_t
), KM_SLEEP
);
235 cms
->cms_modp
= modp
;
243 cms_cpu_match(cmi_hdl_t hdl1
, cmi_hdl_t hdl2
, int match
)
245 if (match
>= CMS_MATCH_VENDOR
&&
246 cmi_hdl_vendor(hdl1
) != cmi_hdl_vendor(hdl2
))
249 if (match
>= CMS_MATCH_FAMILY
&&
250 cmi_hdl_family(hdl1
) != cmi_hdl_family(hdl2
))
253 if (match
>= CMS_MATCH_MODEL
&&
254 cmi_hdl_model(hdl1
) != cmi_hdl_model(hdl2
))
257 if (match
>= CMS_MATCH_STEPPING
&&
258 cmi_hdl_stepping(hdl1
) != cmi_hdl_stepping(hdl2
))
265 cms_search_list_cb(cmi_hdl_t whdl
, void *arg1
, void *arg2
, void *arg3
)
267 cmi_hdl_t thdl
= (cmi_hdl_t
)arg1
;
268 int match
= *((int *)arg2
);
269 cmi_hdl_t
*rsltp
= (cmi_hdl_t
*)arg3
;
271 if (cms_cpu_match(thdl
, whdl
, match
)) {
272 cmi_hdl_hold(whdl
); /* short-term hold */
274 return (CMI_HDL_WALK_DONE
);
276 return (CMI_HDL_WALK_NEXT
);
281 * Look to see if we've already got a module loaded for a CPU just
282 * like this one. If we do, then we'll re-use it.
285 cms_search_list(cmi_hdl_t hdl
, int match
)
287 cmi_hdl_t dhdl
= NULL
;
290 ASSERT(MUTEX_HELD(&cms_load_lock
));
292 cmi_hdl_walk(cms_search_list_cb
, (void *)hdl
, (void *)&match
, &dhdl
);
295 cmi_hdl_rele(dhdl
); /* held in cms_search_list_cb */
302 * Try to find or load a module that offers model-specific support for
303 * this vendor/family/model/stepping combination. When attempting to load
304 * a module we look in CPUMOD_MS_SUBDIR first for a match on
305 * vendor/family/model/stepping, then on vendor/family/model (ignoring
306 * stepping), then on vendor/family (ignoring model and stepping), then
310 cms_load_module(cmi_hdl_t hdl
, int match
, int *chosenp
)
317 ASSERT(MUTEX_HELD(&cms_load_lock
));
318 ASSERT(match
== CMS_MATCH_STEPPING
|| match
== CMS_MATCH_MODEL
||
319 match
== CMS_MATCH_FAMILY
|| match
== CMS_MATCH_VENDOR
);
321 s
[0] = cmi_hdl_family(hdl
);
322 s
[1] = cmi_hdl_model(hdl
);
323 s
[2] = cmi_hdl_stepping(hdl
);
326 * Have we already loaded a module for a cpu with the same
327 * vendor/family/model/stepping?
329 if ((cms
= cms_search_list(hdl
, match
)) != NULL
) {
334 modid
= modload_qualified(CPUMOD_MS_SUBDIR
, CPUMOD_MS_PREFIX
,
335 cmi_hdl_vendorstr(hdl
), ".", s
, match
, chosenp
);
340 modp
= mod_hold_by_id(modid
);
341 cms
= cms_load_modctl(modp
);
344 mod_release_mod(modp
);
350 cms_load_specific(cmi_hdl_t hdl
, void **datap
)
356 ASSERT(MUTEX_HELD(&cms_load_lock
));
358 for (i
= CMS_MATCH_STEPPING
; i
>= CMS_MATCH_VENDOR
; i
--) {
361 if ((cms
= cms_load_module(hdl
, i
, &suffixlevel
)) == NULL
)
365 * A module has loaded and has a _cms_ops structure, and the
366 * module has been held for this instance. Call the cms_init
367 * entry point - we expect success (0) or ENOTSUP.
369 if ((err
= cms
->cms_ops
->cms_init(hdl
, datap
)) == 0) {
370 if (boothowto
& RB_VERBOSE
) {
371 printf("initialized model-specific "
372 "module '%s' on chip %d core %d "
374 cms
->cms_modp
->mod_modname
,
375 cmi_hdl_chipid(hdl
), cmi_hdl_coreid(hdl
),
376 cmi_hdl_strandid(hdl
));
379 } else if (err
!= ENOTSUP
) {
380 cmn_err(CE_WARN
, "failed to init model-specific "
381 "module '%s' on chip %d core %d strand %d: err=%d",
382 cms
->cms_modp
->mod_modname
,
383 cmi_hdl_chipid(hdl
), cmi_hdl_coreid(hdl
),
384 cmi_hdl_strandid(hdl
), err
);
388 * The module failed or declined to init, so release
389 * it and potentially change i to be equal to the number
390 * of suffices actually used in the last module path.
400 cms_init(cmi_hdl_t hdl
)
405 if (cms_no_model_specific
!= 0)
408 mutex_enter(&cms_load_lock
);
410 if ((cms
= cms_load_specific(hdl
, &data
)) != NULL
) {
413 ASSERT(cmi_hdl_getspecific(hdl
) == NULL
);
415 cdp
= kmem_alloc(sizeof (*cdp
), KM_SLEEP
);
417 cdp
->cs_cmsdata
= data
;
418 cmi_hdl_setspecific(hdl
, cdp
);
421 mutex_exit(&cms_load_lock
);
425 cms_fini(cmi_hdl_t hdl
)
427 cms_t
*cms
= HDL2CMS(hdl
);
430 if (CMS_OP_PRESENT(cms
, cms_fini
))
431 CMS_OPS(cms
)->cms_fini(hdl
);
433 mutex_enter(&cms_load_lock
);
434 cdp
= (struct cms_ctl
*)cmi_hdl_getspecific(hdl
);
436 if (cdp
->cs_cms
!= NULL
)
437 cms_rele(cdp
->cs_cms
);
438 kmem_free(cdp
, sizeof (*cdp
));
440 mutex_exit(&cms_load_lock
);
444 cms_present(cmi_hdl_t hdl
)
446 return (HDL2CMS(hdl
) != NULL
? B_TRUE
: B_FALSE
);
450 cms_post_startup(cmi_hdl_t hdl
)
452 cms_t
*cms
= HDL2CMS(hdl
);
454 if (CMS_OP_PRESENT(cms
, cms_post_startup
))
455 CMS_OPS(cms
)->cms_post_startup(hdl
);
459 cms_post_mpstartup(cmi_hdl_t hdl
)
461 cms_t
*cms
= HDL2CMS(hdl
);
463 if (CMS_OP_PRESENT(cms
, cms_post_mpstartup
))
464 CMS_OPS(cms
)->cms_post_mpstartup(hdl
);
468 cms_logout_size(cmi_hdl_t hdl
)
470 cms_t
*cms
= HDL2CMS(hdl
);
472 if (!CMS_OP_PRESENT(cms
, cms_logout_size
))
475 return (CMS_OPS(cms
)->cms_logout_size(hdl
));
479 cms_mcgctl_val(cmi_hdl_t hdl
, int nbanks
, uint64_t def
)
481 cms_t
*cms
= HDL2CMS(hdl
);
483 if (!CMS_OP_PRESENT(cms
, cms_mcgctl_val
))
486 return (CMS_OPS(cms
)->cms_mcgctl_val(hdl
, nbanks
, def
));
490 cms_bankctl_skipinit(cmi_hdl_t hdl
, int banknum
)
492 cms_t
*cms
= HDL2CMS(hdl
);
494 if (!CMS_OP_PRESENT(cms
, cms_bankctl_skipinit
))
497 return (CMS_OPS(cms
)->cms_bankctl_skipinit(hdl
, banknum
));
501 cms_bankctl_val(cmi_hdl_t hdl
, int banknum
, uint64_t def
)
503 cms_t
*cms
= HDL2CMS(hdl
);
505 if (!CMS_OP_PRESENT(cms
, cms_bankctl_val
))
508 return (CMS_OPS(cms
)->cms_bankctl_val(hdl
, banknum
, def
));
512 cms_bankstatus_skipinit(cmi_hdl_t hdl
, int banknum
)
514 cms_t
*cms
= HDL2CMS(hdl
);
516 if (!CMS_OP_PRESENT(cms
, cms_bankstatus_skipinit
))
519 return (CMS_OPS(cms
)->cms_bankstatus_skipinit(hdl
, banknum
));
523 cms_bankstatus_val(cmi_hdl_t hdl
, int banknum
, uint64_t def
)
525 cms_t
*cms
= HDL2CMS(hdl
);
527 if (!CMS_OP_PRESENT(cms
, cms_bankstatus_val
))
530 return (CMS_OPS(cms
)->cms_bankstatus_val(hdl
, banknum
, def
));
534 cms_mca_init(cmi_hdl_t hdl
, int nbanks
)
536 cms_t
*cms
= HDL2CMS(hdl
);
538 if (CMS_OP_PRESENT(cms
, cms_mca_init
))
539 CMS_OPS(cms
)->cms_mca_init(hdl
, nbanks
);
543 cms_poll_ownermask(cmi_hdl_t hdl
, hrtime_t poll_interval
)
545 cms_t
*cms
= HDL2CMS(hdl
);
547 if (CMS_OP_PRESENT(cms
, cms_poll_ownermask
))
548 return (CMS_OPS(cms
)->cms_poll_ownermask(hdl
, poll_interval
));
550 return (-1ULL); /* poll all banks by default */
554 cms_bank_logout(cmi_hdl_t hdl
, int banknum
, uint64_t status
, uint64_t addr
,
555 uint64_t misc
, void *mslogout
)
557 cms_t
*cms
= HDL2CMS(hdl
);
559 if (mslogout
!= NULL
&& CMS_OP_PRESENT(cms
, cms_bank_logout
))
560 CMS_OPS(cms
)->cms_bank_logout(hdl
, banknum
, status
, addr
,
565 cms_msrinject(cmi_hdl_t hdl
, uint_t msr
, uint64_t val
)
567 cms_t
*cms
= HDL2CMS(hdl
);
569 if (CMS_OP_PRESENT(cms
, cms_msrinject
))
570 return (CMS_OPS(cms
)->cms_msrinject(hdl
, msr
, val
));
572 return (CMSERR_NOTSUP
);
576 cms_error_action(cmi_hdl_t hdl
, int ismc
, int banknum
, uint64_t status
,
577 uint64_t addr
, uint64_t misc
, void *mslogout
)
579 cms_t
*cms
= HDL2CMS(hdl
);
581 if (CMS_OP_PRESENT(cms
, cms_error_action
))
582 return (CMS_OPS(cms
)->cms_error_action(hdl
, ismc
, banknum
,
583 status
, addr
, misc
, mslogout
));
589 cms_disp_match(cmi_hdl_t hdl
, int ismc
, int banknum
, uint64_t status
,
590 uint64_t addr
, uint64_t misc
, void *mslogout
)
592 cms_t
*cms
= HDL2CMS(hdl
);
594 if (CMS_OP_PRESENT(cms
, cms_disp_match
))
595 return (CMS_OPS(cms
)->cms_disp_match(hdl
, ismc
, banknum
,
596 status
, addr
, misc
, mslogout
));
603 cms_ereport_class(cmi_hdl_t hdl
, cms_cookie_t mscookie
, const char **cpuclsp
,
604 const char **leafclsp
)
606 cms_t
*cms
= HDL2CMS(hdl
);
608 if (cpuclsp
== NULL
|| leafclsp
== NULL
)
611 *cpuclsp
= *leafclsp
= NULL
;
612 if (CMS_OP_PRESENT(cms
, cms_ereport_class
)) {
613 CMS_OPS(cms
)->cms_ereport_class(hdl
, mscookie
, cpuclsp
,
619 cms_ereport_detector(cmi_hdl_t hdl
, int bankno
, cms_cookie_t mscookie
,
622 cms_t
*cms
= HDL2CMS(hdl
);
624 if (CMS_OP_PRESENT(cms
, cms_ereport_detector
))
625 return (CMS_OPS(cms
)->cms_ereport_detector(hdl
, bankno
,
633 cms_ereport_includestack(cmi_hdl_t hdl
, cms_cookie_t mscookie
)
635 cms_t
*cms
= HDL2CMS(hdl
);
637 if (CMS_OP_PRESENT(cms
, cms_ereport_includestack
)) {
638 return (CMS_OPS(cms
)->cms_ereport_includestack(hdl
, mscookie
));
645 cms_ereport_add_logout(cmi_hdl_t hdl
, nvlist_t
*nvl
, nv_alloc_t
*nva
,
646 int banknum
, uint64_t status
, uint64_t addr
, uint64_t misc
, void *mslogout
,
647 cms_cookie_t mscookie
)
649 cms_t
*cms
= HDL2CMS(hdl
);
651 if (CMS_OP_PRESENT(cms
, cms_ereport_add_logout
))
652 CMS_OPS(cms
)->cms_ereport_add_logout(hdl
, nvl
, nva
, banknum
,
653 status
, addr
, misc
, mslogout
, mscookie
);