preprocessor cleanup: __xpv
[unleashed.git] / arch / x86 / kernel / platform / i86pc / os / cmi.c
blob254b9f763cb4c9599806b63973e0149866f4a1d9
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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Public interface to routines implemented by CPU modules
31 #include <sys/types.h>
32 #include <sys/atomic.h>
33 #include <sys/x86_archext.h>
34 #include <sys/cpu_module_impl.h>
35 #include <sys/cpu_module_ms.h>
36 #include <sys/fm/util.h>
37 #include <sys/reboot.h>
38 #include <sys/modctl.h>
39 #include <sys/param.h>
40 #include <sys/cmn_err.h>
41 #include <sys/systm.h>
42 #include <sys/fm/protocol.h>
43 #include <sys/pcb.h>
44 #include <sys/ontrap.h>
45 #include <sys/psw.h>
46 #include <sys/privregs.h>
47 #include <sys/machsystm.h>
50 * Set to force cmi_init to fail.
52 int cmi_no_init = 0;
55 * Set to avoid MCA initialization.
57 int cmi_no_mca_init = 0;
60 * If cleared for debugging we will not attempt to load a model-specific
61 * cpu module but will load the generic cpu module instead.
63 int cmi_force_generic = 0;
66 * If cleared for debugging, we will suppress panicking on fatal hardware
67 * errors. This should *only* be used for debugging; it use can and will
68 * cause data corruption if actual hardware errors are detected by the system.
70 int cmi_panic_on_uncorrectable_error = 1;
73 * Set to indicate whether we are able to enable cmci interrupt.
75 int cmi_enable_cmci = 0;
78 * Subdirectory (relative to the module search path) in which we will
79 * look for cpu modules.
81 #define CPUMOD_SUBDIR "cpu"
84 * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and
85 * "cpu.generic" - the "cpu" prefix is specified by the following.
87 #define CPUMOD_PREFIX "cpu"
90 * Structure used to keep track of cpu modules we have loaded and their ops
92 typedef struct cmi {
93 struct cmi *cmi_next;
94 struct cmi *cmi_prev;
95 const cmi_ops_t *cmi_ops;
96 struct modctl *cmi_modp;
97 uint_t cmi_refcnt;
98 } cmi_t;
100 static cmi_t *cmi_list;
101 static const cmi_mc_ops_t *cmi_mc_global_ops;
102 static void *cmi_mc_global_data;
103 static kmutex_t cmi_load_lock;
106 * Functions we need from cmi_hw.c that are not part of the cpu_module.h
107 * interface.
109 extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t);
110 extern void cmi_hdl_destroy(cmi_hdl_t ophdl);
111 extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *);
112 extern void *cmi_hdl_getcmi(cmi_hdl_t);
113 extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *);
114 extern void cmi_hdl_inj_begin(cmi_hdl_t);
115 extern void cmi_hdl_inj_end(cmi_hdl_t);
116 extern void cmi_read_smbios(cmi_hdl_t);
118 #define HDL2CMI(hdl) cmi_hdl_getcmi(hdl)
120 #define CMI_OPS(cmi) (cmi)->cmi_ops
121 #define CMI_OP_PRESENT(cmi, op) ((cmi) && CMI_OPS(cmi)->op != NULL)
123 #define CMI_MATCH_VENDOR 0 /* Just match on vendor */
124 #define CMI_MATCH_FAMILY 1 /* Match down to family */
125 #define CMI_MATCH_MODEL 2 /* Match down to model */
126 #define CMI_MATCH_STEPPING 3 /* Match down to stepping */
128 static void
129 cmi_link(cmi_t *cmi)
131 ASSERT(MUTEX_HELD(&cmi_load_lock));
133 cmi->cmi_prev = NULL;
134 cmi->cmi_next = cmi_list;
135 if (cmi_list != NULL)
136 cmi_list->cmi_prev = cmi;
137 cmi_list = cmi;
140 static void
141 cmi_unlink(cmi_t *cmi)
143 ASSERT(MUTEX_HELD(&cmi_load_lock));
144 ASSERT(cmi->cmi_refcnt == 0);
146 if (cmi->cmi_prev != NULL)
147 cmi->cmi_prev = cmi->cmi_next;
149 if (cmi->cmi_next != NULL)
150 cmi->cmi_next->cmi_prev = cmi->cmi_prev;
152 if (cmi_list == cmi)
153 cmi_list = cmi->cmi_next;
157 * Hold the module in memory. We call to CPU modules without using the
158 * stubs mechanism, so these modules must be manually held in memory.
159 * The mod_ref acts as if another loaded module has a dependency on us.
161 static void
162 cmi_hold(cmi_t *cmi)
164 ASSERT(MUTEX_HELD(&cmi_load_lock));
166 mutex_enter(&mod_lock);
167 cmi->cmi_modp->mod_ref++;
168 mutex_exit(&mod_lock);
169 cmi->cmi_refcnt++;
172 static void
173 cmi_rele(cmi_t *cmi)
175 ASSERT(MUTEX_HELD(&cmi_load_lock));
177 mutex_enter(&mod_lock);
178 cmi->cmi_modp->mod_ref--;
179 mutex_exit(&mod_lock);
181 if (--cmi->cmi_refcnt == 0) {
182 cmi_unlink(cmi);
183 kmem_free(cmi, sizeof (cmi_t));
187 static cmi_ops_t *
188 cmi_getops(modctl_t *modp)
190 cmi_ops_t *ops;
192 if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) ==
193 NULL) {
194 cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops "
195 "found", modp->mod_modname);
196 return (NULL);
199 if (ops->cmi_init == NULL) {
200 cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init "
201 "entry point", modp->mod_modname);
202 return (NULL);
205 return (ops);
208 static cmi_t *
209 cmi_load_modctl(modctl_t *modp)
211 cmi_ops_t *ops;
212 uintptr_t ver;
213 cmi_t *cmi;
214 cmi_api_ver_t apiver;
216 ASSERT(MUTEX_HELD(&cmi_load_lock));
218 for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) {
219 if (cmi->cmi_modp == modp)
220 return (cmi);
223 if ((ver = modlookup_by_modctl(modp, "_cmi_api_version"))
224 == (uintptr_t)NULL) {
226 * Apparently a cpu module before versioning was introduced -
227 * we call this version 0.
229 apiver = CMI_API_VERSION_0;
230 } else {
231 apiver = *((cmi_api_ver_t *)ver);
232 if (!CMI_API_VERSION_CHKMAGIC(apiver)) {
233 cmn_err(CE_WARN, "cpu module '%s' is invalid: "
234 "_cmi_api_version 0x%x has bad magic",
235 modp->mod_modname, apiver);
236 return (NULL);
240 if (apiver != CMI_API_VERSION) {
241 cmn_err(CE_WARN, "cpu module '%s' has API version %d, "
242 "kernel requires API version %d", modp->mod_modname,
243 CMI_API_VERSION_TOPRINT(apiver),
244 CMI_API_VERSION_TOPRINT(CMI_API_VERSION));
245 return (NULL);
248 if ((ops = cmi_getops(modp)) == NULL)
249 return (NULL);
251 cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP);
252 cmi->cmi_ops = ops;
253 cmi->cmi_modp = modp;
255 cmi_link(cmi);
257 return (cmi);
260 static int
261 cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match)
263 if (match >= CMI_MATCH_VENDOR &&
264 cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2))
265 return (0);
267 if (match >= CMI_MATCH_FAMILY &&
268 cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
269 return (0);
271 if (match >= CMI_MATCH_MODEL &&
272 cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
273 return (0);
275 if (match >= CMI_MATCH_STEPPING &&
276 cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
277 return (0);
279 return (1);
282 static int
283 cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3)
285 cmi_hdl_t thdl = (cmi_hdl_t)arg1;
286 int match = *((int *)arg2);
287 cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3;
289 if (cmi_cpu_match(thdl, whdl, match)) {
290 cmi_hdl_hold(whdl); /* short-term hold */
291 *rsltp = whdl;
292 return (CMI_HDL_WALK_DONE);
293 } else {
294 return (CMI_HDL_WALK_NEXT);
298 static cmi_t *
299 cmi_search_list(cmi_hdl_t hdl, int match)
301 cmi_hdl_t dhdl = NULL;
302 cmi_t *cmi = NULL;
304 ASSERT(MUTEX_HELD(&cmi_load_lock));
306 cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
307 if (dhdl) {
308 cmi = HDL2CMI(dhdl);
309 cmi_hdl_rele(dhdl); /* held in cmi_search_list_cb */
312 return (cmi);
315 static cmi_t *
316 cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp)
318 modctl_t *modp;
319 cmi_t *cmi;
320 int modid;
321 uint_t s[3];
323 ASSERT(MUTEX_HELD(&cmi_load_lock));
324 ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL ||
325 match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR);
328 * Have we already loaded a module for a cpu with the same
329 * vendor/family/model/stepping?
331 if ((cmi = cmi_search_list(hdl, match)) != NULL) {
332 cmi_hold(cmi);
333 return (cmi);
336 s[0] = cmi_hdl_family(hdl);
337 s[1] = cmi_hdl_model(hdl);
338 s[2] = cmi_hdl_stepping(hdl);
339 modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX,
340 cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
342 if (modid == -1)
343 return (NULL);
345 modp = mod_hold_by_id(modid);
346 cmi = cmi_load_modctl(modp);
347 if (cmi)
348 cmi_hold(cmi);
349 mod_release_mod(modp);
351 return (cmi);
355 * Try to load a cpu module with specific support for this chip type.
357 static cmi_t *
358 cmi_load_specific(cmi_hdl_t hdl, void **datap)
360 cmi_t *cmi;
361 int err;
362 int i;
364 ASSERT(MUTEX_HELD(&cmi_load_lock));
366 for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) {
367 int suffixlevel;
369 if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL)
370 return (NULL);
373 * A module has loaded and has a _cmi_ops structure, and the
374 * module has been held for this instance. Call its cmi_init
375 * entry point - we expect success (0) or ENOTSUP.
377 if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) {
378 if (boothowto & RB_VERBOSE) {
379 printf("initialized cpu module '%s' on "
380 "chip %d core %d strand %d\n",
381 cmi->cmi_modp->mod_modname,
382 cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
383 cmi_hdl_strandid(hdl));
385 return (cmi);
386 } else if (err != ENOTSUP) {
387 cmn_err(CE_WARN, "failed to init cpu module '%s' on "
388 "chip %d core %d strand %d: err=%d\n",
389 cmi->cmi_modp->mod_modname,
390 cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
391 cmi_hdl_strandid(hdl), err);
395 * The module failed or declined to init, so release
396 * it and update i to be equal to the number
397 * of suffices actually used in the last module path.
399 cmi_rele(cmi);
400 i = suffixlevel;
403 return (NULL);
407 * Load the generic IA32 MCA cpu module, which may still supplement
408 * itself with model-specific support through cpu model-specific modules.
410 static cmi_t *
411 cmi_load_generic(cmi_hdl_t hdl, void **datap)
413 modctl_t *modp;
414 cmi_t *cmi;
415 int modid;
416 int err;
418 ASSERT(MUTEX_HELD(&cmi_load_lock));
420 if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1)
421 return (NULL);
423 modp = mod_hold_by_id(modid);
424 cmi = cmi_load_modctl(modp);
425 if (cmi)
426 cmi_hold(cmi);
427 mod_release_mod(modp);
429 if (cmi == NULL)
430 return (NULL);
432 if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) {
433 if (err != ENOTSUP)
434 cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to "
435 "init: err=%d", err);
436 cmi_rele(cmi);
437 return (NULL);
440 return (cmi);
443 cmi_hdl_t
444 cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
445 uint_t strandid)
447 cmi_t *cmi = NULL;
448 cmi_hdl_t hdl;
449 void *data;
451 if (cmi_no_init) {
452 cmi_no_mca_init = 1;
453 return (NULL);
456 mutex_enter(&cmi_load_lock);
458 if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) {
459 mutex_exit(&cmi_load_lock);
460 cmn_err(CE_WARN, "There will be no MCA support on chip %d "
461 "core %d strand %d (cmi_hdl_create returned NULL)\n",
462 chipid, coreid, strandid);
463 return (NULL);
466 if (!cmi_force_generic)
467 cmi = cmi_load_specific(hdl, &data);
469 if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) {
470 cmn_err(CE_WARN, "There will be no MCA support on chip %d "
471 "core %d strand %d\n", chipid, coreid, strandid);
472 cmi_hdl_rele(hdl);
473 mutex_exit(&cmi_load_lock);
474 return (NULL);
477 cmi_hdl_setcmi(hdl, cmi, data);
479 cms_init(hdl);
481 cmi_read_smbios(hdl);
483 mutex_exit(&cmi_load_lock);
485 return (hdl);
489 * cmi_fini is called on DR deconfigure of a cpu resource.
490 * It should not be called at simple offline of a cpu.
492 void
493 cmi_fini(cmi_hdl_t hdl)
495 cmi_t *cmi = HDL2CMI(hdl);
497 if (cms_present(hdl))
498 cms_fini(hdl);
500 if (CMI_OP_PRESENT(cmi, cmi_fini))
501 CMI_OPS(cmi)->cmi_fini(hdl);
503 cmi_hdl_destroy(hdl);
507 * cmi_post_startup is called from post_startup for the boot cpu only (no
508 * other cpus are started yet).
510 void
511 cmi_post_startup(void)
513 cmi_hdl_t hdl;
514 cmi_t *cmi;
516 if (cmi_no_mca_init != 0 ||
517 (hdl = cmi_hdl_any()) == NULL) /* short-term hold */
518 return;
520 cmi = HDL2CMI(hdl);
522 if (CMI_OP_PRESENT(cmi, cmi_post_startup))
523 CMI_OPS(cmi)->cmi_post_startup(hdl);
525 cmi_hdl_rele(hdl);
529 * Called just once from start_other_cpus when all processors are started.
530 * This will not be called for each cpu, so the registered op must not
531 * assume it is called as such. We are not necessarily executing on
532 * the boot cpu.
534 void
535 cmi_post_mpstartup(void)
537 cmi_hdl_t hdl;
538 cmi_t *cmi;
540 if (cmi_no_mca_init != 0 ||
541 (hdl = cmi_hdl_any()) == NULL) /* short-term hold */
542 return;
544 cmi = HDL2CMI(hdl);
546 if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup))
547 CMI_OPS(cmi)->cmi_post_mpstartup(hdl);
549 cmi_hdl_rele(hdl);
552 void
553 cmi_faulted_enter(cmi_hdl_t hdl)
555 cmi_t *cmi = HDL2CMI(hdl);
557 if (cmi_no_mca_init != 0)
558 return;
560 if (CMI_OP_PRESENT(cmi, cmi_faulted_enter))
561 CMI_OPS(cmi)->cmi_faulted_enter(hdl);
564 void
565 cmi_faulted_exit(cmi_hdl_t hdl)
567 cmi_t *cmi = HDL2CMI(hdl);
569 if (cmi_no_mca_init != 0)
570 return;
572 if (CMI_OP_PRESENT(cmi, cmi_faulted_exit))
573 CMI_OPS(cmi)->cmi_faulted_exit(hdl);
576 void
577 cmi_mca_init(cmi_hdl_t hdl)
579 cmi_t *cmi;
581 if (cmi_no_mca_init != 0)
582 return;
584 cmi = HDL2CMI(hdl);
586 if (CMI_OP_PRESENT(cmi, cmi_mca_init))
587 CMI_OPS(cmi)->cmi_mca_init(hdl);
590 #define CMI_RESPONSE_PANIC 0x0 /* panic must have value 0 */
591 #define CMI_RESPONSE_NONE 0x1
592 #define CMI_RESPONSE_CKILL 0x2
593 #define CMI_RESPONSE_REBOOT 0x3 /* not implemented */
594 #define CMI_RESPONSE_ONTRAP_PROT 0x4
595 #define CMI_RESPONSE_LOFAULT_PROT 0x5
598 * Return 0 if we will panic in response to this machine check, otherwise
599 * non-zero. If the caller is cmi_mca_trap in this file then the nonzero
600 * return values are to be interpreted from CMI_RESPONSE_* above.
602 * This function must just return what will be done without actually
603 * doing anything; this includes not changing the regs.
606 cmi_mce_response(struct regs *rp, uint64_t disp)
608 int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC :
609 CMI_RESPONSE_NONE;
610 on_trap_data_t *otp;
612 ASSERT(rp != NULL); /* don't call for polling, only on #MC */
615 * If no bits are set in the disposition then there is nothing to
616 * worry about and we do not need to trampoline to ontrap or
617 * lofault handlers.
619 if (disp == 0)
620 return (CMI_RESPONSE_NONE);
623 * Unconstrained errors cannot be forgiven, even by ontrap or
624 * lofault protection. The data is not poisoned and may not
625 * even belong to the trapped context - eg a writeback of
626 * data that is found to be bad.
628 if (disp & CMI_ERRDISP_UC_UNCONSTRAINED)
629 return (panicrsp);
632 * ontrap OT_DATA_EC and lofault protection forgive any disposition
633 * other than unconstrained, even those normally forced fatal.
635 if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC)
636 return (CMI_RESPONSE_ONTRAP_PROT);
637 else if (curthread->t_lofault)
638 return (CMI_RESPONSE_LOFAULT_PROT);
641 * Forced-fatal errors are terminal even in user mode.
643 if (disp & CMI_ERRDISP_FORCEFATAL)
644 return (panicrsp);
647 * If the trapped context is corrupt or we have no instruction pointer
648 * to resume at (and aren't trampolining to a fault handler)
649 * then in the kernel case we must panic and in usermode we
650 * kill the affected contract.
652 if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID))
653 return (USERMODE(rp->r_cs) ? CMI_RESPONSE_CKILL : panicrsp);
656 * Anything else is harmless
658 return (CMI_RESPONSE_NONE);
661 int cma_mca_trap_panic_suppressed = 0;
663 static void
664 cmi_mca_panic(void)
666 if (cmi_panic_on_uncorrectable_error) {
667 fm_panic("Unrecoverable Machine-Check Exception");
668 } else {
669 cmn_err(CE_WARN, "suppressing panic from fatal #mc");
670 cma_mca_trap_panic_suppressed++;
675 int cma_mca_trap_contract_kills = 0;
676 int cma_mca_trap_ontrap_forgiven = 0;
677 int cma_mca_trap_lofault_forgiven = 0;
680 * Native #MC handler - we branch to here from mcetrap
682 /*ARGSUSED*/
683 void
684 cmi_mca_trap(struct regs *rp)
686 cmi_hdl_t hdl = NULL;
687 uint64_t disp;
688 cmi_t *cmi;
689 int s;
691 if (cmi_no_mca_init != 0)
692 return;
695 * This function can call cmn_err, and the cpu module cmi_mca_trap
696 * entry point may also elect to call cmn_err (e.g., if it can't
697 * log the error onto an errorq, say very early in boot).
698 * We need to let cprintf know that we must not block.
700 s = spl8();
702 if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
703 cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
704 (cmi = HDL2CMI(hdl)) == NULL ||
705 !CMI_OP_PRESENT(cmi, cmi_mca_trap)) {
707 cmn_err(CE_WARN, "#MC exception on cpuid %d: %s",
708 CPU->cpu_id,
709 hdl ? "handle lookup ok but no #MC handler found" :
710 "handle lookup failed");
712 if (hdl != NULL)
713 cmi_hdl_rele(hdl);
715 splx(s);
716 return;
719 disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp);
721 switch (cmi_mce_response(rp, disp)) {
722 default:
723 cmn_err(CE_WARN, "Invalid response from cmi_mce_response");
724 /*FALLTHRU*/
726 case CMI_RESPONSE_PANIC:
727 cmi_mca_panic();
728 break;
730 case CMI_RESPONSE_NONE:
731 break;
733 case CMI_RESPONSE_CKILL:
734 ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR;
735 aston(curthread);
736 cma_mca_trap_contract_kills++;
737 break;
739 case CMI_RESPONSE_ONTRAP_PROT: {
740 on_trap_data_t *otp = curthread->t_ontrap;
741 otp->ot_trap = OT_DATA_EC;
742 rp->r_pc = otp->ot_trampoline;
743 cma_mca_trap_ontrap_forgiven++;
744 break;
747 case CMI_RESPONSE_LOFAULT_PROT:
748 rp->r_r0 = EFAULT;
749 rp->r_pc = curthread->t_lofault;
750 cma_mca_trap_lofault_forgiven++;
751 break;
754 cmi_hdl_rele(hdl);
755 splx(s);
758 void
759 cmi_hdl_poke(cmi_hdl_t hdl)
761 cmi_t *cmi = HDL2CMI(hdl);
763 if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke))
764 return;
766 CMI_OPS(cmi)->cmi_hdl_poke(hdl);
769 void
770 cmi_cmci_trap()
772 cmi_hdl_t hdl = NULL;
773 cmi_t *cmi;
775 if (cmi_no_mca_init != 0)
776 return;
778 if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
779 cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
780 (cmi = HDL2CMI(hdl)) == NULL ||
781 !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) {
783 cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s",
784 CPU->cpu_id,
785 hdl ? "handle lookup ok but no CMCI handler found" :
786 "handle lookup failed");
788 if (hdl != NULL)
789 cmi_hdl_rele(hdl);
791 return;
794 CMI_OPS(cmi)->cmi_cmci_trap(hdl);
796 cmi_hdl_rele(hdl);
799 void
800 cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata)
802 if (!cmi_no_mca_init)
803 cmi_hdl_setmc(hdl, mcops, mcdata);
806 cmi_errno_t
807 cmi_mc_register_global(const cmi_mc_ops_t *mcops, void *mcdata)
809 if (!cmi_no_mca_init) {
810 if (cmi_mc_global_ops != NULL || cmi_mc_global_data != NULL ||
811 mcops == NULL || mcops->cmi_mc_patounum == NULL ||
812 mcops->cmi_mc_unumtopa == NULL) {
813 return (CMIERR_UNKNOWN);
815 cmi_mc_global_data = mcdata;
816 cmi_mc_global_ops = mcops;
818 return (CMI_SUCCESS);
821 void
822 cmi_mc_sw_memscrub_disable(void)
824 memscrub_disable();
827 cmi_errno_t
828 cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd,
829 int syndtype, mc_unum_t *up)
831 const struct cmi_mc_ops *mcops;
832 cmi_hdl_t hdl;
833 cmi_errno_t rv;
835 if (cmi_no_mca_init)
836 return (CMIERR_MC_ABSENT);
838 if (cmi_mc_global_ops != NULL) {
839 if (cmi_mc_global_ops->cmi_mc_patounum == NULL)
840 return (CMIERR_MC_NOTSUP);
841 return (cmi_mc_global_ops->cmi_mc_patounum(cmi_mc_global_data,
842 pa, valid_hi, valid_lo, synd, syndtype, up));
845 if ((hdl = cmi_hdl_any()) == NULL) /* short-term hold */
846 return (CMIERR_MC_ABSENT);
848 if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
849 mcops->cmi_mc_patounum == NULL) {
850 cmi_hdl_rele(hdl);
851 return (CMIERR_MC_NOTSUP);
854 rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi,
855 valid_lo, synd, syndtype, up);
857 cmi_hdl_rele(hdl);
859 return (rv);
862 cmi_errno_t
863 cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap)
865 const struct cmi_mc_ops *mcops;
866 cmi_hdl_t hdl;
867 cmi_errno_t rv;
868 nvlist_t *hcsp;
870 if (up != NULL && nvl != NULL)
871 return (CMIERR_API); /* convert from just one form */
873 if (cmi_no_mca_init)
874 return (CMIERR_MC_ABSENT);
876 if (cmi_mc_global_ops != NULL) {
877 if (cmi_mc_global_ops->cmi_mc_unumtopa == NULL)
878 return (CMIERR_MC_NOTSUP);
879 return (cmi_mc_global_ops->cmi_mc_unumtopa(cmi_mc_global_data,
880 up, nvl, pap));
883 if ((hdl = cmi_hdl_any()) == NULL) /* short-term hold */
884 return (CMIERR_MC_ABSENT);
886 if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
887 mcops->cmi_mc_unumtopa == NULL) {
888 cmi_hdl_rele(hdl);
890 if (nvl != NULL && nvlist_lookup_nvlist(nvl,
891 FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
892 (nvlist_lookup_uint64(hcsp,
893 "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, pap) == 0 ||
894 nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
895 pap) == 0)) {
896 return (CMIERR_MC_PARTIALUNUMTOPA);
897 } else {
898 return (mcops && mcops->cmi_mc_unumtopa == NULL ?
899 CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT);
903 rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap);
905 cmi_hdl_rele(hdl);
907 return (rv);
910 void
911 cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync)
913 const struct cmi_mc_ops *mcops;
915 if (cmi_no_mca_init)
916 return;
918 if (cmi_mc_global_ops != NULL)
919 mcops = cmi_mc_global_ops;
920 else
921 mcops = cmi_hdl_getmcops(hdl);
923 if (mcops != NULL && mcops->cmi_mc_logout != NULL)
924 mcops->cmi_mc_logout(hdl, ismc, sync);
927 cmi_errno_t
928 cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs,
929 int force)
931 cmi_t *cmi = cmi_hdl_getcmi(hdl);
932 cmi_errno_t rc;
934 if (!CMI_OP_PRESENT(cmi, cmi_msrinject))
935 return (CMIERR_NOTSUP);
937 cmi_hdl_inj_begin(hdl);
938 rc = CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force);
939 cmi_hdl_inj_end(hdl);
941 return (rc);
944 boolean_t
945 cmi_panic_on_ue(void)
947 return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE);
950 void
951 cmi_panic_callback(void)
953 cmi_hdl_t hdl;
954 cmi_t *cmi;
956 if (cmi_no_mca_init || (hdl = cmi_hdl_any()) == NULL)
957 return;
959 cmi = cmi_hdl_getcmi(hdl);
960 if (CMI_OP_PRESENT(cmi, cmi_panic_callback))
961 CMI_OPS(cmi)->cmi_panic_callback();
963 cmi_hdl_rele(hdl);