1e4b8688Cheng Sean Ye/*
2e4b8688Cheng Sean Ye * CDDL HEADER START
3e4b8688Cheng Sean Ye *
4e4b8688Cheng Sean Ye * The contents of this file are subject to the terms of the
5e4b8688Cheng Sean Ye * Common Development and Distribution License (the "License").
6e4b8688Cheng Sean Ye * You may not use this file except in compliance with the License.
7e4b8688Cheng Sean Ye *
8e4b8688Cheng Sean Ye * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e4b8688Cheng Sean Ye * or http://www.opensolaris.org/os/licensing.
10e4b8688Cheng Sean Ye * See the License for the specific language governing permissions
11e4b8688Cheng Sean Ye * and limitations under the License.
12e4b8688Cheng Sean Ye *
13e4b8688Cheng Sean Ye * When distributing Covered Code, include this CDDL HEADER in each
14e4b8688Cheng Sean Ye * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e4b8688Cheng Sean Ye * If applicable, add the following below this CDDL HEADER, with the
16e4b8688Cheng Sean Ye * fields enclosed by brackets "[]" replaced with your own identifying
17e4b8688Cheng Sean Ye * information: Portions Copyright [yyyy] [name of copyright owner]
18e4b8688Cheng Sean Ye *
19e4b8688Cheng Sean Ye * CDDL HEADER END
20e4b8688Cheng Sean Ye */
21e4b8688Cheng Sean Ye
22e4b8688Cheng Sean Ye/*
23349b53dStuart Maybee * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24e4b8688Cheng Sean Ye * Use is subject to license terms.
25e4b8688Cheng Sean Ye */
26e4b8688Cheng Sean Ye
27e4b8688Cheng Sean Ye/*
28e4b8688Cheng Sean Ye * "Polled" MCA events in an i86xpv dom0.  A timeout runs in the hypervisor
29e4b8688Cheng Sean Ye * and checks MCA state.  If it observes valid MCA state in a bank and if
30e4b8688Cheng Sean Ye * it sees that dom0 has registered a handler for the VIRQ_MCA then it
31e4b8688Cheng Sean Ye * raises that VIRQ to dom0.  The interrupt handler performs a
32e4b8688Cheng Sean Ye * hypercall to retrieve the polled telemetry and then pushes that telemetry
33e4b8688Cheng Sean Ye * into the MSR interpose hash and calls the generic logout code which
34e4b8688Cheng Sean Ye * will then find the provided interposed MSR values when it performs
35e4b8688Cheng Sean Ye * cmi_hdl_rdmsr so logout code works unchanged for native or i86xpv dom0.
36e4b8688Cheng Sean Ye */
37e4b8688Cheng Sean Ye
38e4b8688Cheng Sean Ye#include <sys/types.h>
39e4b8688Cheng Sean Ye#include <sys/conf.h>
40e4b8688Cheng Sean Ye#include <sys/x86_archext.h>
41e4b8688Cheng Sean Ye#include <sys/mca_x86.h>
42e4b8688Cheng Sean Ye#include <sys/ddi.h>
43e4b8688Cheng Sean Ye#include <sys/spl.h>
44e4b8688Cheng Sean Ye#include <sys/sunddi.h>
45e4b8688Cheng Sean Ye#include <sys/evtchn_impl.h>
46e4b8688Cheng Sean Ye#include <sys/hypervisor.h>
47e4b8688Cheng Sean Ye
48e4b8688Cheng Sean Ye#include "../../i86pc/cpu/generic_cpu/gcpu.h"
49e4b8688Cheng Sean Ye
50e4b8688Cheng Sean Yeextern int *gcpu_xpv_telem_read(mc_info_t *, int, uint64_t *);
51e4b8688Cheng Sean Yeextern void gcpu_xpv_telem_ack(int, uint64_t);
52e4b8688Cheng Sean Yeextern void gcpu_xpv_mci_process(mc_info_t *, int, cmi_mca_regs_t *, size_t);
53e4b8688Cheng Sean Ye
54e4b8688Cheng Sean Yeint gcpu_xpv_mch_poll_interval_secs = 10;
55e4b8688Cheng Sean Yeint gcpu_xpv_virq_level = 3;
56e4b8688Cheng Sean Ye
57e4b8688Cheng Sean Yestatic timeout_id_t gcpu_xpv_mch_poll_timeoutid;
58e4b8688Cheng Sean Ye
59e4b8688Cheng Sean Yestatic int gcpu_xpv_virq_vect = -1;
60e4b8688Cheng Sean Ye
61e4b8688Cheng Sean Yestatic mc_info_t gcpu_xpv_polldata;
62e4b8688Cheng Sean Yestatic kmutex_t gcpu_xpv_polldata_lock;
63e4b8688Cheng Sean Ye
64e4b8688Cheng Sean Yestatic cmi_mca_regs_t *gcpu_xpv_poll_bankregs;
65e4b8688Cheng Sean Yestatic size_t gcpu_xpv_poll_bankregs_sz;
66e4b8688Cheng Sean Ye
67e4b8688Cheng Sean Yestatic uint32_t gcpu_xpv_intr_unclaimed;
68e4b8688Cheng Sean Yestatic uint32_t gcpu_xpv_mca_hcall_busy;
69e4b8688Cheng Sean Ye
70e4b8688Cheng Sean Yestatic gcpu_poll_trace_ctl_t gcpu_xpv_poll_trace_ctl;
71e4b8688Cheng Sean Ye
72e4b8688Cheng Sean Ye#define	GCPU_XPV_ARCH_NREGS		3
73e4b8688Cheng Sean Ye#define	GCPU_XPV_MCH_POLL_REARM		((void *)1)
74e4b8688Cheng Sean Ye#define	GCPU_XPV_MCH_POLL_NO_REARM	NULL
75e4b8688Cheng Sean Ye
76e4b8688Cheng Sean Yestatic uint_t
775328fc5Toomas Soomegcpu_xpv_virq_intr(caddr_t arg __unused, caddr_t arg1 __unused)
78e4b8688Cheng Sean Ye{
79349b53dStuart Maybee	int types[] = { XEN_MC_URGENT, XEN_MC_NONURGENT };
80e4b8688Cheng Sean Ye	uint64_t fetch_id;
81e4b8688Cheng Sean Ye	int count = 0;
82e4b8688Cheng Sean Ye	int i;
83e4b8688Cheng Sean Ye
84e4b8688Cheng Sean Ye	if (gcpu_xpv_virq_vect == -1 || gcpu_xpv_poll_bankregs_sz == 0) {
85e4b8688Cheng Sean Ye		gcpu_xpv_intr_unclaimed++;
86e4b8688Cheng Sean Ye		return (DDI_INTR_UNCLAIMED);
87e4b8688Cheng Sean Ye	}
88e4b8688Cheng Sean Ye
89e4b8688Cheng Sean Ye	if (!mutex_tryenter(&gcpu_xpv_polldata_lock)) {
90e4b8688Cheng Sean Ye		gcpu_xpv_mca_hcall_busy++;
91e4b8688Cheng Sean Ye		return (DDI_INTR_CLAIMED);
92e4b8688Cheng Sean Ye	}
93e4b8688Cheng Sean Ye
94e4b8688Cheng Sean Ye	for (i = 0; i < sizeof (types) / sizeof (types[0]); i++) {
95e4b8688Cheng Sean Ye		while (gcpu_xpv_telem_read(&gcpu_xpv_polldata, types[i],
96e4b8688Cheng Sean Ye		    &fetch_id)) {
97e4b8688Cheng Sean Ye			gcpu_poll_trace(&gcpu_xpv_poll_trace_ctl,
98e4b8688Cheng Sean Ye			    GCPU_MPT_WHAT_XPV_VIRQ,
99e4b8688Cheng Sean Ye			    x86_mcinfo_nentries(&gcpu_xpv_polldata));
100e4b8688Cheng Sean Ye			gcpu_xpv_mci_process(&gcpu_xpv_polldata, types[i],
101e4b8688Cheng Sean Ye			    gcpu_xpv_poll_bankregs, gcpu_xpv_poll_bankregs_sz);
102e4b8688Cheng Sean Ye			gcpu_xpv_telem_ack(types[i], fetch_id);
103e4b8688Cheng Sean Ye			count++;
104e4b8688Cheng Sean Ye		}
105e4b8688Cheng Sean Ye	}
106e4b8688Cheng Sean Ye
107e4b8688Cheng Sean Ye	mutex_exit(&gcpu_xpv_polldata_lock);
108e4b8688Cheng Sean Ye
109e4b8688Cheng Sean Ye	return (DDI_INTR_CLAIMED);
110e4b8688Cheng Sean Ye}
111e4b8688Cheng Sean Ye
112e4b8688Cheng Sean Yestatic void
113e4b8688Cheng Sean Yegcpu_xpv_mch_poll(void *arg)
114e4b8688Cheng Sean Ye{
115e4b8688Cheng Sean Ye	cmi_hdl_t hdl = cmi_hdl_any();
116e4b8688Cheng Sean Ye
117e4b8688Cheng Sean Ye	if (hdl != NULL) {
118e4b8688Cheng Sean Ye		cmi_mc_logout(hdl, 0, 0);
119e4b8688Cheng Sean Ye		cmi_hdl_rele(hdl);
120e4b8688Cheng Sean Ye	}
121e4b8688Cheng Sean Ye
122e4b8688Cheng Sean Ye	if (arg == GCPU_XPV_MCH_POLL_REARM &&
123e4b8688Cheng Sean Ye	    gcpu_xpv_mch_poll_interval_secs != 0) {
124e4b8688Cheng Sean Ye		gcpu_xpv_mch_poll_timeoutid = timeout(gcpu_xpv_mch_poll,
125e4b8688Cheng Sean Ye		    GCPU_XPV_MCH_POLL_REARM,
126e4b8688Cheng Sean Ye		    drv_usectohz(gcpu_xpv_mch_poll_interval_secs * MICROSEC));
127e4b8688Cheng Sean Ye	}
128e4b8688Cheng Sean Ye}
129e4b8688Cheng Sean Ye