xref: /titanic_50/usr/src/uts/i86pc/os/cmi.c (revision 95dd938966e7f45c67d0003e88ead5f5f2ddaecb)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Public interface to routines implemented by CPU modules
29  */
30 
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 
48 /*
49  * Set to force cmi_init to fail.
50  */
51 int cmi_no_init = 0;
52 
53 /*
54  * Set to avoid MCA initialization.
55  */
56 int cmi_no_mca_init = 0;
57 
58 /*
59  * If cleared for debugging we will not attempt to load a model-specific
60  * cpu module but will load the generic cpu module instead.
61  */
62 int cmi_force_generic = 0;
63 
64 /*
65  * If cleared for debugging, we will suppress panicking on fatal hardware
66  * errors.  This should *only* be used for debugging; it use can and will
67  * cause data corruption if actual hardware errors are detected by the system.
68  */
69 int cmi_panic_on_uncorrectable_error = 1;
70 
71 /*
72  * Set to indicate whether we are able to enable cmci interrupt.
73  */
74 int cmi_enable_cmci = 0;
75 
76 /*
77  * Subdirectory (relative to the module search path) in which we will
78  * look for cpu modules.
79  */
80 #define	CPUMOD_SUBDIR	"cpu"
81 
82 /*
83  * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and
84  * "cpu.generic" - the "cpu" prefix is specified by the following.
85  */
86 #define	CPUMOD_PREFIX	"cpu"
87 
88 /*
89  * Structure used to keep track of cpu modules we have loaded and their ops
90  */
91 typedef struct cmi {
92 	struct cmi *cmi_next;
93 	struct cmi *cmi_prev;
94 	const cmi_ops_t *cmi_ops;
95 	struct modctl *cmi_modp;
96 	uint_t cmi_refcnt;
97 } cmi_t;
98 
99 static cmi_t *cmi_list;
100 static kmutex_t cmi_load_lock;
101 
102 /*
103  * Functions we need from cmi_hw.c that are not part of the cpu_module.h
104  * interface.
105  */
106 extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t,
107     boolean_t);
108 extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *);
109 extern void *cmi_hdl_getcmi(cmi_hdl_t);
110 extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *);
111 
112 #define	HDL2CMI(hdl)		cmi_hdl_getcmi(hdl)
113 
114 #define	CMI_OPS(cmi)		(cmi)->cmi_ops
115 #define	CMI_OP_PRESENT(cmi, op)	((cmi) && CMI_OPS(cmi)->op != NULL)
116 
117 #define	CMI_MATCH_VENDOR	0	/* Just match on vendor */
118 #define	CMI_MATCH_FAMILY	1	/* Match down to family */
119 #define	CMI_MATCH_MODEL		2	/* Match down to model */
120 #define	CMI_MATCH_STEPPING	3	/* Match down to stepping */
121 
122 static void
123 cmi_link(cmi_t *cmi)
124 {
125 	ASSERT(MUTEX_HELD(&cmi_load_lock));
126 
127 	cmi->cmi_prev = NULL;
128 	cmi->cmi_next = cmi_list;
129 	if (cmi_list != NULL)
130 		cmi_list->cmi_prev = cmi;
131 	cmi_list = cmi;
132 }
133 
134 static void
135 cmi_unlink(cmi_t *cmi)
136 {
137 	ASSERT(MUTEX_HELD(&cmi_load_lock));
138 	ASSERT(cmi->cmi_refcnt == 0);
139 
140 	if (cmi->cmi_prev != NULL)
141 		cmi->cmi_prev = cmi->cmi_next;
142 
143 	if (cmi->cmi_next != NULL)
144 		cmi->cmi_next->cmi_prev = cmi->cmi_prev;
145 
146 	if (cmi_list == cmi)
147 		cmi_list = cmi->cmi_next;
148 }
149 
150 /*
151  * Hold the module in memory.  We call to CPU modules without using the
152  * stubs mechanism, so these modules must be manually held in memory.
153  * The mod_ref acts as if another loaded module has a dependency on us.
154  */
155 static void
156 cmi_hold(cmi_t *cmi)
157 {
158 	ASSERT(MUTEX_HELD(&cmi_load_lock));
159 
160 	mutex_enter(&mod_lock);
161 	cmi->cmi_modp->mod_ref++;
162 	mutex_exit(&mod_lock);
163 	cmi->cmi_refcnt++;
164 }
165 
166 static void
167 cmi_rele(cmi_t *cmi)
168 {
169 	ASSERT(MUTEX_HELD(&cmi_load_lock));
170 
171 	mutex_enter(&mod_lock);
172 	cmi->cmi_modp->mod_ref--;
173 	mutex_exit(&mod_lock);
174 
175 	if (--cmi->cmi_refcnt == 0) {
176 		cmi_unlink(cmi);
177 		kmem_free(cmi, sizeof (cmi_t));
178 	}
179 }
180 
181 static cmi_ops_t *
182 cmi_getops(modctl_t *modp)
183 {
184 	cmi_ops_t *ops;
185 
186 	if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) ==
187 	    NULL) {
188 		cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops "
189 		    "found", modp->mod_modname);
190 		return (NULL);
191 	}
192 
193 	if (ops->cmi_init == NULL) {
194 		cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init "
195 		    "entry point", modp->mod_modname);
196 		return (NULL);
197 	}
198 
199 	return (ops);
200 }
201 
202 static cmi_t *
203 cmi_load_modctl(modctl_t *modp)
204 {
205 	cmi_ops_t *ops;
206 	uintptr_t ver;
207 	cmi_t *cmi;
208 	cmi_api_ver_t apiver;
209 
210 	ASSERT(MUTEX_HELD(&cmi_load_lock));
211 
212 	for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) {
213 		if (cmi->cmi_modp == modp)
214 			return (cmi);
215 	}
216 
217 	if ((ver = modlookup_by_modctl(modp, "_cmi_api_version")) == NULL) {
218 		/*
219 		 * Apparently a cpu module before versioning was introduced -
220 		 * we call this version 0.
221 		 */
222 		apiver = CMI_API_VERSION_0;
223 	} else {
224 		apiver = *((cmi_api_ver_t *)ver);
225 		if (!CMI_API_VERSION_CHKMAGIC(apiver)) {
226 			cmn_err(CE_WARN, "cpu module '%s' is invalid: "
227 			    "_cmi_api_version 0x%x has bad magic",
228 			    modp->mod_modname, apiver);
229 			return (NULL);
230 		}
231 	}
232 
233 	if (apiver != CMI_API_VERSION) {
234 		cmn_err(CE_WARN, "cpu module '%s' has API version %d, "
235 		    "kernel requires API version %d", modp->mod_modname,
236 		    CMI_API_VERSION_TOPRINT(apiver),
237 		    CMI_API_VERSION_TOPRINT(CMI_API_VERSION));
238 		return (NULL);
239 	}
240 
241 	if ((ops = cmi_getops(modp)) == NULL)
242 		return (NULL);
243 
244 	cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP);
245 	cmi->cmi_ops = ops;
246 	cmi->cmi_modp = modp;
247 
248 	cmi_link(cmi);
249 
250 	return (cmi);
251 }
252 
253 static int
254 cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match)
255 {
256 	if (match >= CMI_MATCH_VENDOR &&
257 	    cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2))
258 		return (0);
259 
260 	if (match >= CMI_MATCH_FAMILY &&
261 	    cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
262 		return (0);
263 
264 	if (match >= CMI_MATCH_MODEL &&
265 	    cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
266 		return (0);
267 
268 	if (match >= CMI_MATCH_STEPPING &&
269 	    cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
270 		return (0);
271 
272 	return (1);
273 }
274 
275 static int
276 cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3)
277 {
278 	cmi_hdl_t thdl = (cmi_hdl_t)arg1;
279 	int match = *((int *)arg2);
280 	cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3;
281 
282 	if (cmi_cpu_match(thdl, whdl, match)) {
283 		cmi_hdl_hold(whdl);	/* short-term hold */
284 		*rsltp = whdl;
285 		return (CMI_HDL_WALK_DONE);
286 	} else {
287 		return (CMI_HDL_WALK_NEXT);
288 	}
289 }
290 
291 static cmi_t *
292 cmi_search_list(cmi_hdl_t hdl, int match)
293 {
294 	cmi_hdl_t dhdl = NULL;
295 	cmi_t *cmi = NULL;
296 
297 	ASSERT(MUTEX_HELD(&cmi_load_lock));
298 
299 	cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
300 	if (dhdl) {
301 		cmi = HDL2CMI(dhdl);
302 		cmi_hdl_rele(dhdl);	/* held in cmi_search_list_cb */
303 	}
304 
305 	return (cmi);
306 }
307 
308 static cmi_t *
309 cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp)
310 {
311 	modctl_t *modp;
312 	cmi_t *cmi;
313 	int modid;
314 	uint_t s[3];
315 
316 	ASSERT(MUTEX_HELD(&cmi_load_lock));
317 	ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL ||
318 	    match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR);
319 
320 	/*
321 	 * Have we already loaded a module for a cpu with the same
322 	 * vendor/family/model/stepping?
323 	 */
324 	if ((cmi = cmi_search_list(hdl, match)) != NULL) {
325 		cmi_hold(cmi);
326 		return (cmi);
327 	}
328 
329 	s[0] = cmi_hdl_family(hdl);
330 	s[1] = cmi_hdl_model(hdl);
331 	s[2] = cmi_hdl_stepping(hdl);
332 	modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX,
333 	    cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
334 
335 	if (modid == -1)
336 		return (NULL);
337 
338 	modp = mod_hold_by_id(modid);
339 	cmi = cmi_load_modctl(modp);
340 	if (cmi)
341 		cmi_hold(cmi);
342 	mod_release_mod(modp);
343 
344 	return (cmi);
345 }
346 
347 /*
348  * Try to load a cpu module with specific support for this chip type.
349  */
350 static cmi_t *
351 cmi_load_specific(cmi_hdl_t hdl, void **datap)
352 {
353 	cmi_t *cmi;
354 	int err;
355 	int i;
356 
357 	ASSERT(MUTEX_HELD(&cmi_load_lock));
358 
359 	for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) {
360 		int suffixlevel;
361 
362 		if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL)
363 			return (NULL);
364 
365 		/*
366 		 * A module has loaded and has a _cmi_ops structure, and the
367 		 * module has been held for this instance.  Call its cmi_init
368 		 * entry point - we expect success (0) or ENOTSUP.
369 		 */
370 		if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) {
371 			if (boothowto & RB_VERBOSE) {
372 				printf("initialized cpu module '%s' on "
373 				    "chip %d core %d strand %d\n",
374 				    cmi->cmi_modp->mod_modname,
375 				    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
376 				    cmi_hdl_strandid(hdl));
377 			}
378 			return (cmi);
379 		} else if (err != ENOTSUP) {
380 			cmn_err(CE_WARN, "failed to init cpu module '%s' on "
381 			    "chip %d core %d strand %d: err=%d\n",
382 			    cmi->cmi_modp->mod_modname,
383 			    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
384 			    cmi_hdl_strandid(hdl), err);
385 		}
386 
387 		/*
388 		 * The module failed or declined to init, so release
389 		 * it and update i to be equal to the number
390 		 * of suffices actually used in the last module path.
391 		 */
392 		cmi_rele(cmi);
393 		i = suffixlevel;
394 	}
395 
396 	return (NULL);
397 }
398 
399 /*
400  * Load the generic IA32 MCA cpu module, which may still supplement
401  * itself with model-specific support through cpu model-specific modules.
402  */
403 static cmi_t *
404 cmi_load_generic(cmi_hdl_t hdl, void **datap)
405 {
406 	modctl_t *modp;
407 	cmi_t *cmi;
408 	int modid;
409 	int err;
410 
411 	ASSERT(MUTEX_HELD(&cmi_load_lock));
412 
413 	if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1)
414 		return (NULL);
415 
416 	modp = mod_hold_by_id(modid);
417 	cmi = cmi_load_modctl(modp);
418 	if (cmi)
419 		cmi_hold(cmi);
420 	mod_release_mod(modp);
421 
422 	if (cmi == NULL)
423 		return (NULL);
424 
425 	if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) {
426 		if (err != ENOTSUP)
427 			cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to "
428 			    "init: err=%d", err);
429 		cmi_rele(cmi);
430 		return (NULL);
431 	}
432 
433 	return (cmi);
434 }
435 
436 cmi_hdl_t
437 cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
438     uint_t strandid, boolean_t mstrand)
439 {
440 	cmi_t *cmi = NULL;
441 	cmi_hdl_t hdl;
442 	void *data;
443 
444 	if (cmi_no_init) {
445 		cmi_no_mca_init = 1;
446 		return (NULL);
447 	}
448 
449 	mutex_enter(&cmi_load_lock);
450 
451 	if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid,
452 	    mstrand)) == NULL) {
453 		mutex_exit(&cmi_load_lock);
454 		cmn_err(CE_WARN, "There will be no MCA support on chip %d "
455 		    "core %d strand %d (cmi_hdl_create returned NULL)\n",
456 		    chipid, coreid, strandid);
457 		return (NULL);
458 	}
459 
460 	if (!cmi_force_generic)
461 		cmi = cmi_load_specific(hdl, &data);
462 
463 	if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) {
464 		cmn_err(CE_WARN, "There will be no MCA support on chip %d "
465 		    "core %d strand %d\n", chipid, coreid, strandid);
466 		cmi_hdl_rele(hdl);
467 		mutex_exit(&cmi_load_lock);
468 		return (NULL);
469 	}
470 
471 	cmi_hdl_setcmi(hdl, cmi, data);
472 
473 	cms_init(hdl);
474 
475 	mutex_exit(&cmi_load_lock);
476 
477 	return (hdl);
478 }
479 
480 /*
481  * cmi_fini is not called at the moment.  It is intended to be called
482  * on DR deconfigure of a cpu resource.  It should not be called at
483  * simple offline of a cpu.
484  */
485 void
486 cmi_fini(cmi_hdl_t hdl)
487 {
488 	cmi_t *cmi = HDL2CMI(hdl);
489 
490 	if (cms_present(hdl))
491 		cms_fini(hdl);
492 
493 	if (CMI_OP_PRESENT(cmi, cmi_fini))
494 		CMI_OPS(cmi)->cmi_fini(hdl);
495 
496 	cmi_hdl_rele(hdl);	/* release hold obtained in cmi_hdl_create */
497 }
498 
499 /*
500  * cmi_post_startup is called from post_startup for the boot cpu only.
501  */
502 void
503 cmi_post_startup(void)
504 {
505 	cmi_hdl_t hdl;
506 	cmi_t *cmi;
507 
508 	if (cmi_no_mca_init != 0 ||
509 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
510 		return;
511 
512 	cmi = HDL2CMI(hdl);
513 
514 	if (CMI_OP_PRESENT(cmi, cmi_post_startup))
515 		CMI_OPS(cmi)->cmi_post_startup(hdl);
516 
517 	cmi_hdl_rele(hdl);
518 }
519 
520 /*
521  * Called just once from start_other_cpus when all processors are started.
522  * This will not be called for each cpu, so the registered op must not
523  * assume it is called as such.
524  */
525 void
526 cmi_post_mpstartup(void)
527 {
528 	cmi_hdl_t hdl;
529 	cmi_t *cmi;
530 
531 	if (cmi_no_mca_init != 0 ||
532 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
533 		return;
534 
535 	cmi = HDL2CMI(hdl);
536 
537 	if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup))
538 		CMI_OPS(cmi)->cmi_post_mpstartup(hdl);
539 
540 	cmi_hdl_rele(hdl);
541 }
542 
543 void
544 cmi_faulted_enter(cmi_hdl_t hdl)
545 {
546 	cmi_t *cmi = HDL2CMI(hdl);
547 
548 	if (cmi_no_mca_init != 0)
549 		return;
550 
551 	if (CMI_OP_PRESENT(cmi, cmi_faulted_enter))
552 		CMI_OPS(cmi)->cmi_faulted_enter(hdl);
553 }
554 
555 void
556 cmi_faulted_exit(cmi_hdl_t hdl)
557 {
558 	cmi_t *cmi = HDL2CMI(hdl);
559 
560 	if (cmi_no_mca_init != 0)
561 		return;
562 
563 	if (CMI_OP_PRESENT(cmi, cmi_faulted_exit))
564 		CMI_OPS(cmi)->cmi_faulted_exit(hdl);
565 }
566 
567 void
568 cmi_mca_init(cmi_hdl_t hdl)
569 {
570 	cmi_t *cmi;
571 
572 	if (cmi_no_mca_init != 0)
573 		return;
574 
575 	cmi = HDL2CMI(hdl);
576 
577 	if (CMI_OP_PRESENT(cmi, cmi_mca_init))
578 		CMI_OPS(cmi)->cmi_mca_init(hdl);
579 }
580 
581 #define	CMI_RESPONSE_PANIC		0x0	/* panic must have value 0 */
582 #define	CMI_RESPONSE_NONE		0x1
583 #define	CMI_RESPONSE_CKILL		0x2
584 #define	CMI_RESPONSE_REBOOT		0x3	/* not implemented */
585 #define	CMI_RESPONSE_ONTRAP_PROT	0x4
586 #define	CMI_RESPONSE_LOFAULT_PROT	0x5
587 
588 /*
589  * Return 0 if we will panic in response to this machine check, otherwise
590  * non-zero.  If the caller is cmi_mca_trap in this file then the nonzero
591  * return values are to be interpreted from CMI_RESPONSE_* above.
592  *
593  * This function must just return what will be done without actually
594  * doing anything; this includes not changing the regs.
595  */
596 int
597 cmi_mce_response(struct regs *rp, uint64_t disp)
598 {
599 	int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC :
600 	    CMI_RESPONSE_NONE;
601 	on_trap_data_t *otp;
602 
603 	ASSERT(rp != NULL);	/* don't call for polling, only on #MC */
604 
605 	/*
606 	 * If no bits are set in the disposition then there is nothing to
607 	 * worry about and we do not need to trampoline to ontrap or
608 	 * lofault handlers.
609 	 */
610 	if (disp == 0)
611 		return (CMI_RESPONSE_NONE);
612 
613 	/*
614 	 * Unconstrained errors cannot be forgiven, even by ontrap or
615 	 * lofault protection.  The data is not poisoned and may not
616 	 * even belong to the trapped context - eg a writeback of
617 	 * data that is found to be bad.
618 	 */
619 	if (disp & CMI_ERRDISP_UC_UNCONSTRAINED)
620 		return (panicrsp);
621 
622 	/*
623 	 * ontrap OT_DATA_EC and lofault protection forgive any disposition
624 	 * other than unconstrained, even those normally forced fatal.
625 	 */
626 	if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC)
627 		return (CMI_RESPONSE_ONTRAP_PROT);
628 	else if (curthread->t_lofault)
629 		return (CMI_RESPONSE_LOFAULT_PROT);
630 
631 	/*
632 	 * Forced-fatal errors are terminal even in user mode.
633 	 */
634 	if (disp & CMI_ERRDISP_FORCEFATAL)
635 		return (panicrsp);
636 
637 	/*
638 	 * If the trapped context is corrupt or we have no instruction pointer
639 	 * to resume at (and aren't trampolining to a fault handler)
640 	 * then in the kernel case we must panic and in usermode we
641 	 * kill the affected contract.
642 	 */
643 	if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID))
644 		return (USERMODE(rp->r_cs) ?  CMI_RESPONSE_CKILL : panicrsp);
645 
646 	/*
647 	 * Anything else is harmless
648 	 */
649 	return (CMI_RESPONSE_NONE);
650 }
651 
652 int cma_mca_trap_panic_suppressed = 0;
653 
654 static void
655 cmi_mca_panic(void)
656 {
657 	if (cmi_panic_on_uncorrectable_error) {
658 		fm_panic("Unrecoverable Machine-Check Exception");
659 	} else {
660 		cmn_err(CE_WARN, "suppressing panic from fatal #mc");
661 		cma_mca_trap_panic_suppressed++;
662 	}
663 }
664 
665 
666 int cma_mca_trap_contract_kills = 0;
667 int cma_mca_trap_ontrap_forgiven = 0;
668 int cma_mca_trap_lofault_forgiven = 0;
669 
670 /*
671  * Native #MC handler - we branch to here from mcetrap
672  */
673 /*ARGSUSED*/
674 void
675 cmi_mca_trap(struct regs *rp)
676 {
677 #ifndef	__xpv
678 	cmi_hdl_t hdl = NULL;
679 	uint64_t disp;
680 	cmi_t *cmi;
681 	int s;
682 
683 	if (cmi_no_mca_init != 0)
684 		return;
685 
686 	/*
687 	 * This function can call cmn_err, and the cpu module cmi_mca_trap
688 	 * entry point may also elect to call cmn_err (e.g., if it can't
689 	 * log the error onto an errorq, say very early in boot).
690 	 * We need to let cprintf know that we must not block.
691 	 */
692 	s = spl8();
693 
694 	if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
695 	    cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
696 	    (cmi = HDL2CMI(hdl)) == NULL ||
697 	    !CMI_OP_PRESENT(cmi, cmi_mca_trap)) {
698 
699 		cmn_err(CE_WARN, "#MC exception on cpuid %d: %s",
700 		    CPU->cpu_id,
701 		    hdl ? "handle lookup ok but no #MC handler found" :
702 		    "handle lookup failed");
703 
704 		if (hdl != NULL)
705 			cmi_hdl_rele(hdl);
706 
707 		splx(s);
708 		return;
709 	}
710 
711 	disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp);
712 
713 	switch (cmi_mce_response(rp, disp)) {
714 	default:
715 		cmn_err(CE_WARN, "Invalid response from cmi_mce_response");
716 		/*FALLTHRU*/
717 
718 	case CMI_RESPONSE_PANIC:
719 		cmi_mca_panic();
720 		break;
721 
722 	case CMI_RESPONSE_NONE:
723 		break;
724 
725 	case CMI_RESPONSE_CKILL:
726 		ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR;
727 		aston(curthread);
728 		cma_mca_trap_contract_kills++;
729 		break;
730 
731 	case CMI_RESPONSE_ONTRAP_PROT: {
732 		on_trap_data_t *otp = curthread->t_ontrap;
733 		otp->ot_trap = OT_DATA_EC;
734 		rp->r_pc = otp->ot_trampoline;
735 		cma_mca_trap_ontrap_forgiven++;
736 		break;
737 	}
738 
739 	case CMI_RESPONSE_LOFAULT_PROT:
740 		rp->r_r0 = EFAULT;
741 		rp->r_pc = curthread->t_lofault;
742 		cma_mca_trap_lofault_forgiven++;
743 		break;
744 	}
745 
746 	cmi_hdl_rele(hdl);
747 	splx(s);
748 #endif	/* __xpv */
749 }
750 
751 void
752 cmi_hdl_poke(cmi_hdl_t hdl)
753 {
754 	cmi_t *cmi = HDL2CMI(hdl);
755 
756 	if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke))
757 		return;
758 
759 	CMI_OPS(cmi)->cmi_hdl_poke(hdl);
760 }
761 
762 void
763 cmi_cmci_trap()
764 {
765 #ifndef	__xpv
766 	cmi_hdl_t hdl = NULL;
767 	cmi_t *cmi;
768 
769 	if (cmi_no_mca_init != 0)
770 		return;
771 
772 	if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
773 	    cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
774 	    (cmi = HDL2CMI(hdl)) == NULL ||
775 	    !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) {
776 
777 		cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s",
778 		    CPU->cpu_id,
779 		    hdl ? "handle lookup ok but no CMCI handler found" :
780 		    "handle lookup failed");
781 
782 		if (hdl != NULL)
783 			cmi_hdl_rele(hdl);
784 
785 		return;
786 	}
787 
788 	CMI_OPS(cmi)->cmi_cmci_trap(hdl);
789 
790 	cmi_hdl_rele(hdl);
791 #endif	/* __xpv */
792 }
793 
794 void
795 cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata)
796 {
797 	if (!cmi_no_mca_init)
798 		cmi_hdl_setmc(hdl, mcops, mcdata);
799 }
800 
801 cmi_errno_t
802 cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd,
803     int syndtype, mc_unum_t *up)
804 {
805 	const struct cmi_mc_ops *mcops;
806 	cmi_hdl_t hdl;
807 	cmi_errno_t rv;
808 
809 	if (cmi_no_mca_init ||
810 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
811 		return (CMIERR_MC_ABSENT);
812 
813 	if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
814 	    mcops->cmi_mc_patounum == NULL) {
815 		cmi_hdl_rele(hdl);
816 		return (CMIERR_MC_NOTSUP);
817 	}
818 
819 	rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi,
820 	    valid_lo, synd, syndtype, up);
821 
822 	cmi_hdl_rele(hdl);
823 
824 	return (rv);
825 }
826 
827 cmi_errno_t
828 cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap)
829 {
830 	const struct cmi_mc_ops *mcops;
831 	cmi_hdl_t hdl;
832 	cmi_errno_t rv;
833 
834 	if (up != NULL && nvl != NULL)
835 		return (CMIERR_API);	/* convert from just one form */
836 
837 	if (cmi_no_mca_init ||
838 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
839 		return (CMIERR_MC_ABSENT);
840 
841 	if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
842 	    mcops->cmi_mc_unumtopa == NULL) {
843 		cmi_hdl_rele(hdl);
844 
845 		if (nvl != NULL && nvlist_lookup_uint64(nvl,
846 		    FM_FMRI_MEM_PHYSADDR, pap) == 0) {
847 			return (CMIERR_MC_PARTIALUNUMTOPA);
848 		} else {
849 			return (mcops && mcops->cmi_mc_unumtopa ?
850 			    CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT);
851 		}
852 	}
853 
854 	rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap);
855 
856 	cmi_hdl_rele(hdl);
857 
858 	return (rv);
859 }
860 
861 void
862 cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync)
863 {
864 	const struct cmi_mc_ops *mcops;
865 
866 	if (cmi_no_mca_init || (mcops = cmi_hdl_getmcops(hdl)) == NULL)
867 		return;
868 
869 	if (mcops->cmi_mc_logout != NULL)
870 		mcops->cmi_mc_logout(hdl, ismc, sync);
871 }
872 
873 cmi_errno_t
874 cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs,
875     int force)
876 {
877 	cmi_t *cmi = cmi_hdl_getcmi(hdl);
878 
879 	if (!CMI_OP_PRESENT(cmi, cmi_msrinject))
880 		return (CMIERR_NOTSUP);
881 
882 	return (CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force));
883 }
884 
885 boolean_t
886 cmi_panic_on_ue(void)
887 {
888 	return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE);
889 }
890