xref: /onnv-gate/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c (revision 5254:38162db71c7d)
1*5254Sgavinm /*
2*5254Sgavinm  * CDDL HEADER START
3*5254Sgavinm  *
4*5254Sgavinm  * The contents of this file are subject to the terms of the
5*5254Sgavinm  * Common Development and Distribution License (the "License").
6*5254Sgavinm  * You may not use this file except in compliance with the License.
7*5254Sgavinm  *
8*5254Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5254Sgavinm  * or http://www.opensolaris.org/os/licensing.
10*5254Sgavinm  * See the License for the specific language governing permissions
11*5254Sgavinm  * and limitations under the License.
12*5254Sgavinm  *
13*5254Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
14*5254Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5254Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
16*5254Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
17*5254Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5254Sgavinm  *
19*5254Sgavinm  * CDDL HEADER END
20*5254Sgavinm  */
21*5254Sgavinm 
22*5254Sgavinm /*
23*5254Sgavinm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*5254Sgavinm  * Use is subject to license terms.
25*5254Sgavinm  */
26*5254Sgavinm 
27*5254Sgavinm #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*5254Sgavinm 
29*5254Sgavinm /*
30*5254Sgavinm  * "Generic AMD" model-specific support.  If no more-specific support can
31*5254Sgavinm  * be found, or such modules declines to initialize, then for AuthenticAMD
32*5254Sgavinm  * cpus this module can have a crack at providing some AMD model-specific
33*5254Sgavinm  * support that at least goes beyond common MCA architectural features
34*5254Sgavinm  * if not down to the nitty-gritty level for a particular model.  We
35*5254Sgavinm  * are layered on top of a cpu module, likely cpu.generic, so there is no
36*5254Sgavinm  * need for us to perform common architecturally-accessible functions.
37*5254Sgavinm  */
38*5254Sgavinm 
39*5254Sgavinm #include <sys/types.h>
40*5254Sgavinm #include <sys/cmn_err.h>
41*5254Sgavinm #include <sys/modctl.h>
42*5254Sgavinm #include <sys/cpu_module.h>
43*5254Sgavinm #include <sys/mca_x86.h>
44*5254Sgavinm #include <sys/pci_cfgspace.h>
45*5254Sgavinm #include <sys/x86_archext.h>
46*5254Sgavinm #include <sys/mc_amd.h>
47*5254Sgavinm #include <sys/fm/protocol.h>
48*5254Sgavinm #include <sys/fm/cpu/GENAMD.h>
49*5254Sgavinm #include <sys/nvpair.h>
50*5254Sgavinm #include <sys/controlregs.h>
51*5254Sgavinm #include <sys/pghw.h>
52*5254Sgavinm #include <sys/sunddi.h>
53*5254Sgavinm #include <sys/cpu_module_ms_impl.h>
54*5254Sgavinm 
55*5254Sgavinm #include "authamd.h"
56*5254Sgavinm 
57*5254Sgavinm int authamd_ms_support_disable = 0;
58*5254Sgavinm 
59*5254Sgavinm #define	AUTHAMD_F_REVS_BCDE \
60*5254Sgavinm 	(X86_CHIPREV_AMD_F_REV_B | X86_CHIPREV_AMD_F_REV_C0 | \
61*5254Sgavinm 	X86_CHIPREV_AMD_F_REV_CG | X86_CHIPREV_AMD_F_REV_D | \
62*5254Sgavinm 	X86_CHIPREV_AMD_F_REV_E)
63*5254Sgavinm 
64*5254Sgavinm #define	AUTHAMD_F_REVS_FG \
65*5254Sgavinm 	(X86_CHIPREV_AMD_F_REV_F | X86_CHIPREV_AMD_F_REV_G)
66*5254Sgavinm 
67*5254Sgavinm #define	AUTHAMD_10_REVS_AB \
68*5254Sgavinm 	(X86_CHIPREV_AMD_10_REV_A | X86_CHIPREV_AMD_10_REV_B)
69*5254Sgavinm 
70*5254Sgavinm /*
71*5254Sgavinm  * Bitmasks of support for various features.  Try to enable features
72*5254Sgavinm  * via inclusion in one of these bitmasks and check that at the
73*5254Sgavinm  * feature imlementation - that way new family support may often simply
74*5254Sgavinm  * simply need to update these bitmasks.
75*5254Sgavinm  */
76*5254Sgavinm 
77*5254Sgavinm /*
78*5254Sgavinm  * Families that this module will provide some model-specific
79*5254Sgavinm  * support for (if no more-specific module claims it first).
80*5254Sgavinm  * We try to support whole families rather than differentiate down
81*5254Sgavinm  * to revision.
82*5254Sgavinm  */
83*5254Sgavinm #define	AUTHAMD_SUPPORTED(fam) \
84*5254Sgavinm 	((fam) == AUTHAMD_FAMILY_6 || (fam) == AUTHAMD_FAMILY_F || \
85*5254Sgavinm 	(fam) == AUTHAMD_FAMILY_10)
86*5254Sgavinm 
87*5254Sgavinm /*
88*5254Sgavinm  * Families/revisions for which we can recognise main memory ECC errors.
89*5254Sgavinm  */
90*5254Sgavinm #define	AUTHAMD_MEMECC_RECOGNISED(rev) \
91*5254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
92*5254Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
93*5254Sgavinm 
94*5254Sgavinm /*
95*5254Sgavinm  * Families/revisions that have an Online Spare Control Register
96*5254Sgavinm  */
97*5254Sgavinm #define	AUTHAMD_HAS_ONLINESPARECTL(rev) \
98*5254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) || \
99*5254Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
100*5254Sgavinm 
101*5254Sgavinm /*
102*5254Sgavinm  * Families/revisions that have a NB misc register or registers -
103*5254Sgavinm  * evaluates to 0 if no support, otherwise the number of MC4_MISCj.
104*5254Sgavinm  */
105*5254Sgavinm #define	AUTHAMD_NBMISC_NUM(rev) \
106*5254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F)? 1 : \
107*5254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A) ? 3 : 0))
108*5254Sgavinm 
109*5254Sgavinm /*
110*5254Sgavinm  * Families/revision for which we wish not to machine check for GART
111*5254Sgavinm  * table walk errors - bit 10 of NB CTL.
112*5254Sgavinm  */
113*5254Sgavinm #define	AUTHAMD_NOGARTTBLWLK_MC(rev) \
114*5254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
115*5254Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
116*5254Sgavinm 
117*5254Sgavinm /*
118*5254Sgavinm  * We recognise main memory ECC errors for AUTHAMD_MEMECC_RECOGNISED
119*5254Sgavinm  * revisions as:
120*5254Sgavinm  *
121*5254Sgavinm  *	- being reported by the NB
122*5254Sgavinm  *	- being a compound bus/interconnect error (external to chip)
123*5254Sgavinm  *	- having LL of LG
124*5254Sgavinm  *	- having II of MEM (but could still be a master/target abort)
125*5254Sgavinm  *	- having CECC or UECC set
126*5254Sgavinm  *
127*5254Sgavinm  * We do not check the extended error code (first nibble of the
128*5254Sgavinm  * model-specific error code on AMD) since this has changed from
129*5254Sgavinm  * family 0xf to family 0x10 (ext code 0 now reserved on family 0x10).
130*5254Sgavinm  * Instead we use CECC/UECC to separate off the master/target
131*5254Sgavinm  * abort cases.
132*5254Sgavinm  *
133*5254Sgavinm  * We insist that the detector be the NorthBridge bank;  although
134*5254Sgavinm  * IC/DC can report some main memory errors, they do not capture
135*5254Sgavinm  * an address at sufficient resolution to be useful and the NB will
136*5254Sgavinm  * report most errors.
137*5254Sgavinm  */
138*5254Sgavinm #define	AUTHAMD_IS_MEMECCERR(bank, status) \
139*5254Sgavinm 	((bank) == AMD_MCA_BANK_NB && \
140*5254Sgavinm 	MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && \
141*5254Sgavinm 	MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
142*5254Sgavinm 	MCAX86_ERRCODE_II(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_II_MEM && \
143*5254Sgavinm 	((status) & (AMD_BANK_STAT_CECC | AMD_BANK_STAT_UECC)))
144*5254Sgavinm 
145*5254Sgavinm static authamd_error_disp_t authamd_memce_disp = {
146*5254Sgavinm 	FM_EREPORT_CPU_GENAMD,
147*5254Sgavinm 	FM_EREPORT_CPU_GENAMD_MEM_CE,
148*5254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_CE
149*5254Sgavinm };
150*5254Sgavinm 
151*5254Sgavinm static authamd_error_disp_t authamd_memue_disp = {
152*5254Sgavinm 	FM_EREPORT_CPU_GENAMD,
153*5254Sgavinm 	FM_EREPORT_CPU_GENAMD_MEM_UE,
154*5254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_UE
155*5254Sgavinm };
156*5254Sgavinm 
157*5254Sgavinm static authamd_error_disp_t authamd_ckmemce_disp = {
158*5254Sgavinm 	FM_EREPORT_CPU_GENAMD,
159*5254Sgavinm 	FM_EREPORT_CPU_GENAMD_CKMEM_CE,
160*5254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_CE
161*5254Sgavinm };
162*5254Sgavinm 
163*5254Sgavinm static authamd_error_disp_t authamd_ckmemue_disp = {
164*5254Sgavinm 	FM_EREPORT_CPU_GENAMD,
165*5254Sgavinm 	FM_EREPORT_CPU_GENAMD_CKMEM_UE,
166*5254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_UE
167*5254Sgavinm };
168*5254Sgavinm 
169*5254Sgavinm /*
170*5254Sgavinm  * We recognise GART walk errors as:
171*5254Sgavinm  *
172*5254Sgavinm  *	- being reported by the NB
173*5254Sgavinm  *	- being a compound TLB error
174*5254Sgavinm  *	- having LL of LG and TT of GEN
175*5254Sgavinm  *	- having UC set
176*5254Sgavinm  *	- possibly having PCC set (if source CPU)
177*5254Sgavinm  */
178*5254Sgavinm #define	AUTHAMD_IS_GARTERR(bank, status) \
179*5254Sgavinm 	((bank) == AMD_MCA_BANK_NB && \
180*5254Sgavinm 	MCAX86_ERRCODE_ISTLB(MCAX86_ERRCODE(status)) && \
181*5254Sgavinm 	MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
182*5254Sgavinm 	MCAX86_ERRCODE_TT(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_TT_GEN && \
183*5254Sgavinm 	(status) & MSR_MC_STATUS_UC)
184*5254Sgavinm 
185*5254Sgavinm static authamd_error_disp_t authamd_gart_disp = {
186*5254Sgavinm 	FM_EREPORT_CPU_GENAMD,			/* use generic subclass */
187*5254Sgavinm 	FM_EREPORT_CPU_GENADM_GARTTBLWLK,	/* use generic leafclass */
188*5254Sgavinm 	0					/* no additional payload */
189*5254Sgavinm };
190*5254Sgavinm 
191*5254Sgavinm 
192*5254Sgavinm static struct authamd_chipshared *authamd_shared[AUTHAMD_MAX_CHIPS];
193*5254Sgavinm 
194*5254Sgavinm static int
195*5254Sgavinm authamd_chip_once(authamd_data_t *authamd, enum authamd_cfgonce_bitnum what)
196*5254Sgavinm {
197*5254Sgavinm 	return (atomic_set_long_excl(&authamd->amd_shared->acs_cfgonce,
198*5254Sgavinm 	    what) == 0 ?  B_TRUE : B_FALSE);
199*5254Sgavinm }
200*5254Sgavinm 
201*5254Sgavinm static void
202*5254Sgavinm authamd_pcicfg_write(uint_t chipid, uint_t func, uint_t reg, uint32_t val)
203*5254Sgavinm {
204*5254Sgavinm 	ASSERT(chipid + 24 <= 31);
205*5254Sgavinm 	ASSERT((func & 7) == func);
206*5254Sgavinm 	ASSERT((reg & 3) == 0 && reg < 256);
207*5254Sgavinm 
208*5254Sgavinm 	cmi_pci_putl(0, chipid + 24, func, reg, 0, val);
209*5254Sgavinm }
210*5254Sgavinm 
211*5254Sgavinm static uint32_t
212*5254Sgavinm authamd_pcicfg_read(uint_t chipid, uint_t func, uint_t reg)
213*5254Sgavinm {
214*5254Sgavinm 	ASSERT(chipid + 24 <= 31);
215*5254Sgavinm 	ASSERT((func & 7) == func);
216*5254Sgavinm 	ASSERT((reg & 3) == 0 && reg < 256);
217*5254Sgavinm 
218*5254Sgavinm 	return (cmi_pci_getl(0, chipid + 24, func, reg, 0, 0));
219*5254Sgavinm }
220*5254Sgavinm 
221*5254Sgavinm void
222*5254Sgavinm authamd_bankstatus_prewrite(cmi_hdl_t hdl, authamd_data_t *authamd)
223*5254Sgavinm {
224*5254Sgavinm 	uint64_t hwcr;
225*5254Sgavinm 
226*5254Sgavinm 	if (cmi_hdl_rdmsr(hdl, MSR_AMD_HWCR, &hwcr) != CMI_SUCCESS)
227*5254Sgavinm 		return;
228*5254Sgavinm 
229*5254Sgavinm 	authamd->amd_hwcr = hwcr;
230*5254Sgavinm 
231*5254Sgavinm 	if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
232*5254Sgavinm 		hwcr |= AMD_HWCR_MCI_STATUS_WREN;
233*5254Sgavinm 		(void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
234*5254Sgavinm 	}
235*5254Sgavinm }
236*5254Sgavinm 
237*5254Sgavinm void
238*5254Sgavinm authamd_bankstatus_postwrite(cmi_hdl_t hdl, authamd_data_t *authamd)
239*5254Sgavinm {
240*5254Sgavinm 	uint64_t hwcr = authamd->amd_hwcr;
241*5254Sgavinm 
242*5254Sgavinm 	if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
243*5254Sgavinm 		hwcr &= ~AMD_HWCR_MCI_STATUS_WREN;
244*5254Sgavinm 		(void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
245*5254Sgavinm 	}
246*5254Sgavinm }
247*5254Sgavinm 
248*5254Sgavinm /*
249*5254Sgavinm  * Read EccCnt repeatedly for all possible channel/chip-select combos:
250*5254Sgavinm  *
251*5254Sgavinm  *	- read sparectl register
252*5254Sgavinm  *	- if EccErrCntWrEn is set, clear that bit in the just-read value
253*5254Sgavinm  *	  and write it back to sparectl;  this *may* clobber the EccCnt
254*5254Sgavinm  *	  for the channel/chip-select combination currently selected, so
255*5254Sgavinm  *	  we leave this bit clear if we had to clear it
256*5254Sgavinm  *	- cycle through all channel/chip-select combinations writing each
257*5254Sgavinm  *	  combination to sparectl before reading the register back for
258*5254Sgavinm  *	  EccCnt for that combination;  since EccErrCntWrEn is clear
259*5254Sgavinm  *	  the writes to select what count to read will not themselves
260*5254Sgavinm  *	  zero any counts
261*5254Sgavinm  */
262*5254Sgavinm static int
263*5254Sgavinm authamd_read_ecccnt(authamd_data_t *authamd, struct authamd_logout *msl)
264*5254Sgavinm {
265*5254Sgavinm 	union mcreg_sparectl sparectl;
266*5254Sgavinm 	uint_t chipid = authamd->amd_shared->acs_chipid;
267*5254Sgavinm 	uint_t family = authamd->amd_shared->acs_family;
268*5254Sgavinm 	uint32_t rev = authamd->amd_shared->acs_rev;
269*5254Sgavinm 	int chan, cs;
270*5254Sgavinm 
271*5254Sgavinm 	/*
272*5254Sgavinm 	 * Check for feature support;  this macro will test down to the
273*5254Sgavinm 	 * family revision number, whereafter we'll switch on family
274*5254Sgavinm 	 * assuming that future revisions will use the same register
275*5254Sgavinm 	 * format.
276*5254Sgavinm 	 */
277*5254Sgavinm 	if (!AUTHAMD_HAS_ONLINESPARECTL(rev)) {
278*5254Sgavinm 		bzero(&msl->aal_eccerrcnt, sizeof (msl->aal_eccerrcnt));
279*5254Sgavinm 		return (0);
280*5254Sgavinm 	}
281*5254Sgavinm 
282*5254Sgavinm 	MCREG_VAL32(&sparectl) =
283*5254Sgavinm 	    authamd_pcicfg_read(chipid, MC_FUNC_MISCCTL, MC_CTL_REG_SPARECTL);
284*5254Sgavinm 
285*5254Sgavinm 	switch (family) {
286*5254Sgavinm 	case AUTHAMD_FAMILY_F:
287*5254Sgavinm 		MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 0;
288*5254Sgavinm 		break;
289*5254Sgavinm 
290*5254Sgavinm 	case AUTHAMD_FAMILY_10:
291*5254Sgavinm 		MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 0;
292*5254Sgavinm 		break;
293*5254Sgavinm 	}
294*5254Sgavinm 
295*5254Sgavinm 	for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
296*5254Sgavinm 		switch (family) {
297*5254Sgavinm 		case AUTHAMD_FAMILY_F:
298*5254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
299*5254Sgavinm 			    chan;
300*5254Sgavinm 			break;
301*5254Sgavinm 
302*5254Sgavinm 		case AUTHAMD_FAMILY_10:
303*5254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
304*5254Sgavinm 			    chan;
305*5254Sgavinm 			break;
306*5254Sgavinm 		}
307*5254Sgavinm 
308*5254Sgavinm 		for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
309*5254Sgavinm 			switch (family) {
310*5254Sgavinm 			case AUTHAMD_FAMILY_F:
311*5254Sgavinm 				MCREG_FIELD_F_revFG(&sparectl,
312*5254Sgavinm 				    EccErrCntDramCs) = cs;
313*5254Sgavinm 				break;
314*5254Sgavinm 
315*5254Sgavinm 			case AUTHAMD_FAMILY_10:
316*5254Sgavinm 				MCREG_FIELD_10_revAB(&sparectl,
317*5254Sgavinm 				    EccErrCntDramCs) = cs;
318*5254Sgavinm 				break;
319*5254Sgavinm 			}
320*5254Sgavinm 
321*5254Sgavinm 			authamd_pcicfg_write(chipid, MC_FUNC_MISCCTL,
322*5254Sgavinm 			    MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
323*5254Sgavinm 
324*5254Sgavinm 			MCREG_VAL32(&sparectl) = authamd_pcicfg_read(chipid,
325*5254Sgavinm 			    MC_FUNC_MISCCTL, MC_CTL_REG_SPARECTL);
326*5254Sgavinm 
327*5254Sgavinm 			switch (family) {
328*5254Sgavinm 			case AUTHAMD_FAMILY_F:
329*5254Sgavinm 				msl->aal_eccerrcnt[chan][cs] =
330*5254Sgavinm 				    MCREG_FIELD_F_revFG(&sparectl, EccErrCnt);
331*5254Sgavinm 				break;
332*5254Sgavinm 			case AUTHAMD_FAMILY_10:
333*5254Sgavinm 				msl->aal_eccerrcnt[chan][cs] =
334*5254Sgavinm 				    MCREG_FIELD_10_revAB(&sparectl, EccErrCnt);
335*5254Sgavinm 				break;
336*5254Sgavinm 			}
337*5254Sgavinm 		}
338*5254Sgavinm 	}
339*5254Sgavinm 
340*5254Sgavinm 	return (1);
341*5254Sgavinm }
342*5254Sgavinm 
343*5254Sgavinm /*
344*5254Sgavinm  * Clear EccCnt for all possible channel/chip-select combos:
345*5254Sgavinm  *
346*5254Sgavinm  *	- set EccErrCntWrEn in sparectl, if necessary
347*5254Sgavinm  *	- write 0 to EccCnt for all channel/chip-select combinations
348*5254Sgavinm  *	- clear EccErrCntWrEn
349*5254Sgavinm  *
350*5254Sgavinm  * If requested also disable the interrupts taken on counter overflow
351*5254Sgavinm  * and on swap done.
352*5254Sgavinm  */
353*5254Sgavinm static void
354*5254Sgavinm authamd_clear_ecccnt(authamd_data_t *authamd, boolean_t clrint)
355*5254Sgavinm {
356*5254Sgavinm 	union mcreg_sparectl sparectl;
357*5254Sgavinm 	uint_t chipid = authamd->amd_shared->acs_chipid;
358*5254Sgavinm 	uint_t family = authamd->amd_shared->acs_family;
359*5254Sgavinm 	uint32_t rev = authamd->amd_shared->acs_rev;
360*5254Sgavinm 	int chan, cs;
361*5254Sgavinm 
362*5254Sgavinm 	if (!AUTHAMD_HAS_ONLINESPARECTL(rev))
363*5254Sgavinm 		return;
364*5254Sgavinm 
365*5254Sgavinm 	MCREG_VAL32(&sparectl) =
366*5254Sgavinm 	    authamd_pcicfg_read(chipid, MC_FUNC_MISCCTL, MC_CTL_REG_SPARECTL);
367*5254Sgavinm 
368*5254Sgavinm 	switch (family) {
369*5254Sgavinm 	case AUTHAMD_FAMILY_F:
370*5254Sgavinm 		MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 1;
371*5254Sgavinm 		if (clrint) {
372*5254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, EccErrInt) = 0;
373*5254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, SwapDoneInt) = 0;
374*5254Sgavinm 		}
375*5254Sgavinm 		break;
376*5254Sgavinm 
377*5254Sgavinm 	case AUTHAMD_FAMILY_10:
378*5254Sgavinm 		MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 1;
379*5254Sgavinm 		if (clrint) {
380*5254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, EccErrInt) = 0;
381*5254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, SwapDoneInt) = 0;
382*5254Sgavinm 		}
383*5254Sgavinm 		break;
384*5254Sgavinm 	}
385*5254Sgavinm 
386*5254Sgavinm 	authamd_pcicfg_write(chipid, MC_FUNC_MISCCTL,
387*5254Sgavinm 	    MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
388*5254Sgavinm 
389*5254Sgavinm 	for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
390*5254Sgavinm 		switch (family) {
391*5254Sgavinm 		case AUTHAMD_FAMILY_F:
392*5254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
393*5254Sgavinm 			    chan;
394*5254Sgavinm 			break;
395*5254Sgavinm 
396*5254Sgavinm 		case AUTHAMD_FAMILY_10:
397*5254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
398*5254Sgavinm 			    chan;
399*5254Sgavinm 			break;
400*5254Sgavinm 		}
401*5254Sgavinm 
402*5254Sgavinm 		for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
403*5254Sgavinm 			switch (family) {
404*5254Sgavinm 			case AUTHAMD_FAMILY_F:
405*5254Sgavinm 				MCREG_FIELD_F_revFG(&sparectl,
406*5254Sgavinm 				    EccErrCntDramCs) = cs;
407*5254Sgavinm 				MCREG_FIELD_F_revFG(&sparectl,
408*5254Sgavinm 				    EccErrCnt) = 0;
409*5254Sgavinm 				break;
410*5254Sgavinm 
411*5254Sgavinm 			case AUTHAMD_FAMILY_10:
412*5254Sgavinm 				MCREG_FIELD_10_revAB(&sparectl,
413*5254Sgavinm 				    EccErrCntDramCs) = cs;
414*5254Sgavinm 				MCREG_FIELD_10_revAB(&sparectl,
415*5254Sgavinm 				    EccErrCnt) = 0;
416*5254Sgavinm 				break;
417*5254Sgavinm 			}
418*5254Sgavinm 
419*5254Sgavinm 			authamd_pcicfg_write(chipid, MC_FUNC_MISCCTL,
420*5254Sgavinm 			    MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
421*5254Sgavinm 		}
422*5254Sgavinm 	}
423*5254Sgavinm }
424*5254Sgavinm 
425*5254Sgavinm /*
426*5254Sgavinm  * cms_init entry point.
427*5254Sgavinm  *
428*5254Sgavinm  * This module provides broad model-specific support for AMD families
429*5254Sgavinm  * 0x6, 0xf and 0x10.  Future families will have to be evaluated once their
430*5254Sgavinm  * documentation is available.
431*5254Sgavinm  */
432*5254Sgavinm int
433*5254Sgavinm authamd_init(cmi_hdl_t hdl, void **datap)
434*5254Sgavinm {
435*5254Sgavinm 	uint_t chipid = cmi_hdl_chipid(hdl);
436*5254Sgavinm 	struct authamd_chipshared *sp, *osp;
437*5254Sgavinm 	uint_t family = cmi_hdl_family(hdl);
438*5254Sgavinm 	authamd_data_t *authamd;
439*5254Sgavinm 	uint64_t cap;
440*5254Sgavinm 
441*5254Sgavinm 	if (authamd_ms_support_disable || !AUTHAMD_SUPPORTED(family))
442*5254Sgavinm 		return (ENOTSUP);
443*5254Sgavinm 
444*5254Sgavinm 	if (!(x86_feature & X86_MCA))
445*5254Sgavinm 		return (ENOTSUP);
446*5254Sgavinm 
447*5254Sgavinm 	if (cmi_hdl_rdmsr(hdl, IA32_MSR_MCG_CAP, &cap) != CMI_SUCCESS)
448*5254Sgavinm 		return (ENOTSUP);
449*5254Sgavinm 
450*5254Sgavinm 	if (!(cap & MCG_CAP_CTL_P))
451*5254Sgavinm 		return (ENOTSUP);
452*5254Sgavinm 
453*5254Sgavinm 	authamd = *datap = kmem_zalloc(sizeof (authamd_data_t), KM_SLEEP);
454*5254Sgavinm 	cmi_hdl_hold(hdl);	/* release in fini */
455*5254Sgavinm 	authamd->amd_hdl = hdl;
456*5254Sgavinm 
457*5254Sgavinm 	if ((sp = authamd_shared[chipid]) == NULL) {
458*5254Sgavinm 		sp = kmem_zalloc(sizeof (struct authamd_chipshared), KM_SLEEP);
459*5254Sgavinm 		osp = atomic_cas_ptr(&authamd_shared[chipid], NULL, sp);
460*5254Sgavinm 		if (osp != NULL) {
461*5254Sgavinm 			kmem_free(sp, sizeof (struct authamd_chipshared));
462*5254Sgavinm 			sp = osp;
463*5254Sgavinm 		} else {
464*5254Sgavinm 			sp->acs_chipid = chipid;
465*5254Sgavinm 			sp->acs_family = family;
466*5254Sgavinm 			sp->acs_rev = cmi_hdl_chiprev(hdl);
467*5254Sgavinm 		}
468*5254Sgavinm 	}
469*5254Sgavinm 	authamd->amd_shared = sp;
470*5254Sgavinm 
471*5254Sgavinm 	return (0);
472*5254Sgavinm }
473*5254Sgavinm 
474*5254Sgavinm /*
475*5254Sgavinm  * cms_logout_size entry point.
476*5254Sgavinm  */
477*5254Sgavinm /*ARGSUSED*/
478*5254Sgavinm size_t
479*5254Sgavinm authamd_logout_size(cmi_hdl_t hdl)
480*5254Sgavinm {
481*5254Sgavinm 	return (sizeof (struct authamd_logout));
482*5254Sgavinm }
483*5254Sgavinm 
484*5254Sgavinm /*
485*5254Sgavinm  * cms_mcgctl_val entry point
486*5254Sgavinm  *
487*5254Sgavinm  * Instead of setting all bits to 1 we can set just those for the
488*5254Sgavinm  * error detector banks known to exist.
489*5254Sgavinm  */
490*5254Sgavinm /*ARGSUSED*/
491*5254Sgavinm uint64_t
492*5254Sgavinm authamd_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t proposed)
493*5254Sgavinm {
494*5254Sgavinm 	return (nbanks < 64 ? (1ULL << nbanks) - 1 : proposed);
495*5254Sgavinm }
496*5254Sgavinm 
497*5254Sgavinm /*
498*5254Sgavinm  * cms_bankctl_skipinit entry point
499*5254Sgavinm  *
500*5254Sgavinm  * On K6 we do not initialize MC0_CTL since, reportedly, this bank (for DC)
501*5254Sgavinm  * may produce spurious machine checks.
502*5254Sgavinm  */
503*5254Sgavinm /*ARGSUSED*/
504*5254Sgavinm boolean_t
505*5254Sgavinm authamd_bankctl_skipinit(cmi_hdl_t hdl, int bank)
506*5254Sgavinm {
507*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
508*5254Sgavinm 
509*5254Sgavinm 	return (authamd->amd_shared->acs_family == AUTHAMD_FAMILY_6 &&
510*5254Sgavinm 	    bank == 0 ?  B_TRUE : B_FALSE);
511*5254Sgavinm }
512*5254Sgavinm 
513*5254Sgavinm /*
514*5254Sgavinm  * cms_bankctl_val entry point
515*5254Sgavinm  */
516*5254Sgavinm uint64_t
517*5254Sgavinm authamd_bankctl_val(cmi_hdl_t hdl, int bank, uint64_t proposed)
518*5254Sgavinm {
519*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
520*5254Sgavinm 	uint32_t rev = authamd->amd_shared->acs_rev;
521*5254Sgavinm 	uint64_t val = proposed;
522*5254Sgavinm 
523*5254Sgavinm 	/*
524*5254Sgavinm 	 * The Intel MCA says we can write all 1's to enable #MC for
525*5254Sgavinm 	 * all errors, and AMD docs say much the same.  But, depending
526*5254Sgavinm 	 * perhaps on other config registers, taking machine checks
527*5254Sgavinm 	 * for some errors such as GART TLB errors and master/target
528*5254Sgavinm 	 * aborts may be bad - they set UC and sometime also PCC, but
529*5254Sgavinm 	 * we should not always panic for these error types.
530*5254Sgavinm 	 *
531*5254Sgavinm 	 * Our cms_error_action entry point can suppress such panics,
532*5254Sgavinm 	 * however we can also use the cms_bankctl_val entry point to
533*5254Sgavinm 	 * veto enabling of some of the known villains in the first place.
534*5254Sgavinm 	 */
535*5254Sgavinm 	if (bank == AMD_MCA_BANK_NB && AUTHAMD_NOGARTTBLWLK_MC(rev))
536*5254Sgavinm 		val &= ~AMD_NB_EN_GARTTBLWK;
537*5254Sgavinm 
538*5254Sgavinm 	return (val);
539*5254Sgavinm }
540*5254Sgavinm 
541*5254Sgavinm /*
542*5254Sgavinm  * cms_mca_init entry point.
543*5254Sgavinm  */
544*5254Sgavinm /*ARGSUSED*/
545*5254Sgavinm void
546*5254Sgavinm authamd_mca_init(cmi_hdl_t hdl, int nbanks)
547*5254Sgavinm {
548*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
549*5254Sgavinm 	uint32_t rev = authamd->amd_shared->acs_rev;
550*5254Sgavinm 
551*5254Sgavinm 	/*
552*5254Sgavinm 	 * On chips with a NB online spare control register take control
553*5254Sgavinm 	 * and clear ECC counts.
554*5254Sgavinm 	 */
555*5254Sgavinm 	if (AUTHAMD_HAS_ONLINESPARECTL(rev) &&
556*5254Sgavinm 	    authamd_chip_once(authamd, AUTHAMD_CFGONCE_ONLNSPRCFG)) {
557*5254Sgavinm 		authamd_clear_ecccnt(authamd, B_TRUE);
558*5254Sgavinm 	}
559*5254Sgavinm 
560*5254Sgavinm 	/*
561*5254Sgavinm 	 * And since we are claiming the telemetry stop the BIOS receiving
562*5254Sgavinm 	 * an SMI on NB threshold overflow.
563*5254Sgavinm 	 */
564*5254Sgavinm 	if (AUTHAMD_NBMISC_NUM(rev) &&
565*5254Sgavinm 	    authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBTHRESH)) {
566*5254Sgavinm 		union mcmsr_nbmisc nbm;
567*5254Sgavinm 		int i;
568*5254Sgavinm 
569*5254Sgavinm 		authamd_bankstatus_prewrite(hdl, authamd);
570*5254Sgavinm 
571*5254Sgavinm 		for (i = 0; i < AUTHAMD_NBMISC_NUM(rev); i++) {
572*5254Sgavinm 			if (cmi_hdl_rdmsr(hdl, MC_MSR_NB_MISC(i),
573*5254Sgavinm 			    (uint64_t *)&nbm) != CMI_SUCCESS)
574*5254Sgavinm 				continue;
575*5254Sgavinm 
576*5254Sgavinm 			if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) &&
577*5254Sgavinm 			    MCMSR_FIELD_F_revFG(&nbm, mcmisc_Valid) &&
578*5254Sgavinm 			    MCMSR_FIELD_F_revFG(&nbm, mcmisc_CntP)) {
579*5254Sgavinm 				MCMSR_FIELD_F_revFG(&nbm, mcmisc_IntType) = 0;
580*5254Sgavinm 			} else if (X86_CHIPREV_ATLEAST(rev,
581*5254Sgavinm 			    X86_CHIPREV_AMD_10_REV_A) &&
582*5254Sgavinm 			    MCMSR_FIELD_10_revAB(&nbm, mcmisc_Valid) &&
583*5254Sgavinm 			    MCMSR_FIELD_10_revAB(&nbm, mcmisc_CntP)) {
584*5254Sgavinm 				MCMSR_FIELD_10_revAB(&nbm, mcmisc_IntType) = 0;
585*5254Sgavinm 			}
586*5254Sgavinm 
587*5254Sgavinm 			(void) cmi_hdl_wrmsr(hdl, MC_MSR_NB_MISC(i),
588*5254Sgavinm 			    MCMSR_VAL(&nbm));
589*5254Sgavinm 		}
590*5254Sgavinm 
591*5254Sgavinm 		authamd_bankstatus_postwrite(hdl, authamd);
592*5254Sgavinm 	}
593*5254Sgavinm }
594*5254Sgavinm 
595*5254Sgavinm /*
596*5254Sgavinm  * cms_bank_logout entry point.
597*5254Sgavinm  */
598*5254Sgavinm /*ARGSUSED*/
599*5254Sgavinm void
600*5254Sgavinm authamd_bank_logout(cmi_hdl_t hdl, int bank, uint64_t status,
601*5254Sgavinm     uint64_t addr, uint64_t misc, void *mslogout)
602*5254Sgavinm {
603*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
604*5254Sgavinm 	struct authamd_logout *msl = mslogout;
605*5254Sgavinm 	uint32_t rev = authamd->amd_shared->acs_rev;
606*5254Sgavinm 
607*5254Sgavinm 	if (msl == NULL)
608*5254Sgavinm 		return;
609*5254Sgavinm 
610*5254Sgavinm 	/*
611*5254Sgavinm 	 * For main memory ECC errors on revisions with an Online Spare
612*5254Sgavinm 	 * Control Register grab the ECC counts by channel and chip-select
613*5254Sgavinm 	 * and reset them to 0.
614*5254Sgavinm 	 */
615*5254Sgavinm 	if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
616*5254Sgavinm 	    AUTHAMD_IS_MEMECCERR(bank, status) &&
617*5254Sgavinm 	    AUTHAMD_HAS_ONLINESPARECTL(rev)) {
618*5254Sgavinm 		if (authamd_read_ecccnt(authamd, msl))
619*5254Sgavinm 			authamd_clear_ecccnt(authamd, B_FALSE);
620*5254Sgavinm 	}
621*5254Sgavinm }
622*5254Sgavinm 
623*5254Sgavinm /*
624*5254Sgavinm  * cms_error_action entry point
625*5254Sgavinm  */
626*5254Sgavinm 
627*5254Sgavinm int authamd_forgive_uc = 0;	/* For test/debug only */
628*5254Sgavinm int authamd_forgive_pcc = 0;	/* For test/debug only */
629*5254Sgavinm int authamd_fake_poison = 0;	/* For test/debug only */
630*5254Sgavinm 
631*5254Sgavinm /*ARGSUSED*/
632*5254Sgavinm uint32_t
633*5254Sgavinm authamd_error_action(cmi_hdl_t hdl, int ismc, int bank,
634*5254Sgavinm     uint64_t status, uint64_t addr, uint64_t misc, void *mslogout)
635*5254Sgavinm {
636*5254Sgavinm 	authamd_error_disp_t *disp;
637*5254Sgavinm 	uint32_t rv = 0;
638*5254Sgavinm 
639*5254Sgavinm 	if (authamd_forgive_uc)
640*5254Sgavinm 		rv |= CMS_ERRSCOPE_CLEARED_UC;
641*5254Sgavinm 
642*5254Sgavinm 	if (authamd_forgive_pcc)
643*5254Sgavinm 		rv |= CMS_ERRSCOPE_CURCONTEXT_OK;
644*5254Sgavinm 
645*5254Sgavinm 	if (authamd_fake_poison && status & MSR_MC_STATUS_UC)
646*5254Sgavinm 		rv |= CMS_ERRSCOPE_POISONED;
647*5254Sgavinm 
648*5254Sgavinm 	if (rv)
649*5254Sgavinm 		return (rv);
650*5254Sgavinm 
651*5254Sgavinm 	disp = authamd_disp_match(hdl, bank, status, addr, misc, mslogout);
652*5254Sgavinm 
653*5254Sgavinm 	if (disp == &authamd_gart_disp) {
654*5254Sgavinm 		/*
655*5254Sgavinm 		 * GART walk errors set UC and possibly PCC (if source CPU)
656*5254Sgavinm 		 * but should not be regarded as terminal.
657*5254Sgavinm 		 */
658*5254Sgavinm 		return (CMS_ERRSCOPE_IGNORE_ERR);
659*5254Sgavinm 	}
660*5254Sgavinm 
661*5254Sgavinm 	/*
662*5254Sgavinm 	 * May also want to consider master abort and target abort.  These
663*5254Sgavinm 	 * also set UC and PCC (if src CPU) but the requester gets -1
664*5254Sgavinm 	 * and I believe the IO stuff in Solaris will handle that.
665*5254Sgavinm 	 */
666*5254Sgavinm 
667*5254Sgavinm 	return (rv);
668*5254Sgavinm }
669*5254Sgavinm 
670*5254Sgavinm /*
671*5254Sgavinm  * cms_disp_match entry point
672*5254Sgavinm  */
673*5254Sgavinm /*ARGSUSED*/
674*5254Sgavinm cms_cookie_t
675*5254Sgavinm authamd_disp_match(cmi_hdl_t hdl, int bank, uint64_t status,
676*5254Sgavinm     uint64_t addr, uint64_t misc, void *mslogout)
677*5254Sgavinm {
678*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
679*5254Sgavinm 	/* uint16_t errcode = MCAX86_ERRCODE(status); */
680*5254Sgavinm 	uint16_t exterrcode = AMD_EXT_ERRCODE(status);
681*5254Sgavinm 	uint32_t rev = authamd->amd_shared->acs_rev;
682*5254Sgavinm 
683*5254Sgavinm 	/*
684*5254Sgavinm 	 * Recognise main memory ECC errors
685*5254Sgavinm 	 */
686*5254Sgavinm 	if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
687*5254Sgavinm 	    AUTHAMD_IS_MEMECCERR(bank, status)) {
688*5254Sgavinm 		if (status & AMD_BANK_STAT_CECC) {
689*5254Sgavinm 			return (exterrcode == 0 ? &authamd_memce_disp :
690*5254Sgavinm 			    &authamd_ckmemce_disp);
691*5254Sgavinm 		} else if (status & AMD_BANK_STAT_UECC) {
692*5254Sgavinm 			return (exterrcode == 0 ? &authamd_memue_disp :
693*5254Sgavinm 			    &authamd_ckmemue_disp);
694*5254Sgavinm 		}
695*5254Sgavinm 	}
696*5254Sgavinm 
697*5254Sgavinm 	/*
698*5254Sgavinm 	 * Recognise GART walk errors
699*5254Sgavinm 	 */
700*5254Sgavinm 	if (AUTHAMD_NOGARTTBLWLK_MC(rev) && AUTHAMD_IS_GARTERR(bank, status))
701*5254Sgavinm 		return (&authamd_gart_disp);
702*5254Sgavinm 
703*5254Sgavinm 	return (NULL);
704*5254Sgavinm }
705*5254Sgavinm 
706*5254Sgavinm /*
707*5254Sgavinm  * cms_ereport_class entry point
708*5254Sgavinm  */
709*5254Sgavinm /*ARGSUSED*/
710*5254Sgavinm void
711*5254Sgavinm authamd_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie,
712*5254Sgavinm     const char **cpuclsp, const char **leafclsp)
713*5254Sgavinm {
714*5254Sgavinm 	const authamd_error_disp_t *aed = mscookie;
715*5254Sgavinm 
716*5254Sgavinm 	if (aed == NULL)
717*5254Sgavinm 		return;
718*5254Sgavinm 
719*5254Sgavinm 	if (aed->aad_subclass != NULL)
720*5254Sgavinm 		*cpuclsp = aed->aad_subclass;
721*5254Sgavinm 	if (aed->aad_leafclass != NULL)
722*5254Sgavinm 		*leafclsp = aed->aad_leafclass;
723*5254Sgavinm }
724*5254Sgavinm 
725*5254Sgavinm /*ARGSUSED*/
726*5254Sgavinm static void
727*5254Sgavinm authamd_ereport_add_resource(cmi_hdl_t hdl, authamd_data_t *authamd,
728*5254Sgavinm     nvlist_t *ereport, nv_alloc_t *nva, void *mslogout)
729*5254Sgavinm {
730*5254Sgavinm 	nvlist_t *elems[AUTHAMD_DRAM_NCHANNEL * AUTHAMD_DRAM_NCS];
731*5254Sgavinm 	uint8_t counts[AUTHAMD_DRAM_NCHANNEL * AUTHAMD_DRAM_NCS];
732*5254Sgavinm 	authamd_logout_t *msl;
733*5254Sgavinm 	nvlist_t *nvl;
734*5254Sgavinm 	int nelems = 0;
735*5254Sgavinm 	int i, chan, cs;
736*5254Sgavinm 
737*5254Sgavinm 	if ((msl = mslogout) == NULL)
738*5254Sgavinm 		return;
739*5254Sgavinm 
740*5254Sgavinm 	for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
741*5254Sgavinm 		for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
742*5254Sgavinm 			if (msl->aal_eccerrcnt[chan][cs] == 0)
743*5254Sgavinm 				continue;
744*5254Sgavinm 
745*5254Sgavinm 			if ((nvl = fm_nvlist_create(nva)) == NULL)
746*5254Sgavinm 				continue;
747*5254Sgavinm 
748*5254Sgavinm 			elems[nelems] = nvl;
749*5254Sgavinm 			counts[nelems++] = msl->aal_eccerrcnt[chan][cs];
750*5254Sgavinm 
751*5254Sgavinm 			fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
752*5254Sgavinm 			    "motherboard", 0,
753*5254Sgavinm 			    "chip", authamd->amd_shared->acs_chipid,
754*5254Sgavinm 			    "memory-controller", 0,
755*5254Sgavinm 			    "dram-channel", chan,
756*5254Sgavinm 			    "chip-select", cs);
757*5254Sgavinm 		}
758*5254Sgavinm 	}
759*5254Sgavinm 
760*5254Sgavinm 	if (nelems == 0)
761*5254Sgavinm 		return;
762*5254Sgavinm 
763*5254Sgavinm 	fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_RESOURCE,
764*5254Sgavinm 	    DATA_TYPE_NVLIST_ARRAY, nelems, elems,
765*5254Sgavinm 	    NULL);
766*5254Sgavinm 
767*5254Sgavinm 	fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_RESOURCECNT,
768*5254Sgavinm 	    DATA_TYPE_UINT8_ARRAY, nelems, &counts[0],
769*5254Sgavinm 	    NULL);
770*5254Sgavinm 
771*5254Sgavinm 	for (i = 0; i < nelems; i++)
772*5254Sgavinm 		fm_nvlist_destroy(elems[i], nva ? FM_NVA_RETAIN : FM_NVA_FREE);
773*5254Sgavinm }
774*5254Sgavinm 
775*5254Sgavinm /*
776*5254Sgavinm  * cms_ereport_add_logout entry point
777*5254Sgavinm  */
778*5254Sgavinm /*ARGSUSED*/
779*5254Sgavinm void
780*5254Sgavinm authamd_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport, nv_alloc_t *nva,
781*5254Sgavinm     int bank, uint64_t status, uint64_t addr, uint64_t misc,
782*5254Sgavinm     void *mslogout, cms_cookie_t mscookie)
783*5254Sgavinm {
784*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
785*5254Sgavinm 	const authamd_error_disp_t *aed = mscookie;
786*5254Sgavinm 	uint64_t members;
787*5254Sgavinm 
788*5254Sgavinm 	if (aed == NULL)
789*5254Sgavinm 		return;
790*5254Sgavinm 
791*5254Sgavinm 	members = aed->aad_ereport_members;
792*5254Sgavinm 
793*5254Sgavinm 	if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYND) {
794*5254Sgavinm 		fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_SYND,
795*5254Sgavinm 		    DATA_TYPE_UINT16, (uint16_t)AMD_BANK_SYND(status),
796*5254Sgavinm 		    NULL);
797*5254Sgavinm 
798*5254Sgavinm 		if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYNDTYPE) {
799*5254Sgavinm 			fm_payload_set(ereport,
800*5254Sgavinm 			    FM_EREPORT_GENAMD_PAYLOAD_NAME_SYNDTYPE,
801*5254Sgavinm 			    DATA_TYPE_STRING, "E",
802*5254Sgavinm 			    NULL);
803*5254Sgavinm 		}
804*5254Sgavinm 	}
805*5254Sgavinm 
806*5254Sgavinm 	if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_CKSYND) {
807*5254Sgavinm 		fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_CKSYND,
808*5254Sgavinm 		    DATA_TYPE_UINT16, (uint16_t)AMD_NB_STAT_CKSYND(status),
809*5254Sgavinm 		    NULL);
810*5254Sgavinm 
811*5254Sgavinm 		if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYNDTYPE) {
812*5254Sgavinm 			fm_payload_set(ereport,
813*5254Sgavinm 			    FM_EREPORT_GENAMD_PAYLOAD_NAME_SYNDTYPE,
814*5254Sgavinm 			    DATA_TYPE_STRING, "C",
815*5254Sgavinm 			    NULL);
816*5254Sgavinm 		}
817*5254Sgavinm 	}
818*5254Sgavinm 
819*5254Sgavinm 	if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_RESOURCE &&
820*5254Sgavinm 	    status & MSR_MC_STATUS_ADDRV) {
821*5254Sgavinm 		authamd_ereport_add_resource(hdl, authamd, ereport, nva,
822*5254Sgavinm 		    mslogout);
823*5254Sgavinm 	}
824*5254Sgavinm }
825*5254Sgavinm 
826*5254Sgavinm /*
827*5254Sgavinm  * cms_msrinject entry point
828*5254Sgavinm  */
829*5254Sgavinm cms_errno_t
830*5254Sgavinm authamd_msrinject(cmi_hdl_t hdl, uint_t msr, uint64_t val)
831*5254Sgavinm {
832*5254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
833*5254Sgavinm 	cms_errno_t rv = CMSERR_BADMSRWRITE;
834*5254Sgavinm 
835*5254Sgavinm 	authamd_bankstatus_prewrite(hdl, authamd);
836*5254Sgavinm 	if (cmi_hdl_wrmsr(hdl, msr, val) == CMI_SUCCESS)
837*5254Sgavinm 		rv = CMS_SUCCESS;
838*5254Sgavinm 	authamd_bankstatus_postwrite(hdl, authamd);
839*5254Sgavinm 
840*5254Sgavinm 	return (rv);
841*5254Sgavinm }
842*5254Sgavinm 
843*5254Sgavinm cms_api_ver_t _cms_api_version = CMS_API_VERSION_0;
844*5254Sgavinm 
845*5254Sgavinm const cms_ops_t _cms_ops = {
846*5254Sgavinm 	authamd_init,			/* cms_init */
847*5254Sgavinm 	NULL,				/* cms_post_startup */
848*5254Sgavinm 	NULL,				/* cms_post_mpstartup */
849*5254Sgavinm 	authamd_logout_size,		/* cms_logout_size */
850*5254Sgavinm 	authamd_mcgctl_val,		/* cms_mcgctl_val */
851*5254Sgavinm 	authamd_bankctl_skipinit,	/* cms_bankctl_skipinit */
852*5254Sgavinm 	authamd_bankctl_val,		/* cms_bankctl_val */
853*5254Sgavinm 	NULL,				/* cms_bankstatus_skipinit */
854*5254Sgavinm 	NULL,				/* cms_bankstatus_val */
855*5254Sgavinm 	authamd_mca_init,		/* cms_mca_init */
856*5254Sgavinm 	NULL,				/* cms_poll_ownermask */
857*5254Sgavinm 	authamd_bank_logout,		/* cms_bank_logout */
858*5254Sgavinm 	authamd_error_action,		/* cms_error_action */
859*5254Sgavinm 	authamd_disp_match,		/* cms_disp_match */
860*5254Sgavinm 	authamd_ereport_class,		/* cms_ereport_class */
861*5254Sgavinm 	NULL,				/* cms_ereport_detector */
862*5254Sgavinm 	NULL,				/* cms_ereport_includestack */
863*5254Sgavinm 	authamd_ereport_add_logout,	/* cms_ereport_add_logout */
864*5254Sgavinm 	authamd_msrinject,		/* cms_msrinject */
865*5254Sgavinm 	NULL,				/* cms_fini */
866*5254Sgavinm };
867*5254Sgavinm 
868*5254Sgavinm static struct modlcpu modlcpu = {
869*5254Sgavinm 	&mod_cpuops,
870*5254Sgavinm 	"Generic AMD model-specific MCA"
871*5254Sgavinm };
872*5254Sgavinm 
873*5254Sgavinm static struct modlinkage modlinkage = {
874*5254Sgavinm 	MODREV_1,
875*5254Sgavinm 	(void *)&modlcpu,
876*5254Sgavinm 	NULL
877*5254Sgavinm };
878*5254Sgavinm 
879*5254Sgavinm int
880*5254Sgavinm _init(void)
881*5254Sgavinm {
882*5254Sgavinm 	return (mod_install(&modlinkage));
883*5254Sgavinm }
884*5254Sgavinm 
885*5254Sgavinm int
886*5254Sgavinm _info(struct modinfo *modinfop)
887*5254Sgavinm {
888*5254Sgavinm 	return (mod_info(&modlinkage, modinfop));
889*5254Sgavinm }
890*5254Sgavinm 
891*5254Sgavinm int
892*5254Sgavinm _fini(void)
893*5254Sgavinm {
894*5254Sgavinm 	return (mod_remove(&modlinkage));
895*5254Sgavinm }
896