gcpu_poll_ntv.c revision e4b86885570d77af552e9cf94f142f4d744fb8c8
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 * Native MCA polling.  We establish an ommipresent cyclic to fire on all
29 * online cpus to check their MCA state and log any valid errors for
30 * diagnosis.
31 */
32
33#include <sys/types.h>
34#include <sys/cyclic.h>
35#include <sys/x86_archext.h>
36#include <sys/mca_x86.h>
37
38#include "gcpu.h"
39
40hrtime_t gcpu_mca_poll_interval = NANOSEC * 10ULL;	/* tuneable */
41static cyclic_id_t gcpu_mca_poll_cycid;
42static int gcpu_mca_poll_inits;
43
44/*
45 * Return nonzero of the given handle should poll the MCH.  We stick with
46 * the same handle as before unless the timestamp has not been updated
47 * for a while.  There is no need to keep a hold on the mch_poll_owner
48 * handle.
49 */
50
51static kmutex_t mch_poll_lock;
52static hrtime_t mch_poll_timestamp;
53static cmi_hdl_t mch_poll_owner;
54
55static int
56mch_pollowner(cmi_hdl_t hdl)
57{
58	hrtime_t now = gethrtime_waitfree();
59	int dopoll = 0;
60
61	mutex_enter(&mch_poll_lock);
62	if (now - mch_poll_timestamp > 2 * gcpu_mca_poll_interval ||
63	    mch_poll_timestamp == 0) {
64		mch_poll_owner = hdl;
65		dopoll = 1;
66	} else if (mch_poll_owner == hdl) {
67		dopoll = 1;
68	}
69
70	if (dopoll)
71		mch_poll_timestamp = now;
72
73	mutex_exit(&mch_poll_lock);
74	return (dopoll);
75}
76
77
78static void
79gcpu_ntv_mca_poll(cmi_hdl_t hdl, int what)
80{
81	gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
82	gcpu_mca_t *mca = &gcpu->gcpu_mca;
83	gcpu_mce_status_t mce;
84	int willpanic;
85	uint64_t bankmask;
86
87	ASSERT(MUTEX_HELD(&gcpu->gcpu_shared->gcpus_poll_lock));
88
89	/* Enable CMCI in first poll if is supported */
90	if (cmi_enable_cmci && (!mca->gcpu_mca_first_poll_cmci_enabled)) {
91		int i;
92		uint64_t ctl2;
93
94		for (i = 0; i < mca->gcpu_mca_nbanks; i++) {
95			if (mca->gcpu_bank_cmci[i].cmci_cap) {
96				(void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC_CTL2(i),
97				    &ctl2);
98				ctl2 |= MSR_MC_CTL2_EN;
99				(void) cmi_hdl_wrmsr(hdl, IA32_MSR_MC_CTL2(i),
100				    ctl2);
101				mca->gcpu_bank_cmci[i].cmci_enabled = 1;
102			}
103		}
104		mca->gcpu_mca_first_poll_cmci_enabled = 1;
105	}
106
107	if (mca->gcpu_mca_flags & GCPU_MCA_F_UNFAULTING) {
108		int i;
109
110		mca->gcpu_mca_flags &= ~GCPU_MCA_F_UNFAULTING;
111		gcpu_poll_trace(&gcpu->gcpu_mca.gcpu_polltrace,
112		    GCPU_MPT_WHAT_UNFAULTING, 0);
113
114		/*
115		 * On the first cyclic poll after unfaulting a CPU we
116		 * clear the status registers; see gcpu_faulted_exit
117		 * for details.  We don't do this if the poll was
118		 * initiated manually (presumably from some injection
119		 * activity).
120		 */
121		if (what == GCPU_MPT_WHAT_CYC_ERR) {
122			for (i = 0; i < mca->gcpu_mca_nbanks; i++) {
123				(void) cmi_hdl_wrmsr(hdl,
124				    IA32_MSR_MC(i, STATUS), 0ULL);
125			}
126			return;
127		}
128	}
129
130	/*
131	 * Logout errors of the MCA banks of this cpu.
132	 */
133	if (what == GCPU_MPT_WHAT_CMCI_ERR) {
134		/*
135		 * for CMCI, all banks should be scanned for log out
136		 */
137		bankmask = -1ULL;
138	} else {
139		bankmask = cms_poll_ownermask(hdl, gcpu_mca_poll_interval);
140	}
141	gcpu_mca_logout(hdl, NULL, bankmask, &mce, B_TRUE, what);
142
143	if (mce.mce_nerr != 0)
144		gcpu_poll_trace(&gcpu->gcpu_mca.gcpu_polltrace, what,
145		    mce.mce_nerr);
146
147	mca->gcpu_mca_lastpoll = gethrtime_waitfree();
148
149	willpanic = mce.mce_disp & CMI_ERRDISP_FORCEFATAL && cmi_panic_on_ue();
150
151	if (what != GCPU_MPT_WHAT_CMCI_ERR) {
152		/*
153		 * Call to the memory-controller driver which may report some
154		 * errors not visible under the MCA (for off-chip NB).
155		 * Since there is typically a single MCH we arrange that
156		 * just one cpu perform this task at each cyclic fire.
157		 */
158		if (mch_pollowner(hdl))
159			cmi_mc_logout(hdl, 0, willpanic);
160	}
161
162	/*
163	 * In the common case any polled error is considered non-fatal,
164	 * even if it indicates PCC or UC etc.  The only condition on which
165	 * we will panic for a polled error is if model-specific support
166	 * forces the error to be terminal regardless of how it is
167	 * encountered.
168	 */
169	if (willpanic) {
170#ifdef DEBUG
171		cmn_err(CE_WARN, "MCA Poll: %u errors, disp=0x%llx, "
172		    "%u PCC (%u ok), "
173		    "%u UC (%u ok, %u poisoned), "
174		    "%u forcefatal, %u ignored",
175		    mce.mce_nerr, (u_longlong_t)mce.mce_disp,
176		    mce.mce_npcc, mce.mce_npcc_ok,
177		    mce.mce_nuc, mce.mce_nuc_ok, mce.mce_nuc_poisoned,
178		    mce.mce_forcefatal, mce.mce_ignored);
179
180#endif
181		fm_panic("Unrecoverable Machine-Check Exception (Polled)");
182	}
183}
184
185/*
186 * See gcpu_mca_trap for an explanation of why preemption is disabled here.
187 * Note that we disable preemption and then contend for an adaptive mutex -
188 * we could block during the mutex operation, but once we return with the
189 * mutex held we nust perform no operation that can block and we cannot
190 * be preempted so we will stay on cpu for the duration.  The disabling
191 * of preemption also means we cannot migrate cpus once we have returned
192 * with the mutex held - cyclic invocations can't migrate, anyway, but
193 * others could if they have failed to bind before this point.
194 */
195static void
196gcpu_ntv_mca_poll_wrapper(cmi_hdl_t hdl, int what)
197{
198	gcpu_data_t *gcpu;
199
200	if (hdl == NULL || (gcpu = cmi_hdl_getcmidata(hdl)) == NULL ||
201	    gcpu->gcpu_mca.gcpu_mca_lgsz == 0)
202		return;
203
204	kpreempt_disable();
205	mutex_enter(&gcpu->gcpu_shared->gcpus_poll_lock);
206	gcpu_ntv_mca_poll(hdl, what);
207	mutex_exit(&gcpu->gcpu_shared->gcpus_poll_lock);
208	kpreempt_enable();
209}
210
211static void
212gcpu_ntv_mca_poll_cyclic(void *arg)
213{
214	gcpu_ntv_mca_poll_wrapper((cmi_hdl_t)arg, GCPU_MPT_WHAT_CYC_ERR);
215}
216
217/*ARGSUSED*/
218static void
219gcpu_ntv_mca_poll_online(void *arg, cpu_t *cp, cyc_handler_t *cyh,
220    cyc_time_t *cyt)
221{
222	cmi_hdl_t hdl;
223
224	/*
225	 * Lookup and hold a handle for this cpu (any hold released in
226	 * our offline function).  If we chose not to initialize a handle
227	 * for this cpu back at cmi_init time then this lookup will return
228	 * NULL, so the cyh_func we appoint must be prepared for that.
229	 */
230	hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(cp),
231	    cmi_ntv_hwcoreid(cp), cmi_ntv_hwstrandid(cp));
232
233	cyt->cyt_when = 0;
234	cyt->cyt_interval = gcpu_mca_poll_interval;
235	cyh->cyh_func = gcpu_ntv_mca_poll_cyclic;
236	cyh->cyh_arg = (void *)hdl;
237	cyh->cyh_level = CY_LOW_LEVEL;
238}
239
240/*ARGSUSED*/
241static void
242gcpu_ntv_mca_poll_offline(void *arg, cpu_t *cpu, void *cyh_arg)
243{
244	cmi_hdl_t hdl = (cmi_hdl_t)cyh_arg;
245
246	if (hdl != NULL)
247		cmi_hdl_rele(hdl);
248}
249
250static void
251gcpu_ntv_mca_poll_start(void)
252{
253	cyc_omni_handler_t cyo;
254
255	if (gcpu_mca_poll_interval == 0 || gcpu_mca_poll_inits == 0)
256		return;
257
258	cyo.cyo_online = gcpu_ntv_mca_poll_online;
259	cyo.cyo_offline = gcpu_ntv_mca_poll_offline;
260	cyo.cyo_arg = NULL;
261
262	mutex_enter(&cpu_lock);
263	gcpu_mca_poll_cycid = cyclic_add_omni(&cyo);
264	mutex_exit(&cpu_lock);
265}
266
267/*
268 * gcpu_mca_poll_init is called from gcpu_mca_init for each cpu handle
269 * that we initialize for.  It should prepare for polling by allocating
270 * control structures and the like, but must not kick polling off yet.
271 */
272
273void
274gcpu_mca_poll_init(cmi_hdl_t hdl)
275{
276	gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
277	gcpu_poll_trace_ctl_t *ptc = &gcpu->gcpu_mca.gcpu_polltrace;
278
279	ASSERT(cmi_hdl_class(hdl) == CMI_HDL_NATIVE);
280
281	gcpu_poll_trace_init(ptc);
282
283	gcpu_mca_poll_inits++;
284}
285
286void
287gcpu_mca_poll_start(cmi_hdl_t hdl)
288{
289	ASSERT(cmi_hdl_class(hdl) == CMI_HDL_NATIVE);
290	gcpu_ntv_mca_poll_start();
291}
292
293void
294gcpu_hdl_poke(cmi_hdl_t hdl)
295{
296	ASSERT(cmi_hdl_class(hdl) == CMI_HDL_NATIVE);
297	gcpu_ntv_mca_poll_wrapper(hdl, GCPU_MPT_WHAT_POKE_ERR);
298}
299
300void
301gcpu_cmci_trap(cmi_hdl_t hdl)
302{
303	gcpu_ntv_mca_poll_wrapper(hdl, GCPU_MPT_WHAT_CMCI_ERR);
304}
305