8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / uts / i86pc / os / cms.c
blobdd3241653571a8f3be418f5708f0ae8aec291789
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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)
63 struct cms_cpuid {
64 const char *vendor;
65 uint_t family;
66 uint_t model;
67 uint_t stepping;
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.
78 typedef struct cms {
79 struct cms *cms_next;
80 struct cms *cms_prev;
81 const cms_ops_t *cms_ops;
82 struct modctl *cms_modp;
83 uint_t cms_refcnt;
84 } cms_t;
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.
92 struct cms_ctl {
93 cms_t *cs_cms;
94 void *cs_cmsdata;
97 static cms_t *
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);
105 void *
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);
113 static void
114 cms_link(cms_t *cms)
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;
122 cms_list = cms;
125 static void
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;
137 if (cms_list == cms)
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.
146 static void
147 cms_hold(cms_t *cms)
149 ASSERT(MUTEX_HELD(&cms_load_lock));
151 mutex_enter(&mod_lock);
152 cms->cms_modp->mod_ref++;
153 mutex_exit(&mod_lock);
154 cms->cms_refcnt++;
157 static void
158 cms_rele(cms_t *cms)
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) {
167 cms_unlink(cms);
168 kmem_free(cms, sizeof (cms_t));
172 static cms_ops_t *
173 cms_getops(modctl_t *modp)
175 cms_ops_t *ops;
177 if ((ops = (cms_ops_t *)modlookup_by_modctl(modp, "_cms_ops")) ==
178 NULL) {
179 cmn_err(CE_WARN, "cpu_ms module '%s' is invalid: no _cms_ops "
180 "found", modp->mod_modname);
181 return (NULL);
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);
187 return (NULL);
190 return (ops);
193 static cms_t *
194 cms_load_modctl(modctl_t *modp)
196 cms_ops_t *ops;
197 uintptr_t ver;
198 cms_t *cms;
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)
205 return (cms);
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);
211 return (NULL);
212 } else {
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);
218 return (NULL);
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));
227 return (NULL);
230 if ((ops = cms_getops(modp)) == NULL)
231 return (NULL);
233 cms = kmem_zalloc(sizeof (cms_t), KM_SLEEP);
234 cms->cms_ops = ops;
235 cms->cms_modp = modp;
237 cms_link(cms);
239 return (cms);
242 static int
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))
247 return (0);
249 if (match >= CMS_MATCH_FAMILY &&
250 cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
251 return (0);
253 if (match >= CMS_MATCH_MODEL &&
254 cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
255 return (0);
257 if (match >= CMS_MATCH_STEPPING &&
258 cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
259 return (0);
261 return (1);
264 static int
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 */
273 *rsltp = whdl;
274 return (CMI_HDL_WALK_DONE);
275 } else {
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.
284 static cms_t *
285 cms_search_list(cmi_hdl_t hdl, int match)
287 cmi_hdl_t dhdl = NULL;
288 cms_t *cms = NULL;
290 ASSERT(MUTEX_HELD(&cms_load_lock));
292 cmi_hdl_walk(cms_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
293 if (dhdl) {
294 cms = HDL2CMS(dhdl);
295 cmi_hdl_rele(dhdl); /* held in cms_search_list_cb */
298 return (cms);
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
307 * on vendor alone.
309 static cms_t *
310 cms_load_module(cmi_hdl_t hdl, int match, int *chosenp)
312 modctl_t *modp;
313 cms_t *cms;
314 int modid;
315 uint_t s[3];
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) {
330 cms_hold(cms);
331 return (cms);
334 modid = modload_qualified(CPUMOD_MS_SUBDIR, CPUMOD_MS_PREFIX,
335 cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
337 if (modid == -1)
338 return (NULL);
340 modp = mod_hold_by_id(modid);
341 cms = cms_load_modctl(modp);
342 if (cms)
343 cms_hold(cms);
344 mod_release_mod(modp);
346 return (cms);
349 static cms_t *
350 cms_load_specific(cmi_hdl_t hdl, void **datap)
352 cms_t *cms;
353 int err;
354 int i;
356 ASSERT(MUTEX_HELD(&cms_load_lock));
358 for (i = CMS_MATCH_STEPPING; i >= CMS_MATCH_VENDOR; i--) {
359 int suffixlevel;
361 if ((cms = cms_load_module(hdl, i, &suffixlevel)) == NULL)
362 return (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 "
373 "strand %d\n",
374 cms->cms_modp->mod_modname,
375 cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
376 cmi_hdl_strandid(hdl));
378 return (cms);
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.
392 cms_rele(cms);
393 i = suffixlevel;
396 return (NULL);
399 void
400 cms_init(cmi_hdl_t hdl)
402 cms_t *cms;
403 void *data;
405 if (cms_no_model_specific != 0)
406 return;
408 mutex_enter(&cms_load_lock);
410 if ((cms = cms_load_specific(hdl, &data)) != NULL) {
411 struct cms_ctl *cdp;
413 ASSERT(cmi_hdl_getspecific(hdl) == NULL);
415 cdp = kmem_alloc(sizeof (*cdp), KM_SLEEP);
416 cdp->cs_cms = cms;
417 cdp->cs_cmsdata = data;
418 cmi_hdl_setspecific(hdl, cdp);
421 mutex_exit(&cms_load_lock);
424 void
425 cms_fini(cmi_hdl_t hdl)
427 cms_t *cms = HDL2CMS(hdl);
428 struct cms_ctl *cdp;
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);
435 if (cdp != NULL) {
436 if (cdp->cs_cms != NULL)
437 cms_rele(cdp->cs_cms);
438 kmem_free(cdp, sizeof (*cdp));
440 mutex_exit(&cms_load_lock);
443 boolean_t
444 cms_present(cmi_hdl_t hdl)
446 return (HDL2CMS(hdl) != NULL ? B_TRUE : B_FALSE);
449 void
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);
458 void
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);
467 size_t
468 cms_logout_size(cmi_hdl_t hdl)
470 cms_t *cms = HDL2CMS(hdl);
472 if (!CMS_OP_PRESENT(cms, cms_logout_size))
473 return (0);
475 return (CMS_OPS(cms)->cms_logout_size(hdl));
478 uint64_t
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))
484 return (def);
486 return (CMS_OPS(cms)->cms_mcgctl_val(hdl, nbanks, def));
489 boolean_t
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))
495 return (B_FALSE);
497 return (CMS_OPS(cms)->cms_bankctl_skipinit(hdl, banknum));
500 uint64_t
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))
506 return (def);
508 return (CMS_OPS(cms)->cms_bankctl_val(hdl, banknum, def));
511 boolean_t
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))
517 return (B_FALSE);
519 return (CMS_OPS(cms)->cms_bankstatus_skipinit(hdl, banknum));
522 uint64_t
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))
528 return (def);
530 return (CMS_OPS(cms)->cms_bankstatus_val(hdl, banknum, def));
533 void
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);
542 uint64_t
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));
549 else
550 return (-1ULL); /* poll all banks by default */
553 void
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,
561 misc, mslogout);
564 cms_errno_t
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));
571 else
572 return (CMSERR_NOTSUP);
575 uint32_t
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));
584 else
585 return (0);
588 cms_cookie_t
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));
597 else
598 return (NULL);
602 void
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)
609 return;
611 *cpuclsp = *leafclsp = NULL;
612 if (CMS_OP_PRESENT(cms, cms_ereport_class)) {
613 CMS_OPS(cms)->cms_ereport_class(hdl, mscookie, cpuclsp,
614 leafclsp);
618 nvlist_t *
619 cms_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie,
620 nv_alloc_t *nva)
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,
626 mscookie, nva));
627 else
628 return (NULL);
632 boolean_t
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));
639 } else {
640 return (B_FALSE);
644 void
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);