ao_mca.c revision 3434:5142e1d7d0bc
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 2007 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/types.h>
30#include <sys/regset.h>
31#include <sys/privregs.h>
32#include <sys/pci_impl.h>
33#include <sys/cpuvar.h>
34#include <sys/x86_archext.h>
35#include <sys/cmn_err.h>
36#include <sys/systm.h>
37#include <sys/sysmacros.h>
38#include <sys/pghw.h>
39#include <sys/cyclic.h>
40#include <sys/cpu_module_impl.h>
41#include <sys/pci_cfgspace_impl.h>
42#include <sys/sysevent.h>
43#include <sys/smbios.h>
44#include <sys/mca_x86.h>
45#include <sys/mca_amd.h>
46#include <sys/mc.h>
47#include <sys/mc_amd.h>
48#include <sys/psw.h>
49#include <sys/ddi.h>
50#include <sys/sunddi.h>
51#include <sys/sdt.h>
52#include <sys/fm/util.h>
53#include <sys/fm/protocol.h>
54#include <sys/fm/cpu/AMD.h>
55#include <sys/acpi/acpi.h>
56#include <sys/acpi/acpi_pci.h>
57#include <sys/acpica.h>
58
59#include "ao.h"
60#include "ao_mca_disp.h"
61
62#define	AO_REVS_FG (X86_CHIPREV_AMD_F_REV_F | X86_CHIPREV_AMD_F_REV_G)
63
64errorq_t *ao_mca_queue;			/* machine-check ereport queue */
65int ao_mca_stack_flag = 0;		/* record stack trace in ereports */
66int ao_mca_smi_disable = 1;		/* attempt to disable SMI polling */
67
68ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT] = {
69	{ AMD_MSR_DC_STATUS, AMD_MSR_DC_ADDR, AMD_MSR_DC_MISC },
70	{ AMD_MSR_IC_STATUS, AMD_MSR_IC_ADDR, AMD_MSR_IC_MISC },
71	{ AMD_MSR_BU_STATUS, AMD_MSR_BU_ADDR, AMD_MSR_BU_MISC },
72	{ AMD_MSR_LS_STATUS, AMD_MSR_LS_ADDR, AMD_MSR_LS_MISC },
73	{ AMD_MSR_NB_STATUS, AMD_MSR_NB_ADDR, AMD_MSR_NB_MISC }
74};
75
76struct ao_ctl_init {
77	uint32_t ctl_revmask;	/* rev(s) to which this applies */
78	uint64_t ctl_bits;	/* mca ctl reg bitmask to set */
79};
80
81/*
82 * Additional NB MCA ctl initialization for revs F and G
83 */
84static const struct ao_ctl_init ao_nb_ctl_init[] = {
85	{ AO_REVS_FG, AMD_NB_CTL_INIT_REV_FG },
86	{ X86_CHIPREV_UNKNOWN, 0 }
87};
88
89typedef struct ao_bank_cfg {
90	uint_t bank_ctl;
91	uint_t bank_ctl_mask;
92	uint64_t bank_ctl_init_cmn;			/* Common init value */
93	const struct ao_ctl_init *bank_ctl_init_extra;	/* Extra for each rev */
94	void (*bank_misc_initfunc)(ao_data_t *, uint32_t);
95	uint_t bank_status;
96	uint_t bank_addr;
97} ao_bank_cfg_t;
98
99static void nb_mcamisc_init(ao_data_t *, uint32_t);
100
101static const ao_bank_cfg_t ao_bank_cfgs[] = {
102	{ AMD_MSR_DC_CTL, AMD_MSR_DC_MASK, AMD_DC_CTL_INIT_CMN,
103	    NULL, NULL, AMD_MSR_DC_STATUS, AMD_MSR_DC_ADDR },
104	{ AMD_MSR_IC_CTL, AMD_MSR_IC_MASK, AMD_IC_CTL_INIT_CMN,
105	    NULL, NULL, AMD_MSR_IC_STATUS, AMD_MSR_IC_ADDR },
106	{ AMD_MSR_BU_CTL, AMD_MSR_BU_MASK, AMD_BU_CTL_INIT_CMN,
107	    NULL, NULL, AMD_MSR_BU_STATUS, AMD_MSR_BU_ADDR },
108	{ AMD_MSR_LS_CTL, AMD_MSR_LS_MASK, AMD_LS_CTL_INIT_CMN,
109	    NULL, NULL, AMD_MSR_LS_STATUS, AMD_MSR_LS_ADDR },
110	{ AMD_MSR_NB_CTL, AMD_MSR_NB_MASK, AMD_NB_CTL_INIT_CMN,
111	    &ao_nb_ctl_init[0], nb_mcamisc_init,
112	    AMD_MSR_NB_STATUS, AMD_MSR_NB_ADDR }
113};
114
115static const ao_error_disp_t ao_disp_unknown = {
116	FM_EREPORT_CPU_AMD_UNKNOWN,
117	FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN
118};
119
120/*
121 * This is quite awful but necessary to work around x86 system vendor's view of
122 * the world.  Other operating systems (you know who you are) don't understand
123 * Opteron-specific error handling, so BIOS and system vendors often hide these
124 * conditions from them by using SMI polling to copy out any errors from the
125 * machine-check registers.  When Solaris runs on a system with this feature,
126 * we want to disable the SMI polling so we can use FMA instead.  Sadly, there
127 * isn't even a standard self-describing way to express the whole situation,
128 * so we have to resort to hard-coded values.  This should all be changed to
129 * be a self-describing vendor-specific SMBIOS structure in the future.
130 */
131static const struct ao_smi_disable {
132	const char *asd_sys_vendor;	/* SMB_TYPE_SYSTEM vendor prefix */
133	const char *asd_sys_product;	/* SMB_TYPE_SYSTEM product prefix */
134	const char *asd_bios_vendor;	/* SMB_TYPE_BIOS vendor prefix */
135	uint8_t asd_code;		/* output code for SMI disable */
136} ao_smi_disable[] = {
137	{ "Sun Microsystems", "Galaxy12",
138	    "American Megatrends", 0x59 },
139	{ "Sun Microsystems", "Sun Fire X4100 Server",
140	    "American Megatrends", 0x59 },
141	{ "Sun Microsystems", "Sun Fire X4200 Server",
142	    "American Megatrends", 0x59 },
143	{ NULL, NULL, NULL, 0 }
144};
145
146static int
147ao_disp_match_r4(uint16_t ref, uint8_t r4)
148{
149	static const uint16_t ao_r4_map[] = {
150		AO_MCA_R4_BIT_GEN,	/* AMD_ERRCODE_R4_GEN */
151		AO_MCA_R4_BIT_RD,	/* AMD_ERRCODE_R4_RD */
152		AO_MCA_R4_BIT_WR,	/* AMD_ERRCODE_R4_WR */
153		AO_MCA_R4_BIT_DRD,	/* AMD_ERRCODE_R4_DRD */
154		AO_MCA_R4_BIT_DWR,	/* AMD_ERRCODE_R4_DWR */
155		AO_MCA_R4_BIT_IRD,	/* AMD_ERRCODE_R4_IRD */
156		AO_MCA_R4_BIT_PREFETCH,	/* AMD_ERRCODE_R4_PREFETCH */
157		AO_MCA_R4_BIT_EVICT,	/* AMD_ERRCODE_R4_EVICT */
158		AO_MCA_R4_BIT_SNOOP	/* AMD_ERRCODE_R4_SNOOP */
159	};
160
161	ASSERT(r4 < sizeof (ao_r4_map) / sizeof (uint16_t));
162
163	return ((ref & ao_r4_map[r4]) != 0);
164}
165
166static int
167ao_disp_match_pp(uint8_t ref, uint8_t pp)
168{
169	static const uint8_t ao_pp_map[] = {
170		AO_MCA_PP_BIT_SRC,	/* AMD_ERRCODE_PP_SRC */
171		AO_MCA_PP_BIT_RSP,	/* AMD_ERRCODE_PP_RSP */
172		AO_MCA_PP_BIT_OBS,	/* AMD_ERRCODE_PP_OBS */
173		AO_MCA_PP_BIT_GEN	/* AMD_ERRCODE_PP_GEN */
174	};
175
176	ASSERT(pp < sizeof (ao_pp_map) / sizeof (uint8_t));
177
178	return ((ref & ao_pp_map[pp]) != 0);
179}
180
181static int
182ao_disp_match_ii(uint8_t ref, uint8_t ii)
183{
184	static const uint8_t ao_ii_map[] = {
185		AO_MCA_II_BIT_MEM,	/* AMD_ERRCODE_II_MEM */
186		0,
187		AO_MCA_II_BIT_IO,	/* AMD_ERRCODE_II_IO */
188		AO_MCA_II_BIT_GEN	/* AMD_ERRCODE_II_GEN */
189	};
190
191	ASSERT(ii < sizeof (ao_ii_map) / sizeof (uint8_t));
192
193	return ((ref & ao_ii_map[ii]) != 0);
194}
195
196static uint8_t
197bit_strip(uint16_t *codep, uint16_t mask, uint16_t shift)
198{
199	uint8_t val = (*codep & mask) >> shift;
200	*codep &= ~mask;
201	return (val);
202}
203
204#define	BIT_STRIP(codep, name) \
205	bit_strip(codep, AMD_ERRCODE_##name##_MASK, AMD_ERRCODE_##name##_SHIFT)
206
207static int
208ao_disp_match_one(const ao_error_disp_t *aed, uint64_t status, uint32_t rev,
209    int bankno)
210{
211	uint16_t code = status & AMD_ERRCODE_MASK;
212	uint8_t extcode = (status & AMD_ERREXT_MASK) >> AMD_ERREXT_SHIFT;
213	uint64_t stat_mask = aed->aed_stat_mask;
214	uint64_t stat_mask_res = aed->aed_stat_mask_res;
215
216	/*
217	 * If the bank's status register indicates overflow, then we can no
218	 * longer rely on the value of CECC: our experience with actual fault
219	 * injection has shown that multiple CE's overwriting each other shows
220	 * AMD_BANK_STAT_CECC and AMD_BANK_STAT_UECC both set to zero.  This
221	 * should be clarified in a future BKDG or by the Revision Guide.
222	 * This behaviour is fixed in revision F.
223	 */
224	if (bankno == AMD_MCA_BANK_NB &&
225	    !X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) &&
226	    status & AMD_BANK_STAT_OVER) {
227		stat_mask &= ~AMD_BANK_STAT_CECC;
228		stat_mask_res &= ~AMD_BANK_STAT_CECC;
229	}
230
231	if ((status & stat_mask) != stat_mask_res)
232		return (0);
233
234	/*
235	 * r4 and pp bits are stored separately, so we mask off and compare them
236	 * for the code types that use them.  Once we've taken the r4 and pp
237	 * bits out of the equation, we can directly compare the resulting code
238	 * with the one stored in the ao_error_disp_t.
239	 */
240	if (AMD_ERRCODE_ISMEM(code)) {
241		uint8_t r4 = BIT_STRIP(&code, R4);
242
243		if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4))
244			return (0);
245
246	} else if (AMD_ERRCODE_ISBUS(code)) {
247		uint8_t r4 = BIT_STRIP(&code, R4);
248		uint8_t pp = BIT_STRIP(&code, PP);
249		uint8_t ii = BIT_STRIP(&code, II);
250
251		if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4) ||
252		    !ao_disp_match_pp(aed->aed_stat_pp_bits, pp) ||
253		    !ao_disp_match_ii(aed->aed_stat_ii_bits, ii))
254			return (0);
255	}
256
257	return (code == aed->aed_stat_code && extcode == aed->aed_stat_extcode);
258}
259
260static const ao_error_disp_t *
261ao_disp_match(uint_t bankno, uint64_t status, uint32_t rev)
262{
263	const ao_error_disp_t *aed;
264
265	for (aed = ao_error_disp[bankno]; aed->aed_stat_mask != 0; aed++) {
266		if (ao_disp_match_one(aed, status, rev, bankno))
267			return (aed);
268	}
269
270	return (&ao_disp_unknown);
271}
272
273void
274ao_pcicfg_write(uint_t chipid, uint_t func, uint_t reg, uint32_t val)
275{
276	ASSERT(chipid + 24 <= 31);
277	ASSERT((func & 7) == func);
278	ASSERT((reg & 3) == 0 && reg < 256);
279
280	pci_mech1_putl(0, chipid + 24, func, reg, val);
281}
282
283uint32_t
284ao_pcicfg_read(uint_t chipid, uint_t func, uint_t reg)
285{
286	ASSERT(chipid + 24 <= 31);
287	ASSERT((func & 7) == func);
288	ASSERT((reg & 3) == 0 && reg < 256);
289
290	return (pci_mech1_getl(0, chipid + 24, func, reg));
291}
292
293/*
294 * ao_chip_once returns 1 if the caller should perform the operation for
295 * this chip, or 0 if some other core has already performed the operation.
296 */
297
298int
299ao_chip_once(ao_data_t *ao, enum ao_cfgonce_bitnum what)
300{
301	return (atomic_set_long_excl(&ao->ao_shared->aos_cfgonce, what) == 0 ?
302	    1 : 0);
303}
304
305/*
306 * Setup individual bank detectors after stashing their bios settings.
307 * The 'donb' argument indicates whether this core should configured
308 * the shared NorthBridhe MSRs.
309 */
310static void
311ao_bank_cfg(ao_data_t *ao, uint32_t rev, int donb)
312{
313	ao_mca_t *mca = &ao->ao_mca;
314	struct ao_chipshared *aos = ao->ao_shared;
315	ao_bios_cfg_t *bcfg = &mca->ao_mca_bios_cfg;
316	const ao_bank_cfg_t *bankcfg = ao_bank_cfgs;
317	const struct ao_ctl_init *extrap;
318	uint64_t mcictl;
319	int i;
320
321	for (i = 0; i < AMD_MCA_BANK_COUNT; i++, bankcfg++) {
322		if (i == AMD_MCA_BANK_NB && donb == 0) {
323			bcfg->bcfg_bank_ctl[i] = 0xbaddcafe;
324			bcfg->bcfg_bank_mask[i] = 0xbaddcafe;
325			continue;
326		} else  if (i == AMD_MCA_BANK_NB) {
327			aos->aos_bcfg_nb_ctl = rdmsr(bankcfg->bank_ctl);
328			aos->aos_bcfg_nb_mask = rdmsr(bankcfg->bank_ctl_mask);
329		} else {
330			bcfg->bcfg_bank_ctl[i] = rdmsr(bankcfg->bank_ctl);
331			bcfg->bcfg_bank_mask[i] = rdmsr(bankcfg->bank_ctl_mask);
332		}
333
334		/* Initialize MCi_CTL register for this bank */
335		mcictl = bankcfg->bank_ctl_init_cmn;
336		if ((extrap = bankcfg->bank_ctl_init_extra) != NULL) {
337			while (extrap->ctl_revmask != X86_CHIPREV_UNKNOWN) {
338				if (X86_CHIPREV_MATCH(rev, extrap->ctl_revmask))
339					mcictl |= extrap->ctl_bits;
340				extrap++;
341			}
342		}
343		wrmsr(bankcfg->bank_ctl, mcictl);
344
345		/* Initialize the MCi_MISC register for this bank */
346		if (bankcfg->bank_misc_initfunc != NULL)
347			(bankcfg->bank_misc_initfunc)(ao, rev);
348	}
349}
350
351/*
352 * This knob exists in case any platform has a problem with our default
353 * policy of disabling any interrupt registered in the NB MC4_MISC
354 * register.  Setting this may cause Solaris and external entities
355 * who also have an interest in this register to argue over available
356 * telemetry (so setting it is generally not recommended).
357 */
358int ao_nb_cfg_mc4misc_noseize = 0;
359
360/*
361 * The BIOS may have setup to receive SMI on counter overflow.  It may also
362 * have locked various fields or made them read-only.  We will clear any
363 * SMI request and leave the register locked.  We will also clear the
364 * counter and enable counting - while we don't use the counter it is nice
365 * to have it enabled for verification and debug work.
366 */
367static void
368nb_mcamisc_init(ao_data_t *ao, uint32_t rev)
369{
370	uint64_t hwcr, oldhwcr;
371	uint64_t val;
372	int locked;
373
374	if (!X86_CHIPREV_MATCH(rev, AO_REVS_FG))
375		return;
376
377	ao->ao_shared->aos_bcfg_nb_misc = val = rdmsr(AMD_MSR_NB_MISC);
378
379	if (ao_nb_cfg_mc4misc_noseize)
380		return;		/* stash BIOS value, but no changes */
381
382	locked = val & AMD_NB_MISC_LOCKED;
383
384	/*
385	 * The Valid bit tells us whether the CtrP bit is defined; if it
386	 * is the CtrP bit tells us whether an ErrCount field is present.
387	 * If not then there is nothing for us to do.
388	 */
389	if (!(val & AMD_NB_MISC_VALID) || !(val & AMD_NB_MISC_CTRP))
390		return;
391
392	if (locked) {
393		oldhwcr = rdmsr(MSR_AMD_HWCR);
394		hwcr = oldhwcr | AMD_HWCR_MCI_STATUS_WREN;
395		wrmsr(MSR_AMD_HWCR, hwcr);
396	}
397
398	val |= AMD_NB_MISC_CNTEN;		/* enable ECC error counting */
399	val &= ~AMD_NB_MISC_ERRCOUNT_MASK;	/* clear ErrCount */
400	val &= ~AMD_NB_MISC_OVRFLW;		/* clear Ovrflw */
401	val &= ~AMD_NB_MISC_INTTYPE_MASK;	/* no interrupt on overflow */
402	val |= AMD_NB_MISC_LOCKED;
403
404	wrmsr(AMD_MSR_NB_MISC, val);
405
406	if (locked)
407		wrmsr(MSR_AMD_HWCR, oldhwcr);
408}
409
410/*
411 * NorthBridge (NB) Configuration.
412 *
413 * We add and remove bits from the BIOS-configured value, rather than
414 * writing an absolute value.  The variables ao_nb_cfg_{add,remove}_cmn and
415 * ap_nb_cfg_{add,remove}_revFG are available for modification via kmdb
416 * and /etc/system.  The revision-specific adds and removes are applied
417 * after the common changes, and one write is made to the config register.
418 * These are not intended for watchdog configuration via these variables -
419 * use the watchdog policy below.
420 */
421
422/*
423 * Bits to be added to the NB configuration register - all revs.
424 */
425uint32_t ao_nb_cfg_add_cmn = AMD_NB_CFG_ADD_CMN;
426
427/*
428 * Bits to be cleared from the NB configuration register - all revs.
429 */
430uint32_t ao_nb_cfg_remove_cmn = AMD_NB_CFG_REMOVE_CMN;
431
432/*
433 * Bits to be added to the NB configuration register - revs F and G.
434 */
435uint32_t ao_nb_cfg_add_revFG = AMD_NB_CFG_ADD_REV_FG;
436
437/*
438 * Bits to be cleared from the NB configuration register - revs F and G.
439 */
440uint32_t ao_nb_cfg_remove_revFG = AMD_NB_CFG_REMOVE_REV_FG;
441
442struct ao_nb_cfg {
443	uint32_t cfg_revmask;
444	uint32_t *cfg_add_p;
445	uint32_t *cfg_remove_p;
446};
447
448static const struct ao_nb_cfg ao_cfg_extra[] = {
449	{ AO_REVS_FG, &ao_nb_cfg_add_revFG, &ao_nb_cfg_remove_revFG },
450	{ X86_CHIPREV_UNKNOWN, NULL, NULL }
451};
452
453/*
454 * Bits to be used if we configure the NorthBridge (NB) Watchdog.  The watchdog
455 * triggers a machine check exception when no response to an NB system access
456 * occurs within a specified time interval.
457 */
458uint32_t ao_nb_cfg_wdog =
459    AMD_NB_CFG_WDOGTMRCNTSEL_4095 |
460    AMD_NB_CFG_WDOGTMRBASESEL_1MS;
461
462/*
463 * The default watchdog policy is to enable it (at the above rate) if it
464 * is disabled;  if it is enabled then we leave it enabled at the rate
465 * chosen by the BIOS.
466 */
467enum {
468	AO_NB_WDOG_LEAVEALONE,		/* Don't touch watchdog config */
469	AO_NB_WDOG_DISABLE,		/* Always disable watchdog */
470	AO_NB_WDOG_ENABLE_IF_DISABLED,	/* If disabled, enable at our rate */
471	AO_NB_WDOG_ENABLE_FORCE_RATE	/* Enable and set our rate */
472} ao_nb_watchdog_policy = AO_NB_WDOG_ENABLE_IF_DISABLED;
473
474static void
475ao_nb_cfg(ao_data_t *ao, uint32_t rev)
476{
477	const struct ao_nb_cfg *nbcp = &ao_cfg_extra[0];
478	uint_t chipid = pg_plat_hw_instance_id(CPU, PGHW_CHIP);
479	uint32_t val;
480
481	/*
482	 * Read the NorthBridge (NB) configuration register in PCI space,
483	 * modify the settings accordingly, and store the new value back.
484	 */
485	ao->ao_shared->aos_bcfg_nb_cfg = val =
486	    ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG);
487
488	switch (ao_nb_watchdog_policy) {
489	case AO_NB_WDOG_LEAVEALONE:
490		break;
491
492	case AO_NB_WDOG_DISABLE:
493		val &= ~AMD_NB_CFG_WDOGTMRBASESEL_MASK;
494		val &= ~AMD_NB_CFG_WDOGTMRCNTSEL_MASK;
495		val |= AMD_NB_CFG_WDOGTMRDIS;
496		break;
497
498	default:
499		cmn_err(CE_NOTE, "ao_nb_watchdog_policy=%d unrecognised, "
500		    "using default policy", ao_nb_watchdog_policy);
501		/*FALLTHRU*/
502
503	case AO_NB_WDOG_ENABLE_IF_DISABLED:
504		if (val & AMD_NB_CFG_WDOGTMRDIS)
505			break;	/* if enabled leave rate intact */
506		/*FALLTHRU*/
507
508	case AO_NB_WDOG_ENABLE_FORCE_RATE:
509		val &= ~AMD_NB_CFG_WDOGTMRBASESEL_MASK;
510		val &= ~AMD_NB_CFG_WDOGTMRCNTSEL_MASK;
511		val &= ~AMD_NB_CFG_WDOGTMRDIS;
512		val |= ao_nb_cfg_wdog;
513		break;
514	}
515
516	/*
517	 * Now apply bit adds and removes, first those common to all revs
518	 * and then the revision-specific ones.
519	 */
520	val &= ~ao_nb_cfg_remove_cmn;
521	val |= ao_nb_cfg_add_cmn;
522
523	while (nbcp->cfg_revmask != X86_CHIPREV_UNKNOWN) {
524		if (X86_CHIPREV_MATCH(rev, nbcp->cfg_revmask)) {
525			val &= ~(*nbcp->cfg_remove_p);
526			val |= *nbcp->cfg_add_p;
527		}
528		nbcp++;
529	}
530
531	ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG, val);
532}
533
534/*
535 * This knob exists in case any platform has a problem with our default
536 * policy of disabling any interrupt registered in the online spare
537 * control register.  Setting this may cause Solaris and external entities
538 * who also have an interest in this register to argue over available
539 * telemetry (so setting it is generally not recommended).
540 */
541int ao_nb_cfg_sparectl_noseize = 0;
542
543/*
544 * Setup the online spare control register (revs F and G).  We disable
545 * any interrupt registered by the BIOS and zero all error counts.
546 */
547static void
548ao_sparectl_cfg(ao_data_t *ao)
549{
550	uint_t chipid = pg_plat_hw_instance_id(CPU, PGHW_CHIP);
551	union mcreg_sparectl sparectl;
552	int chan, cs;
553
554	ao->ao_shared->aos_bcfg_nb_sparectl = MCREG_VAL32(&sparectl) =
555	    ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SPARECTL);
556
557	if (ao_nb_cfg_sparectl_noseize)
558		return;	/* stash BIOS value, but no changes */
559
560	/*
561	 * If the BIOS has requested SMI interrupt type for ECC count
562	 * overflow for a chip-select or channel force those off.
563	 */
564	MCREG_FIELD_revFG(&sparectl, EccErrInt) = 0;
565	MCREG_FIELD_revFG(&sparectl, SwapDoneInt) = 0;
566
567	/* Enable writing to the EccErrCnt field */
568	MCREG_FIELD_revFG(&sparectl, EccErrCntWrEn) = 1;
569
570	/* First write, preparing for writes to EccErrCnt */
571	ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SPARECTL,
572	    MCREG_VAL32(&sparectl));
573
574	/*
575	 * Zero EccErrCnt and write this back to all chan/cs combinations.
576	 */
577	MCREG_FIELD_revFG(&sparectl, EccErrCnt) = 0;
578	for (chan = 0; chan < MC_CHIP_NDRAMCHAN; chan++) {
579		MCREG_FIELD_revFG(&sparectl, EccErrCntDramChan) = chan;
580
581		for (cs = 0; cs < MC_CHIP_NCS; cs++) {
582			MCREG_FIELD_revFG(&sparectl, EccErrCntDramCs) = cs;
583			ao_pcicfg_write(chipid, AMD_NB_FUNC,
584			    AMD_NB_REG_SPARECTL, MCREG_VAL32(&sparectl));
585		}
586	}
587}
588
589/*
590 * Capture the machine-check exception state into our per-CPU logout area, and
591 * dispatch a copy of the logout area to our error queue for ereport creation.
592 * If 'rp' is non-NULL, we're being called from trap context; otherwise we're
593 * being polled or poked by the injector.  We return the number of errors
594 * found through 'np', and a boolean indicating whether the error is fatal.
595 * The caller is expected to call fm_panic() if we return fatal (non-zero).
596 */
597int
598ao_mca_logout(ao_cpu_logout_t *acl, struct regs *rp, int *np, int skipnb,
599    uint32_t rev)
600{
601	uint64_t mcg_status = rdmsr(IA32_MSR_MCG_STATUS);
602	int i, fatal = 0, n = 0;
603
604	acl->acl_timestamp = gethrtime_waitfree();
605	acl->acl_mcg_status = mcg_status;
606	acl->acl_ip = rp ? rp->r_pc : 0;
607	acl->acl_flags = 0;
608
609	/*
610	 * Iterate over the banks of machine-check registers, read the address
611	 * and status registers into the logout area, and clear status as we go.
612	 * Also read the MCi_MISC register if MCi_STATUS.MISCV indicates that
613	 * there is valid info there (as it will in revisions F and G for
614	 * NorthBridge ECC errors).
615	 */
616	for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
617		ao_bank_logout_t *abl = &acl->acl_banks[i];
618
619		if (i == AMD_MCA_BANK_NB && skipnb) {
620			abl->abl_status = 0;
621			continue;
622		}
623
624		abl->abl_addr = rdmsr(ao_bank_regs[i].abr_addr);
625		abl->abl_status = rdmsr(ao_bank_regs[i].abr_status);
626
627		if (abl->abl_status & AMD_BANK_STAT_MISCV)
628			abl->abl_misc = rdmsr(ao_bank_regs[i].abr_misc);
629		else
630			abl->abl_misc = 0;
631
632		if (abl->abl_status & AMD_BANK_STAT_VALID)
633			wrmsr(ao_bank_regs[i].abr_status, 0);
634	}
635
636	if (rp == NULL || !USERMODE(rp->r_cs))
637		acl->acl_flags |= AO_ACL_F_PRIV;
638
639	if (ao_mca_stack_flag)
640		acl->acl_stackdepth = getpcstack(acl->acl_stack, FM_STK_DEPTH);
641	else
642		acl->acl_stackdepth = 0;
643
644	/*
645	 * Clear MCG_STATUS, indicating that machine-check trap processing is
646	 * complete.  Once we do this, another machine-check trap can occur
647	 * (if another occurs up to this point then the system will reset).
648	 */
649	if (mcg_status & MCG_STATUS_MCIP)
650		wrmsr(IA32_MSR_MCG_STATUS, 0);
651
652	/*
653	 * If we took a machine-check trap, then the error is fatal if the
654	 * return instruction pointer is not valid in the global register.
655	 */
656	if (rp != NULL && !(acl->acl_mcg_status & MCG_STATUS_RIPV))
657		fatal++;
658
659	/*
660	 * Now iterate over the saved logout area, determining whether the
661	 * error that we saw is fatal or not based upon our dispositions
662	 * and the hardware's indicators of whether or not we can resume.
663	 */
664	for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
665		ao_bank_logout_t *abl = &acl->acl_banks[i];
666		const ao_error_disp_t *aed;
667		uint8_t when;
668
669		if (!(abl->abl_status & AMD_BANK_STAT_VALID))
670			continue;
671
672		aed = ao_disp_match(i, abl->abl_status, rev);
673		if ((when = aed->aed_panic_when) != AO_AED_PANIC_NEVER) {
674			if ((when & AO_AED_PANIC_ALWAYS) ||
675			    ((when & AO_AED_PANIC_IFMCE) && rp != NULL)) {
676					fatal++;
677			}
678		}
679
680		/*
681		 * If we are taking a machine-check exception and our context
682		 * is corrupt, then we must die.
683		 */
684		if (rp != NULL && abl->abl_status & AMD_BANK_STAT_PCC)
685			fatal++;
686
687		/*
688		 * The overflow bit is set if the bank detects an error but
689		 * the valid bit of its status register is already set
690		 * (software has not yet read and cleared it).  Enabled
691		 * (for mc# reporting) errors overwrite disabled errors,
692		 * uncorrectable errors overwrite correctable errors,
693		 * uncorrectable errors are not overwritten.
694		 *
695		 * For the NB detector bank the overflow bit will not be
696		 * set for repeated correctable errors on revisions D and
697		 * earlier; it will be set on revisions E and later.
698		 * On revision E, however, the CorrECC bit does appear
699		 * to clear in these circumstances.  Since we can enable
700		 * machine-check exception on NB correctables we need to
701		 * be careful here; we never enable mc# for correctable from
702		 * other banks.
703		 *
704		 * Our solution will be to declare a machine-check exception
705		 * fatal if the overflow bit is set except in the case of
706		 * revision F on the NB detector bank for which CorrECC
707		 * is indicated.  Machine-check exception for NB correctables
708		 * on rev E is explicitly not supported.
709		 */
710		if (rp != NULL && abl->abl_status & AMD_BANK_STAT_OVER &&
711		    !(i == AMD_MCA_BANK_NB &&
712		    X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) &&
713		    abl->abl_status & AMD_BANK_STAT_CECC))
714			fatal++;
715
716		/*
717		 * If we are taking a machine-check exception and we don't
718		 * recognize the error case at all, then assume it's fatal.
719		 * This will need to change if we eventually use the Opteron
720		 * Rev E exception mechanism for detecting correctable errors.
721		 */
722		if (rp != NULL && aed == &ao_disp_unknown)
723			fatal++;
724
725		abl->abl_addr_type = aed->aed_flags & AO_AED_FLAGS_ADDRTYPE;
726		abl->abl_addr_valid_hi = aed->aed_addrvalid_hi;
727		abl->abl_addr_valid_lo = aed->aed_addrvalid_lo;
728		n++;
729	}
730
731	if (n > 0) {
732		errorq_dispatch(ao_mca_queue, acl, sizeof (ao_cpu_logout_t),
733		    fatal && cmi_panic_on_uncorrectable_error ?
734		    ERRORQ_SYNC : ERRORQ_ASYNC);
735	}
736
737	if (np != NULL)
738		*np = n; /* return number of errors found to caller */
739
740	return (fatal != 0);
741}
742
743static uint_t
744ao_ereport_synd(ao_data_t *ao, const ao_bank_logout_t *abl, uint_t *typep,
745    int is_nb)
746{
747	if (is_nb) {
748		if (ao->ao_shared->aos_bcfg_nb_cfg & AMD_NB_CFG_CHIPKILLECCEN) {
749			*typep = AMD_SYNDTYPE_CHIPKILL;
750			return (AMD_NB_STAT_CKSYND(abl->abl_status));
751		} else {
752			*typep = AMD_SYNDTYPE_ECC;
753			return (AMD_BANK_SYND(abl->abl_status));
754		}
755	} else {
756		*typep = AMD_SYNDTYPE_ECC;
757		return (AMD_BANK_SYND(abl->abl_status));
758	}
759}
760
761static void
762ao_ereport_create_resource_elem(nvlist_t **nvlp, nv_alloc_t *nva,
763    mc_unum_t *unump, int dimmnum)
764{
765	nvlist_t *snvl;
766	*nvlp = fm_nvlist_create(nva);		/* freed by caller */
767
768	snvl = fm_nvlist_create(nva);
769
770	(void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
771	    unump->unum_offset);
772
773	fm_fmri_hc_set(*nvlp, FM_HC_SCHEME_VERSION, NULL, snvl, 5,
774	    "motherboard", unump->unum_board,
775	    "chip", unump->unum_chip,
776	    "memory-controller", unump->unum_mc,
777	    "dimm", unump->unum_dimms[dimmnum],
778	    "rank", unump->unum_rank);
779
780	fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
781}
782
783static void
784ao_ereport_add_resource(nvlist_t *payload, nv_alloc_t *nva, mc_unum_t *unump)
785{
786
787	nvlist_t *elems[MC_UNUM_NDIMM];
788	int nelems = 0;
789	int i;
790
791	for (i = 0; i < MC_UNUM_NDIMM; i++) {
792		if (unump->unum_dimms[i] == MC_INVALNUM)
793			break;
794		ao_ereport_create_resource_elem(&elems[nelems++], nva,
795		    unump, i);
796	}
797
798	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
799	    DATA_TYPE_NVLIST_ARRAY, nelems, elems, NULL);
800
801	for (i = 0; i < nelems; i++)
802		fm_nvlist_destroy(elems[i], nva ? FM_NVA_RETAIN : FM_NVA_FREE);
803}
804
805static void
806ao_ereport_add_logout(ao_data_t *ao, nvlist_t *payload, nv_alloc_t *nva,
807    const ao_cpu_logout_t *acl, uint_t bankno, const ao_error_disp_t *aed)
808{
809	uint64_t members = aed->aed_ereport_members;
810	const ao_bank_logout_t *abl = &acl->acl_banks[bankno];
811	uint_t synd, syndtype;
812
813	synd = ao_ereport_synd(ao, abl, &syndtype, bankno == AMD_MCA_BANK_NB);
814
815	if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_STAT) {
816		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_STAT,
817		    DATA_TYPE_UINT64, abl->abl_status, NULL);
818	}
819
820	if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_NUM) {
821		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_NUM,
822		    DATA_TYPE_UINT8, bankno, NULL);
823	}
824
825	if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) {
826		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR,
827		    DATA_TYPE_UINT64, abl->abl_addr, NULL);
828	}
829
830	if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) {
831		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR_VALID,
832		    DATA_TYPE_BOOLEAN_VALUE, (abl->abl_status &
833		    AMD_BANK_STAT_ADDRV) ? B_TRUE : B_FALSE, NULL);
834	}
835
836	if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_MISC) {
837		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_MISC,
838		    DATA_TYPE_UINT64, abl->abl_misc, NULL);
839	}
840
841	if (members & FM_EREPORT_PAYLOAD_FLAG_SYND) {
842		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND,
843		    DATA_TYPE_UINT16, synd, NULL);
844	}
845
846	if (members & FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE) {
847		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND_TYPE,
848		    DATA_TYPE_STRING, (syndtype == AMD_SYNDTYPE_CHIPKILL ?
849		    "C" : "E"), NULL);
850	}
851
852	if (members & FM_EREPORT_PAYLOAD_FLAG_IP) {
853		uint64_t ip = (acl->acl_mcg_status & MCG_STATUS_EIPV) ?
854		    acl->acl_ip : 0;
855		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_IP,
856		    DATA_TYPE_UINT64, ip, NULL);
857	}
858
859	if (members & FM_EREPORT_PAYLOAD_FLAG_PRIV) {
860		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PRIV,
861		    DATA_TYPE_BOOLEAN_VALUE, (acl->acl_flags & AO_ACL_F_PRIV) ?
862		    B_TRUE : B_FALSE, NULL);
863	}
864
865	if (members & FM_EREPORT_PAYLOAD_FLAG_RESOURCE) {
866		mc_unum_t unum;
867		int addrvalid = 0;
868
869		if (abl->abl_addr_type & AO_AED_F_PHYSICAL) {
870			addrvalid = (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) &&
871			    (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) &&
872			    (abl->abl_status & AMD_BANK_STAT_ADDRV);
873		}
874
875		if (addrvalid && ao_mc_patounum(ao, abl->abl_addr,
876		    abl->abl_addr_valid_hi, abl->abl_addr_valid_lo,
877		    synd, syndtype, &unum))
878			ao_ereport_add_resource(payload, nva, &unum);
879	}
880
881	if (ao_mca_stack_flag && members & FM_EREPORT_PAYLOAD_FLAG_STACK) {
882		fm_payload_stack_add(payload, acl->acl_stack,
883		    acl->acl_stackdepth);
884	}
885}
886
887static void
888ao_ereport_post(const ao_cpu_logout_t *acl,
889    int bankno, const ao_error_disp_t *aed)
890{
891	ao_data_t *ao = acl->acl_ao;
892	errorq_elem_t *eqep, *scr_eqep;
893	nvlist_t *ereport, *detector;
894	nv_alloc_t *nva = NULL;
895	char buf[FM_MAX_CLASS];
896
897	if (panicstr) {
898		if ((eqep = errorq_reserve(ereport_errorq)) == NULL)
899			return;
900		ereport = errorq_elem_nvl(ereport_errorq, eqep);
901
902		/*
903		 * Now try to allocate another element for scratch space and
904		 * use that for further scratch space (eg for constructing
905		 * nvlists to add the main ereport).  If we can't reserve
906		 * a scratch element just fallback to working within the
907		 * element we already have, and hope for the best.  All this
908		 * is necessary because the fixed buffer nv allocator does
909		 * not reclaim freed space and nvlist construction is
910		 * expensive.
911		 */
912		if ((scr_eqep = errorq_reserve(ereport_errorq)) != NULL)
913			nva = errorq_elem_nva(ereport_errorq, scr_eqep);
914		else
915			nva = errorq_elem_nva(ereport_errorq, eqep);
916	} else {
917		ereport = fm_nvlist_create(NULL);
918	}
919
920	/*
921	 * Create the "hc" scheme detector FMRI identifying this cpu
922	 */
923	detector = ao_fmri_create(ao, nva);
924
925	/*
926	 * Encode all the common data into the ereport.
927	 */
928	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s",
929	    FM_ERROR_CPU, "amd", aed->aed_class);
930
931	fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
932	    fm_ena_generate_cpu(acl->acl_timestamp, ao->ao_cpu->cpu_id,
933	    FM_ENA_FMT1), detector, NULL);
934
935	/*
936	 * We're done with 'detector' so reclaim the scratch space.
937	 */
938	if (panicstr) {
939		fm_nvlist_destroy(detector, FM_NVA_RETAIN);
940		nv_alloc_reset(nva);
941	} else {
942		fm_nvlist_destroy(detector, FM_NVA_FREE);
943	}
944
945	/*
946	 * Encode the error-specific data that was saved in the logout area.
947	 */
948	ao_ereport_add_logout(ao, ereport, nva, acl, bankno, aed);
949
950	if (panicstr) {
951		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
952		if (scr_eqep)
953			errorq_cancel(ereport_errorq, scr_eqep);
954	} else {
955		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
956		fm_nvlist_destroy(ereport, FM_NVA_FREE);
957	}
958}
959
960/*ARGSUSED*/
961void
962ao_mca_drain(void *ignored, const void *data, const errorq_elem_t *eqe)
963{
964	const ao_cpu_logout_t *acl = data;
965	uint32_t rev = acl->acl_ao->ao_shared->aos_chiprev;
966	int i;
967
968	for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
969		const ao_bank_logout_t *abl = &acl->acl_banks[i];
970		const ao_error_disp_t *aed;
971
972		if (abl->abl_status & AMD_BANK_STAT_VALID) {
973			aed = ao_disp_match(i, abl->abl_status, rev);
974			ao_ereport_post(acl, i, aed);
975		}
976	}
977}
978
979/*
980 * Machine check interrupt handler - we jump here from mcetrap.
981 *
982 * A sibling core may attempt to poll the NorthBridge during the
983 * time we are performing the logout.  So we coordinate NB access
984 * of all cores of the same chip via a per-chip lock.  If the lock
985 * is held on a sibling core then we spin for it here; if the
986 * lock is held by the thread we have interrupted then we do
987 * not acquire the lock but can proceed safe in the knowledge that
988 * the lock owner can't actually perform any NB accesses.  This
989 * requires that threads that take the aos_nb_poll_lock do not
990 * block and that they disable preemption while they hold the lock.
991 * It also requires that the lock be adaptive since mutex_owner does
992 * not work for spin locks.
993 */
994static int ao_mca_path1, ao_mca_path2;
995int
996ao_mca_trap(void *data, struct regs *rp)
997{
998	ao_data_t *ao = data;
999	ao_mca_t *mca = &ao->ao_mca;
1000	ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_EXCEPTION];
1001	kmutex_t *nblock = NULL;
1002	int tooklock = 0;
1003	int rv;
1004
1005	if (ao->ao_shared != NULL)
1006		nblock = &ao->ao_shared->aos_nb_poll_lock;
1007
1008	if (nblock && !mutex_owned(nblock)) {
1009		/*
1010		 * The mutex is not owned by the thread we have interrupted
1011		 * (since the holder may not block or be preempted once the
1012		 * lock is acquired).  We will spin for this adaptive lock.
1013		 */
1014		++ao_mca_path1;
1015		while (!mutex_tryenter(nblock)) {
1016			while (mutex_owner(nblock) != NULL)
1017				;
1018		}
1019		tooklock = 1;
1020	} else {
1021		++ao_mca_path2;
1022	}
1023
1024	rv = ao_mca_logout(acl, rp, NULL, 0, ao->ao_shared->aos_chiprev);
1025
1026	if (tooklock)
1027		mutex_exit(&ao->ao_shared->aos_nb_poll_lock);
1028
1029	return (rv);
1030}
1031
1032/*ARGSUSED*/
1033int
1034ao_mca_inject(void *data, cmi_mca_regs_t *regs, uint_t nregs)
1035{
1036	uint64_t hwcr, oldhwcr;
1037	int i;
1038
1039	oldhwcr = rdmsr(MSR_AMD_HWCR);
1040	hwcr = oldhwcr | AMD_HWCR_MCI_STATUS_WREN;
1041	wrmsr(MSR_AMD_HWCR, hwcr);
1042
1043	for (i = 0; i < nregs; i++)
1044		wrmsr(regs[i].cmr_msrnum, regs[i].cmr_msrval);
1045
1046	wrmsr(MSR_AMD_HWCR, oldhwcr);
1047	return (0);
1048}
1049
1050void
1051ao_mca_init(void *data)
1052{
1053	ao_data_t *ao = data;
1054	ao_mca_t *mca = &ao->ao_mca;
1055	uint64_t cap;
1056	uint32_t rev;
1057	int donb;
1058	int i;
1059
1060	ASSERT(x86_feature & X86_MCA);
1061	cap = rdmsr(IA32_MSR_MCG_CAP);
1062	ASSERT(cap & MCG_CAP_CTL_P);
1063
1064	/*
1065	 * If the hardware's bank count is different than what we expect, then
1066	 * we're running on some Opteron variant that we don't understand yet.
1067	 */
1068	if ((cap & MCG_CAP_COUNT_MASK) != AMD_MCA_BANK_COUNT) {
1069		cmn_err(CE_WARN, "CPU %d has %llu MCA banks; expected %u: "
1070		    "disabling MCA on this CPU", ao->ao_cpu->cpu_id,
1071		    (u_longlong_t)cap & MCG_CAP_COUNT_MASK, AMD_MCA_BANK_COUNT);
1072		return;
1073	}
1074
1075	/*
1076	 * Configure the logout areas.  We preset every logout area's acl_ao
1077	 * pointer to refer back to our per-CPU state for errorq drain usage.
1078	 */
1079	for (i = 0; i < AO_MCA_LOGOUT_NUM; i++)
1080		mca->ao_mca_logout[i].acl_ao = ao;
1081
1082	/* LINTED: logical expression always true */
1083	ASSERT(sizeof (ao_bank_cfgs) / sizeof (ao_bank_cfg_t) ==
1084	    AMD_MCA_BANK_COUNT);
1085
1086	rev = ao->ao_shared->aos_chiprev = cpuid_getchiprev(ao->ao_cpu);
1087
1088	/*
1089	 * Must this core perform NB MCA configuration?  This must be done
1090	 * by just one core.
1091	 */
1092	donb = ao_chip_once(ao, AO_CFGONCE_NBMCA);
1093
1094	/*
1095	 * Initialize poller data, but don't start polling yet.
1096	 */
1097	ao_mca_poll_init(ao, donb);
1098
1099	/*
1100	 * Configure the bank MCi_CTL register to nominate which error
1101	 * types for each bank will produce a machine-check (we'll poll
1102	 * for others).  Correctable error types mentioned in these MCi_CTL
1103	 * settings won't actually produce an exception unless an additional
1104	 * (and undocumented) bit is set elsewhere - the poller must still
1105	 * handle these.
1106	 */
1107	ao_bank_cfg(ao, rev, donb);
1108
1109	/*
1110	 * Modify the MCA NB Configuration Register.
1111	 */
1112	if (donb)
1113		ao_nb_cfg(ao, rev);
1114
1115	/*
1116	 * Setup the Online Spare Control Register
1117	 */
1118	if (donb && X86_CHIPREV_MATCH(rev, AO_REVS_FG)) {
1119		ao_sparectl_cfg(ao);
1120	}
1121
1122	/*
1123	 * Enable all error reporting banks (icache, dcache, ...).  This
1124	 * enables error detection, as opposed to error reporting above.
1125	 */
1126	wrmsr(IA32_MSR_MCG_CTL, AMD_MCG_EN_ALL);
1127
1128	/*
1129	 * Throw away all existing bank state.  We do this because some BIOSes,
1130	 * perhaps during POST, do things to the machine that cause MCA state
1131	 * to be updated.  If we interpret this state as an actual error, we
1132	 * may end up indicting something that's not actually broken.
1133	 */
1134	for (i = 0; i < AMD_MCA_BANK_COUNT; i++) {
1135		if (!donb)
1136			continue;
1137
1138		wrmsr(ao_bank_cfgs[i].bank_status, 0ULL);
1139	}
1140
1141	wrmsr(IA32_MSR_MCG_STATUS, 0ULL);
1142	membar_producer();
1143
1144	setcr4(getcr4() | CR4_MCE); /* enable #mc exceptions */
1145}
1146
1147/*
1148 * Note that although this cpu module is loaded before the PSMs are
1149 * loaded (and hence before acpica is loaded), this function is
1150 * called from post_startup(), after PSMs are initialized and acpica
1151 * is loaded.
1152 */
1153static int
1154ao_acpi_find_smicmd(int *asd_port)
1155{
1156	FADT_DESCRIPTOR *fadt = NULL;
1157
1158	/*
1159	 * AcpiGetFirmwareTable works even if ACPI is disabled, so a failure
1160	 * here means we weren't able to retreive a pointer to the FADT.
1161	 */
1162	if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING,
1163	    (ACPI_TABLE_HEADER **)&fadt) != AE_OK)
1164		return (-1);
1165
1166	ASSERT(fadt != NULL);
1167
1168	*asd_port = fadt->SmiCmd;
1169	return (0);
1170}
1171
1172/*ARGSUSED*/
1173void
1174ao_mca_post_init(void *data)
1175{
1176	const struct ao_smi_disable *asd;
1177	id_t id;
1178	int rv = -1, asd_port;
1179
1180	smbios_system_t sy;
1181	smbios_bios_t sb;
1182	smbios_info_t si;
1183
1184	/*
1185	 * Fetch the System and BIOS vendor strings from SMBIOS and see if they
1186	 * match a value in our table.  If so, disable SMI error polling.  This
1187	 * is grotesque and should be replaced by self-describing vendor-
1188	 * specific SMBIOS data or a specification enhancement instead.
1189	 */
1190	if (ao_mca_smi_disable && ksmbios != NULL &&
1191	    smbios_info_bios(ksmbios, &sb) != SMB_ERR &&
1192	    (id = smbios_info_system(ksmbios, &sy)) != SMB_ERR &&
1193	    smbios_info_common(ksmbios, id, &si) != SMB_ERR) {
1194
1195		for (asd = ao_smi_disable; asd->asd_sys_vendor != NULL; asd++) {
1196			if (strncmp(asd->asd_sys_vendor, si.smbi_manufacturer,
1197			    strlen(asd->asd_sys_vendor)) != 0 ||
1198			    strncmp(asd->asd_sys_product, si.smbi_product,
1199			    strlen(asd->asd_sys_product)) != 0 ||
1200			    strncmp(asd->asd_bios_vendor, sb.smbb_vendor,
1201			    strlen(asd->asd_bios_vendor)) != 0)
1202				continue;
1203
1204			/*
1205			 * Look for the SMI_CMD port in the ACPI FADT,
1206			 * if the port is 0, this platform doesn't support
1207			 * SMM, so there is no SMI error polling to disable.
1208			 */
1209			if ((rv = ao_acpi_find_smicmd(&asd_port)) == 0 &&
1210			    asd_port != 0) {
1211				cmn_err(CE_CONT, "?SMI polling disabled in "
1212				    "favor of Solaris Fault Management for "
1213				    "AMD Processors\n");
1214
1215				outb(asd_port, asd->asd_code);
1216
1217			} else if (rv < 0) {
1218				cmn_err(CE_CONT, "?Solaris Fault Management "
1219				    "for AMD Processors could not disable SMI "
1220				    "polling because an error occurred while "
1221				    "trying to determine the SMI command port "
1222				    "from the ACPI FADT table\n");
1223			}
1224			break;
1225		}
1226	}
1227
1228	ao_mca_poll_start();
1229}
1230
1231/*
1232 * Called after a CPU has been marked with CPU_FAULTED.  Not called on the
1233 * faulted CPU.  cpu_lock is held.
1234 */
1235/*ARGSUSED*/
1236void
1237ao_faulted_enter(void *data)
1238{
1239	/*
1240	 * Nothing to do here.  We'd like to turn off the faulted CPU's
1241	 * correctable error detectors, but that can only be done by the
1242	 * faulted CPU itself.  cpu_get_state() will now return P_FAULTED,
1243	 * allowing the poller to skip this CPU until it is re-enabled.
1244	 */
1245}
1246
1247/*
1248 * Called after the CPU_FAULTED bit has been cleared from a previously-faulted
1249 * CPU.  Not called on the faulted CPU.  cpu_lock is held.
1250 */
1251void
1252ao_faulted_exit(void *data)
1253{
1254	ao_data_t *ao = data;
1255
1256	/*
1257	 * We'd like to clear the faulted CPU's MCi_STATUS registers so as to
1258	 * avoid generating ereports for errors which occurred while the CPU was
1259	 * officially faulted.  Unfortunately, those registers can only be
1260	 * cleared by the CPU itself, so we can't do it here.
1261	 *
1262	 * We're going to set the UNFAULTING bit on the formerly-faulted CPU's
1263	 * MCA state.  This will tell the poller that the MCi_STATUS registers
1264	 * can't yet be trusted.  The poller, which is the first thing we
1265	 * control that'll execute on that CPU, will clear the registers, and
1266	 * will then clear the bit.
1267	 */
1268
1269	ao->ao_mca.ao_mca_flags |= AO_MCA_F_UNFAULTING;
1270}
1271