xref: /onnv-gate/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c (revision 11947:e9d33e5d3842)
15254Sgavinm /*
25254Sgavinm  * CDDL HEADER START
35254Sgavinm  *
45254Sgavinm  * The contents of this file are subject to the terms of the
55254Sgavinm  * Common Development and Distribution License (the "License").
65254Sgavinm  * You may not use this file except in compliance with the License.
75254Sgavinm  *
85254Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95254Sgavinm  * or http://www.opensolaris.org/os/licensing.
105254Sgavinm  * See the License for the specific language governing permissions
115254Sgavinm  * and limitations under the License.
125254Sgavinm  *
135254Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
145254Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155254Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
165254Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
175254Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
185254Sgavinm  *
195254Sgavinm  * CDDL HEADER END
205254Sgavinm  */
215254Sgavinm 
225254Sgavinm /*
23*11947Ssrihari.venkatesan@oracle.com  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
245254Sgavinm  * Use is subject to license terms.
255254Sgavinm  */
265254Sgavinm 
275254Sgavinm /*
285254Sgavinm  * "Generic AMD" model-specific support.  If no more-specific support can
295254Sgavinm  * be found, or such modules declines to initialize, then for AuthenticAMD
305254Sgavinm  * cpus this module can have a crack at providing some AMD model-specific
315254Sgavinm  * support that at least goes beyond common MCA architectural features
325254Sgavinm  * if not down to the nitty-gritty level for a particular model.  We
335254Sgavinm  * are layered on top of a cpu module, likely cpu.generic, so there is no
345254Sgavinm  * need for us to perform common architecturally-accessible functions.
355254Sgavinm  */
365254Sgavinm 
375254Sgavinm #include <sys/types.h>
385254Sgavinm #include <sys/cmn_err.h>
395254Sgavinm #include <sys/modctl.h>
405254Sgavinm #include <sys/cpu_module.h>
415254Sgavinm #include <sys/mca_x86.h>
425254Sgavinm #include <sys/pci_cfgspace.h>
435254Sgavinm #include <sys/x86_archext.h>
445254Sgavinm #include <sys/mc_amd.h>
455254Sgavinm #include <sys/fm/protocol.h>
465254Sgavinm #include <sys/fm/cpu/GENAMD.h>
4710942STom.Pothier@Sun.COM #include <sys/fm/smb/fmsmb.h>
4810942STom.Pothier@Sun.COM #include <sys/fm/util.h>
495254Sgavinm #include <sys/nvpair.h>
505254Sgavinm #include <sys/controlregs.h>
515254Sgavinm #include <sys/pghw.h>
525254Sgavinm #include <sys/sunddi.h>
535327Sgavinm #include <sys/sysmacros.h>
545254Sgavinm #include <sys/cpu_module_ms_impl.h>
555254Sgavinm 
565254Sgavinm #include "authamd.h"
575254Sgavinm 
5810942STom.Pothier@Sun.COM extern int x86gentopo_legacy; /* x86 generic topo support */
5910942STom.Pothier@Sun.COM 
605254Sgavinm int authamd_ms_support_disable = 0;
615254Sgavinm 
625254Sgavinm #define	AUTHAMD_F_REVS_BCDE \
635254Sgavinm 	(X86_CHIPREV_AMD_F_REV_B | X86_CHIPREV_AMD_F_REV_C0 | \
645254Sgavinm 	X86_CHIPREV_AMD_F_REV_CG | X86_CHIPREV_AMD_F_REV_D | \
655254Sgavinm 	X86_CHIPREV_AMD_F_REV_E)
665254Sgavinm 
675254Sgavinm #define	AUTHAMD_F_REVS_FG \
685254Sgavinm 	(X86_CHIPREV_AMD_F_REV_F | X86_CHIPREV_AMD_F_REV_G)
695254Sgavinm 
705254Sgavinm #define	AUTHAMD_10_REVS_AB \
715254Sgavinm 	(X86_CHIPREV_AMD_10_REV_A | X86_CHIPREV_AMD_10_REV_B)
725254Sgavinm 
735254Sgavinm /*
745254Sgavinm  * Bitmasks of support for various features.  Try to enable features
755254Sgavinm  * via inclusion in one of these bitmasks and check that at the
765254Sgavinm  * feature imlementation - that way new family support may often simply
775254Sgavinm  * simply need to update these bitmasks.
785254Sgavinm  */
795254Sgavinm 
805254Sgavinm /*
815639Sgavinm  * Models that include an on-chip NorthBridge.
825639Sgavinm  */
835639Sgavinm #define	AUTHAMD_NBONCHIP(rev) \
845639Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
855639Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
865639Sgavinm 
875639Sgavinm /*
885254Sgavinm  * Families/revisions for which we can recognise main memory ECC errors.
895254Sgavinm  */
905254Sgavinm #define	AUTHAMD_MEMECC_RECOGNISED(rev) \
915254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
925254Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
935254Sgavinm 
945254Sgavinm /*
955254Sgavinm  * Families/revisions that have an Online Spare Control Register
965254Sgavinm  */
975254Sgavinm #define	AUTHAMD_HAS_ONLINESPARECTL(rev) \
985254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) || \
995254Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1005254Sgavinm 
1015254Sgavinm /*
1025327Sgavinm  * Families/revisions for which we will perform NB MCA Config changes
1035327Sgavinm  */
1045327Sgavinm #define	AUTHAMD_DO_NBMCACFG(rev) \
1055639Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
1065327Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1075327Sgavinm 
1085327Sgavinm /*
1095327Sgavinm  * Families/revisions that have chip cache scrubbers.
1105327Sgavinm  */
1115327Sgavinm #define	AUTHAMD_HAS_CHIPSCRUB(rev) \
1125639Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
1135327Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1145327Sgavinm 
1155327Sgavinm /*
1165254Sgavinm  * Families/revisions that have a NB misc register or registers -
1175254Sgavinm  * evaluates to 0 if no support, otherwise the number of MC4_MISCj.
1185254Sgavinm  */
1195254Sgavinm #define	AUTHAMD_NBMISC_NUM(rev) \
1205254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F)? 1 : \
1215254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A) ? 3 : 0))
1225254Sgavinm 
1235254Sgavinm /*
1245254Sgavinm  * Families/revision for which we wish not to machine check for GART
1255254Sgavinm  * table walk errors - bit 10 of NB CTL.
1265254Sgavinm  */
1275254Sgavinm #define	AUTHAMD_NOGARTTBLWLK_MC(rev) \
1285254Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
1295254Sgavinm 	X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1305254Sgavinm 
1315254Sgavinm /*
1325327Sgavinm  * Families/revisions that are potentially L3 capable
1335327Sgavinm  */
1345327Sgavinm #define	AUTHAMD_L3CAPABLE(rev) \
1355327Sgavinm 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1365327Sgavinm 
1375327Sgavinm /*
138*11947Ssrihari.venkatesan@oracle.com  * Families/revisions that support x8 ChipKill ECC
139*11947Ssrihari.venkatesan@oracle.com  */
140*11947Ssrihari.venkatesan@oracle.com #define	AUTHAMD_SUPPORTS_X8ECC(rev) \
141*11947Ssrihari.venkatesan@oracle.com 	(X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_D))
142*11947Ssrihari.venkatesan@oracle.com 
143*11947Ssrihari.venkatesan@oracle.com /*
1445254Sgavinm  * We recognise main memory ECC errors for AUTHAMD_MEMECC_RECOGNISED
1455254Sgavinm  * revisions as:
1465254Sgavinm  *
1475254Sgavinm  *	- being reported by the NB
1485254Sgavinm  *	- being a compound bus/interconnect error (external to chip)
1495254Sgavinm  *	- having LL of LG
1505254Sgavinm  *	- having II of MEM (but could still be a master/target abort)
1515254Sgavinm  *	- having CECC or UECC set
1525254Sgavinm  *
1535254Sgavinm  * We do not check the extended error code (first nibble of the
1545254Sgavinm  * model-specific error code on AMD) since this has changed from
1555254Sgavinm  * family 0xf to family 0x10 (ext code 0 now reserved on family 0x10).
1565254Sgavinm  * Instead we use CECC/UECC to separate off the master/target
1575254Sgavinm  * abort cases.
1585254Sgavinm  *
1595254Sgavinm  * We insist that the detector be the NorthBridge bank;  although
1605254Sgavinm  * IC/DC can report some main memory errors, they do not capture
1615254Sgavinm  * an address at sufficient resolution to be useful and the NB will
1625254Sgavinm  * report most errors.
1635254Sgavinm  */
1645254Sgavinm #define	AUTHAMD_IS_MEMECCERR(bank, status) \
1655254Sgavinm 	((bank) == AMD_MCA_BANK_NB && \
1665254Sgavinm 	MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && \
1675254Sgavinm 	MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
1685254Sgavinm 	MCAX86_ERRCODE_II(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_II_MEM && \
1695254Sgavinm 	((status) & (AMD_BANK_STAT_CECC | AMD_BANK_STAT_UECC)))
1705254Sgavinm 
1715254Sgavinm static authamd_error_disp_t authamd_memce_disp = {
1725254Sgavinm 	FM_EREPORT_CPU_GENAMD,
1735254Sgavinm 	FM_EREPORT_CPU_GENAMD_MEM_CE,
1745254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_CE
1755254Sgavinm };
1765254Sgavinm 
1775254Sgavinm static authamd_error_disp_t authamd_memue_disp = {
1785254Sgavinm 	FM_EREPORT_CPU_GENAMD,
1795254Sgavinm 	FM_EREPORT_CPU_GENAMD_MEM_UE,
1805254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_UE
1815254Sgavinm };
1825254Sgavinm 
1835254Sgavinm static authamd_error_disp_t authamd_ckmemce_disp = {
1845254Sgavinm 	FM_EREPORT_CPU_GENAMD,
1855254Sgavinm 	FM_EREPORT_CPU_GENAMD_CKMEM_CE,
1865254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_CE
1875254Sgavinm };
1885254Sgavinm 
1895254Sgavinm static authamd_error_disp_t authamd_ckmemue_disp = {
1905254Sgavinm 	FM_EREPORT_CPU_GENAMD,
1915254Sgavinm 	FM_EREPORT_CPU_GENAMD_CKMEM_UE,
1925254Sgavinm 	FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_UE
1935254Sgavinm };
1945254Sgavinm 
1955254Sgavinm /*
1965254Sgavinm  * We recognise GART walk errors as:
1975254Sgavinm  *
1985254Sgavinm  *	- being reported by the NB
1995254Sgavinm  *	- being a compound TLB error
2005254Sgavinm  *	- having LL of LG and TT of GEN
2015254Sgavinm  *	- having UC set
2025254Sgavinm  *	- possibly having PCC set (if source CPU)
2035254Sgavinm  */
2045254Sgavinm #define	AUTHAMD_IS_GARTERR(bank, status) \
2055254Sgavinm 	((bank) == AMD_MCA_BANK_NB && \
2065254Sgavinm 	MCAX86_ERRCODE_ISTLB(MCAX86_ERRCODE(status)) && \
2075254Sgavinm 	MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
2085254Sgavinm 	MCAX86_ERRCODE_TT(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_TT_GEN && \
2095254Sgavinm 	(status) & MSR_MC_STATUS_UC)
2105254Sgavinm 
2115254Sgavinm static authamd_error_disp_t authamd_gart_disp = {
2125254Sgavinm 	FM_EREPORT_CPU_GENAMD,			/* use generic subclass */
2135254Sgavinm 	FM_EREPORT_CPU_GENADM_GARTTBLWLK,	/* use generic leafclass */
2145254Sgavinm 	0					/* no additional payload */
2155254Sgavinm };
2165254Sgavinm 
2175254Sgavinm 
21810947SSrihari.Venkatesan@Sun.COM static struct authamd_nodeshared *authamd_shared[AUTHAMD_MAX_NODES];
2195254Sgavinm 
2205254Sgavinm static int
2215254Sgavinm authamd_chip_once(authamd_data_t *authamd, enum authamd_cfgonce_bitnum what)
2225254Sgavinm {
223*11947Ssrihari.venkatesan@oracle.com 	return (atomic_set_long_excl(&authamd->amd_shared->ans_cfgonce,
2245254Sgavinm 	    what) == 0 ?  B_TRUE : B_FALSE);
2255254Sgavinm }
2265254Sgavinm 
2275254Sgavinm static void
22810947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(uint_t procnodeid, uint_t func, uint_t reg, uint32_t val)
2295254Sgavinm {
23010947SSrihari.Venkatesan@Sun.COM 	ASSERT(procnodeid + 24 <= 31);
2315254Sgavinm 	ASSERT((func & 7) == func);
232*11947Ssrihari.venkatesan@oracle.com 	ASSERT((reg & 3) == 0 && reg < 4096);
2335254Sgavinm 
23410947SSrihari.Venkatesan@Sun.COM 	cmi_pci_putl(0, procnodeid + 24, func, reg, 0, val);
2355254Sgavinm }
2365254Sgavinm 
2375254Sgavinm static uint32_t
23810947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_read(uint_t procnodeid, uint_t func, uint_t reg)
2395254Sgavinm {
24010947SSrihari.Venkatesan@Sun.COM 	ASSERT(procnodeid + 24 <= 31);
2415254Sgavinm 	ASSERT((func & 7) == func);
242*11947Ssrihari.venkatesan@oracle.com 	ASSERT((reg & 3) == 0 && reg < 4096);
2435254Sgavinm 
24410947SSrihari.Venkatesan@Sun.COM 	return (cmi_pci_getl(0, procnodeid + 24, func, reg, 0, 0));
2455254Sgavinm }
2465254Sgavinm 
2475254Sgavinm void
2485254Sgavinm authamd_bankstatus_prewrite(cmi_hdl_t hdl, authamd_data_t *authamd)
2495254Sgavinm {
2505254Sgavinm 	uint64_t hwcr;
2515254Sgavinm 
2525254Sgavinm 	if (cmi_hdl_rdmsr(hdl, MSR_AMD_HWCR, &hwcr) != CMI_SUCCESS)
2535254Sgavinm 		return;
2545254Sgavinm 
2555254Sgavinm 	authamd->amd_hwcr = hwcr;
2565254Sgavinm 
2575254Sgavinm 	if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
2585254Sgavinm 		hwcr |= AMD_HWCR_MCI_STATUS_WREN;
2595254Sgavinm 		(void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
2605254Sgavinm 	}
2615254Sgavinm }
2625254Sgavinm 
2635254Sgavinm void
2645254Sgavinm authamd_bankstatus_postwrite(cmi_hdl_t hdl, authamd_data_t *authamd)
2655254Sgavinm {
2665254Sgavinm 	uint64_t hwcr = authamd->amd_hwcr;
2675254Sgavinm 
2685254Sgavinm 	if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
2695254Sgavinm 		hwcr &= ~AMD_HWCR_MCI_STATUS_WREN;
2705254Sgavinm 		(void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
2715254Sgavinm 	}
2725254Sgavinm }
2735254Sgavinm 
2745254Sgavinm /*
2755254Sgavinm  * Read EccCnt repeatedly for all possible channel/chip-select combos:
2765254Sgavinm  *
2775254Sgavinm  *	- read sparectl register
2785254Sgavinm  *	- if EccErrCntWrEn is set, clear that bit in the just-read value
2795254Sgavinm  *	  and write it back to sparectl;  this *may* clobber the EccCnt
2805254Sgavinm  *	  for the channel/chip-select combination currently selected, so
2815254Sgavinm  *	  we leave this bit clear if we had to clear it
2825254Sgavinm  *	- cycle through all channel/chip-select combinations writing each
2835254Sgavinm  *	  combination to sparectl before reading the register back for
2845254Sgavinm  *	  EccCnt for that combination;  since EccErrCntWrEn is clear
2855254Sgavinm  *	  the writes to select what count to read will not themselves
2865254Sgavinm  *	  zero any counts
2875254Sgavinm  */
2885254Sgavinm static int
2895254Sgavinm authamd_read_ecccnt(authamd_data_t *authamd, struct authamd_logout *msl)
2905254Sgavinm {
2915254Sgavinm 	union mcreg_sparectl sparectl;
292*11947Ssrihari.venkatesan@oracle.com 	uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
293*11947Ssrihari.venkatesan@oracle.com 	uint_t family = authamd->amd_shared->ans_family;
294*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
2955254Sgavinm 	int chan, cs;
2965254Sgavinm 
2975254Sgavinm 	/*
2985254Sgavinm 	 * Check for feature support;  this macro will test down to the
2995254Sgavinm 	 * family revision number, whereafter we'll switch on family
3005254Sgavinm 	 * assuming that future revisions will use the same register
3015254Sgavinm 	 * format.
3025254Sgavinm 	 */
3035254Sgavinm 	if (!AUTHAMD_HAS_ONLINESPARECTL(rev)) {
3045254Sgavinm 		bzero(&msl->aal_eccerrcnt, sizeof (msl->aal_eccerrcnt));
3055254Sgavinm 		return (0);
3065254Sgavinm 	}
3075254Sgavinm 
3085254Sgavinm 	MCREG_VAL32(&sparectl) =
30910947SSrihari.Venkatesan@Sun.COM 	    authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
31010947SSrihari.Venkatesan@Sun.COM 	    MC_CTL_REG_SPARECTL);
3115254Sgavinm 
3125254Sgavinm 	switch (family) {
3135254Sgavinm 	case AUTHAMD_FAMILY_F:
3145254Sgavinm 		MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 0;
3155254Sgavinm 		break;
3165254Sgavinm 
3175254Sgavinm 	case AUTHAMD_FAMILY_10:
3185254Sgavinm 		MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 0;
3195254Sgavinm 		break;
3205254Sgavinm 	}
3215254Sgavinm 
3225254Sgavinm 	for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
3235254Sgavinm 		switch (family) {
3245254Sgavinm 		case AUTHAMD_FAMILY_F:
3255254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
3265254Sgavinm 			    chan;
3275254Sgavinm 			break;
3285254Sgavinm 
3295254Sgavinm 		case AUTHAMD_FAMILY_10:
3305254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
3315254Sgavinm 			    chan;
3325254Sgavinm 			break;
3335254Sgavinm 		}
3345254Sgavinm 
3355254Sgavinm 		for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
3365254Sgavinm 			switch (family) {
3375254Sgavinm 			case AUTHAMD_FAMILY_F:
3385254Sgavinm 				MCREG_FIELD_F_revFG(&sparectl,
3395254Sgavinm 				    EccErrCntDramCs) = cs;
3405254Sgavinm 				break;
3415254Sgavinm 
3425254Sgavinm 			case AUTHAMD_FAMILY_10:
3435254Sgavinm 				MCREG_FIELD_10_revAB(&sparectl,
3445254Sgavinm 				    EccErrCntDramCs) = cs;
3455254Sgavinm 				break;
3465254Sgavinm 			}
3475254Sgavinm 
34810947SSrihari.Venkatesan@Sun.COM 			authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
3495254Sgavinm 			    MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
3505254Sgavinm 
35110947SSrihari.Venkatesan@Sun.COM 			MCREG_VAL32(&sparectl) = authamd_pcicfg_read(procnodeid,
3525254Sgavinm 			    MC_FUNC_MISCCTL, MC_CTL_REG_SPARECTL);
3535254Sgavinm 
3545254Sgavinm 			switch (family) {
3555254Sgavinm 			case AUTHAMD_FAMILY_F:
3565254Sgavinm 				msl->aal_eccerrcnt[chan][cs] =
3575254Sgavinm 				    MCREG_FIELD_F_revFG(&sparectl, EccErrCnt);
3585254Sgavinm 				break;
3595254Sgavinm 			case AUTHAMD_FAMILY_10:
3605254Sgavinm 				msl->aal_eccerrcnt[chan][cs] =
3615254Sgavinm 				    MCREG_FIELD_10_revAB(&sparectl, EccErrCnt);
3625254Sgavinm 				break;
3635254Sgavinm 			}
3645254Sgavinm 		}
3655254Sgavinm 	}
3665254Sgavinm 
3675254Sgavinm 	return (1);
3685254Sgavinm }
3695254Sgavinm 
3705254Sgavinm /*
3715254Sgavinm  * Clear EccCnt for all possible channel/chip-select combos:
3725254Sgavinm  *
3735254Sgavinm  *	- set EccErrCntWrEn in sparectl, if necessary
3745254Sgavinm  *	- write 0 to EccCnt for all channel/chip-select combinations
3755254Sgavinm  *	- clear EccErrCntWrEn
3765254Sgavinm  *
3775254Sgavinm  * If requested also disable the interrupts taken on counter overflow
3785254Sgavinm  * and on swap done.
3795254Sgavinm  */
3805254Sgavinm static void
3815254Sgavinm authamd_clear_ecccnt(authamd_data_t *authamd, boolean_t clrint)
3825254Sgavinm {
3835254Sgavinm 	union mcreg_sparectl sparectl;
384*11947Ssrihari.venkatesan@oracle.com 	uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
385*11947Ssrihari.venkatesan@oracle.com 	uint_t family = authamd->amd_shared->ans_family;
386*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
3875254Sgavinm 	int chan, cs;
3885254Sgavinm 
3895254Sgavinm 	if (!AUTHAMD_HAS_ONLINESPARECTL(rev))
3905254Sgavinm 		return;
3915254Sgavinm 
3925254Sgavinm 	MCREG_VAL32(&sparectl) =
39310947SSrihari.Venkatesan@Sun.COM 	    authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
39410947SSrihari.Venkatesan@Sun.COM 	    MC_CTL_REG_SPARECTL);
3955254Sgavinm 
3965254Sgavinm 	switch (family) {
3975254Sgavinm 	case AUTHAMD_FAMILY_F:
3985254Sgavinm 		MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 1;
3995254Sgavinm 		if (clrint) {
4005254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, EccErrInt) = 0;
4015254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, SwapDoneInt) = 0;
4025254Sgavinm 		}
4035254Sgavinm 		break;
4045254Sgavinm 
4055254Sgavinm 	case AUTHAMD_FAMILY_10:
4065254Sgavinm 		MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 1;
4075254Sgavinm 		if (clrint) {
4085254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, EccErrInt) = 0;
4095254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, SwapDoneInt) = 0;
4105254Sgavinm 		}
4115254Sgavinm 		break;
4125254Sgavinm 	}
4135254Sgavinm 
41410947SSrihari.Venkatesan@Sun.COM 	authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
4155254Sgavinm 	    MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
4165254Sgavinm 
4175254Sgavinm 	for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
4185254Sgavinm 		switch (family) {
4195254Sgavinm 		case AUTHAMD_FAMILY_F:
4205254Sgavinm 			MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
4215254Sgavinm 			    chan;
4225254Sgavinm 			break;
4235254Sgavinm 
4245254Sgavinm 		case AUTHAMD_FAMILY_10:
4255254Sgavinm 			MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
4265254Sgavinm 			    chan;
4275254Sgavinm 			break;
4285254Sgavinm 		}
4295254Sgavinm 
4305254Sgavinm 		for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
4315254Sgavinm 			switch (family) {
4325254Sgavinm 			case AUTHAMD_FAMILY_F:
4335254Sgavinm 				MCREG_FIELD_F_revFG(&sparectl,
4345254Sgavinm 				    EccErrCntDramCs) = cs;
4355254Sgavinm 				MCREG_FIELD_F_revFG(&sparectl,
4365254Sgavinm 				    EccErrCnt) = 0;
4375254Sgavinm 				break;
4385254Sgavinm 
4395254Sgavinm 			case AUTHAMD_FAMILY_10:
4405254Sgavinm 				MCREG_FIELD_10_revAB(&sparectl,
4415254Sgavinm 				    EccErrCntDramCs) = cs;
4425254Sgavinm 				MCREG_FIELD_10_revAB(&sparectl,
4435254Sgavinm 				    EccErrCnt) = 0;
4445254Sgavinm 				break;
4455254Sgavinm 			}
4465254Sgavinm 
44710947SSrihari.Venkatesan@Sun.COM 			authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
4485254Sgavinm 			    MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
4495254Sgavinm 		}
4505254Sgavinm 	}
4515254Sgavinm }
4525254Sgavinm 
45310026SKuriakose.Kuruvilla@Sun.COM 
45410026SKuriakose.Kuruvilla@Sun.COM /*
45510026SKuriakose.Kuruvilla@Sun.COM  * Return
45610026SKuriakose.Kuruvilla@Sun.COM  * 	1: supported
45710026SKuriakose.Kuruvilla@Sun.COM  *	0: unsupported
45810026SKuriakose.Kuruvilla@Sun.COM  */
45910026SKuriakose.Kuruvilla@Sun.COM static int
46010947SSrihari.Venkatesan@Sun.COM authamd_supported(cmi_hdl_t hdl)
46110026SKuriakose.Kuruvilla@Sun.COM {
46210947SSrihari.Venkatesan@Sun.COM 	uint_t family = cmi_hdl_family(hdl);
46310026SKuriakose.Kuruvilla@Sun.COM 
46410947SSrihari.Venkatesan@Sun.COM 	switch (family) {
46510947SSrihari.Venkatesan@Sun.COM 	case AUTHAMD_FAMILY_6:
46610947SSrihari.Venkatesan@Sun.COM 	case AUTHAMD_FAMILY_F:
46710947SSrihari.Venkatesan@Sun.COM 	case AUTHAMD_FAMILY_10:
46810947SSrihari.Venkatesan@Sun.COM 		return (1);
46910947SSrihari.Venkatesan@Sun.COM 	default:
47010947SSrihari.Venkatesan@Sun.COM 		return (0);
47110026SKuriakose.Kuruvilla@Sun.COM 	}
47210026SKuriakose.Kuruvilla@Sun.COM }
47310026SKuriakose.Kuruvilla@Sun.COM 
4745254Sgavinm /*
4755254Sgavinm  * cms_init entry point.
4765254Sgavinm  *
4775254Sgavinm  * This module provides broad model-specific support for AMD families
4785254Sgavinm  * 0x6, 0xf and 0x10.  Future families will have to be evaluated once their
4795254Sgavinm  * documentation is available.
4805254Sgavinm  */
4815254Sgavinm int
4825254Sgavinm authamd_init(cmi_hdl_t hdl, void **datap)
4835254Sgavinm {
4845254Sgavinm 	uint_t chipid = cmi_hdl_chipid(hdl);
48510947SSrihari.Venkatesan@Sun.COM 	uint_t procnodeid = cmi_hdl_procnodeid(hdl);
48610947SSrihari.Venkatesan@Sun.COM 	struct authamd_nodeshared *sp, *osp;
4875254Sgavinm 	uint_t family = cmi_hdl_family(hdl);
48810026SKuriakose.Kuruvilla@Sun.COM 	uint32_t rev = cmi_hdl_chiprev(hdl);
4895254Sgavinm 	authamd_data_t *authamd;
4905254Sgavinm 	uint64_t cap;
4915254Sgavinm 
49210026SKuriakose.Kuruvilla@Sun.COM 	if (authamd_ms_support_disable ||
49310947SSrihari.Venkatesan@Sun.COM 	    !authamd_supported(hdl))
4945254Sgavinm 		return (ENOTSUP);
4955254Sgavinm 
4965254Sgavinm 	if (!(x86_feature & X86_MCA))
4975254Sgavinm 		return (ENOTSUP);
4985254Sgavinm 
4995254Sgavinm 	if (cmi_hdl_rdmsr(hdl, IA32_MSR_MCG_CAP, &cap) != CMI_SUCCESS)
5005254Sgavinm 		return (ENOTSUP);
5015254Sgavinm 
5025254Sgavinm 	if (!(cap & MCG_CAP_CTL_P))
5035254Sgavinm 		return (ENOTSUP);
5045254Sgavinm 
5055254Sgavinm 	authamd = *datap = kmem_zalloc(sizeof (authamd_data_t), KM_SLEEP);
5065254Sgavinm 	cmi_hdl_hold(hdl);	/* release in fini */
5075254Sgavinm 	authamd->amd_hdl = hdl;
5085254Sgavinm 
50910947SSrihari.Venkatesan@Sun.COM 	if ((sp = authamd_shared[procnodeid]) == NULL) {
51010947SSrihari.Venkatesan@Sun.COM 		sp = kmem_zalloc(sizeof (struct authamd_nodeshared), KM_SLEEP);
511*11947Ssrihari.venkatesan@oracle.com 		sp->ans_chipid = chipid;
512*11947Ssrihari.venkatesan@oracle.com 		sp->ans_procnodeid = procnodeid;
513*11947Ssrihari.venkatesan@oracle.com 		sp->ans_family = family;
514*11947Ssrihari.venkatesan@oracle.com 		sp->ans_rev = rev;
5156000Sgavinm 		membar_producer();
5166000Sgavinm 
51710947SSrihari.Venkatesan@Sun.COM 		osp = atomic_cas_ptr(&authamd_shared[procnodeid], NULL, sp);
5185254Sgavinm 		if (osp != NULL) {
51910947SSrihari.Venkatesan@Sun.COM 			kmem_free(sp, sizeof (struct authamd_nodeshared));
5205254Sgavinm 			sp = osp;
5215254Sgavinm 		}
5225254Sgavinm 	}
5235254Sgavinm 	authamd->amd_shared = sp;
5245254Sgavinm 
5255254Sgavinm 	return (0);
5265254Sgavinm }
5275254Sgavinm 
5285254Sgavinm /*
5295254Sgavinm  * cms_logout_size entry point.
5305254Sgavinm  */
5315254Sgavinm /*ARGSUSED*/
5325254Sgavinm size_t
5335254Sgavinm authamd_logout_size(cmi_hdl_t hdl)
5345254Sgavinm {
5355254Sgavinm 	return (sizeof (struct authamd_logout));
5365254Sgavinm }
5375254Sgavinm 
5385254Sgavinm /*
5395254Sgavinm  * cms_mcgctl_val entry point
5405254Sgavinm  *
5415254Sgavinm  * Instead of setting all bits to 1 we can set just those for the
5425254Sgavinm  * error detector banks known to exist.
5435254Sgavinm  */
5445254Sgavinm /*ARGSUSED*/
5455254Sgavinm uint64_t
5465254Sgavinm authamd_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t proposed)
5475254Sgavinm {
5485254Sgavinm 	return (nbanks < 64 ? (1ULL << nbanks) - 1 : proposed);
5495254Sgavinm }
5505254Sgavinm 
5515254Sgavinm /*
5525254Sgavinm  * cms_bankctl_skipinit entry point
5535254Sgavinm  *
5545254Sgavinm  * On K6 we do not initialize MC0_CTL since, reportedly, this bank (for DC)
5555254Sgavinm  * may produce spurious machine checks.
5565639Sgavinm  *
5575639Sgavinm  * Only allow a single core to setup the NorthBridge MCi_CTL register.
5585254Sgavinm  */
5595254Sgavinm /*ARGSUSED*/
5605254Sgavinm boolean_t
5615254Sgavinm authamd_bankctl_skipinit(cmi_hdl_t hdl, int bank)
5625254Sgavinm {
5635254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
564*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
5655254Sgavinm 
566*11947Ssrihari.venkatesan@oracle.com 	if (authamd->amd_shared->ans_family == AUTHAMD_FAMILY_6)
5675639Sgavinm 		return (bank == 0 ?  B_TRUE : B_FALSE);
5685639Sgavinm 
5695639Sgavinm 	if (AUTHAMD_NBONCHIP(rev) && bank == AMD_MCA_BANK_NB) {
5705639Sgavinm 		return (authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCA) ==
5715639Sgavinm 		    B_TRUE ? B_FALSE : B_TRUE);
5725639Sgavinm 	}
5735639Sgavinm 
5745639Sgavinm 	return (B_FALSE);
5755254Sgavinm }
5765254Sgavinm 
5775254Sgavinm /*
5785254Sgavinm  * cms_bankctl_val entry point
5795254Sgavinm  */
5805254Sgavinm uint64_t
5815254Sgavinm authamd_bankctl_val(cmi_hdl_t hdl, int bank, uint64_t proposed)
5825254Sgavinm {
5835254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
584*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
5855254Sgavinm 	uint64_t val = proposed;
5865254Sgavinm 
5875254Sgavinm 	/*
5885254Sgavinm 	 * The Intel MCA says we can write all 1's to enable #MC for
5895254Sgavinm 	 * all errors, and AMD docs say much the same.  But, depending
5905254Sgavinm 	 * perhaps on other config registers, taking machine checks
5915254Sgavinm 	 * for some errors such as GART TLB errors and master/target
5925254Sgavinm 	 * aborts may be bad - they set UC and sometime also PCC, but
5935254Sgavinm 	 * we should not always panic for these error types.
5945254Sgavinm 	 *
5955254Sgavinm 	 * Our cms_error_action entry point can suppress such panics,
5965254Sgavinm 	 * however we can also use the cms_bankctl_val entry point to
5975254Sgavinm 	 * veto enabling of some of the known villains in the first place.
5985254Sgavinm 	 */
5995254Sgavinm 	if (bank == AMD_MCA_BANK_NB && AUTHAMD_NOGARTTBLWLK_MC(rev))
6005254Sgavinm 		val &= ~AMD_NB_EN_GARTTBLWK;
6015254Sgavinm 
6025254Sgavinm 	return (val);
6035254Sgavinm }
6045254Sgavinm 
6055254Sgavinm /*
6065327Sgavinm  * Bits to add to NB MCA config (after watchdog config).
6075327Sgavinm  */
6085327Sgavinm uint32_t authamd_nb_mcacfg_add = AMD_NB_CFG_ADD_CMN;
6095327Sgavinm 
6105327Sgavinm /*
6115327Sgavinm  * Bits to remove from NB MCA config (after watchdog config)
6125327Sgavinm  */
6135327Sgavinm uint32_t authamd_nb_mcacfg_remove = AMD_NB_CFG_REMOVE_CMN;
6145327Sgavinm 
6155327Sgavinm /*
6165327Sgavinm  * NB Watchdog policy, and rate we use if enabling.
6175327Sgavinm  */
6185327Sgavinm enum {
6195327Sgavinm 	AUTHAMD_NB_WDOG_LEAVEALONE,
6205327Sgavinm 	AUTHAMD_NB_WDOG_DISABLE,
6215327Sgavinm 	AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED,
6225327Sgavinm 	AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE
6235327Sgavinm } authamd_nb_watchdog_policy = AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED;
6245327Sgavinm 
6255327Sgavinm uint32_t authamd_nb_mcacfg_wdog = AMD_NB_CFG_WDOGTMRCNTSEL_4095 |
6265327Sgavinm     AMD_NB_CFG_WDOGTMRBASESEL_1MS;
6275327Sgavinm 
6285327Sgavinm /*
6295327Sgavinm  * Per-core cache scrubbing policy and rates.
6305327Sgavinm  */
6315327Sgavinm enum {
6325327Sgavinm 	AUTHAMD_SCRUB_BIOSDEFAULT,	/* leave as BIOS configured */
6335327Sgavinm 	AUTHAMD_SCRUB_FIXED,		/* assign our chosen rate */
6345327Sgavinm 	AUTHAMD_SCRUB_MAX		/* use higher of ours and BIOS rate */
6355327Sgavinm } authamd_scrub_policy = AUTHAMD_SCRUB_MAX;
6365327Sgavinm 
6375327Sgavinm uint32_t authamd_scrub_rate_dcache = 0xf;	/* 64K per 0.67 seconds */
6385327Sgavinm uint32_t authamd_scrub_rate_l2cache = 0xe;	/* 1MB per 5.3 seconds */
6395327Sgavinm uint32_t authamd_scrub_rate_l3cache = 0xd;	/* 1MB per 2.7 seconds */
6405327Sgavinm 
6415327Sgavinm static uint32_t
6425327Sgavinm authamd_scrubrate(uint32_t osrate, uint32_t biosrate, const char *varnm)
6435327Sgavinm {
6445327Sgavinm 	uint32_t rate;
6455327Sgavinm 
6465327Sgavinm 	if (osrate > AMD_NB_SCRUBCTL_RATE_MAX) {
6475327Sgavinm 		cmn_err(CE_WARN, "%s is too large, resetting to 0x%x\n",
6485327Sgavinm 		    varnm, AMD_NB_SCRUBCTL_RATE_MAX);
6495327Sgavinm 		osrate = AMD_NB_SCRUBCTL_RATE_MAX;
6505327Sgavinm 	}
6515327Sgavinm 
6525327Sgavinm 	switch (authamd_scrub_policy) {
6535327Sgavinm 	case AUTHAMD_SCRUB_FIXED:
6545327Sgavinm 		rate = osrate;
6555327Sgavinm 		break;
6565327Sgavinm 
6575327Sgavinm 	default:
6585327Sgavinm 		cmn_err(CE_WARN, "Unknown authamd_scrub_policy %d - "
6595327Sgavinm 		    "using default policy of AUTHAMD_SCRUB_MAX",
6605327Sgavinm 		    authamd_scrub_policy);
6615327Sgavinm 		/*FALLTHRU*/
6625327Sgavinm 
6635327Sgavinm 	case AUTHAMD_SCRUB_MAX:
6645327Sgavinm 		if (osrate != 0 && biosrate != 0)
6655327Sgavinm 			rate = MIN(osrate, biosrate);	/* small is fast */
6665327Sgavinm 		else
6675327Sgavinm 			rate = osrate ? osrate : biosrate;
6685327Sgavinm 	}
6695327Sgavinm 
6705327Sgavinm 	return (rate);
6715327Sgavinm }
6725327Sgavinm 
6735327Sgavinm /*
6745254Sgavinm  * cms_mca_init entry point.
6755254Sgavinm  */
6765254Sgavinm /*ARGSUSED*/
6775254Sgavinm void
6785254Sgavinm authamd_mca_init(cmi_hdl_t hdl, int nbanks)
6795254Sgavinm {
6805254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
681*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
682*11947Ssrihari.venkatesan@oracle.com 	uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
6835254Sgavinm 
6845254Sgavinm 	/*
6855254Sgavinm 	 * On chips with a NB online spare control register take control
6865254Sgavinm 	 * and clear ECC counts.
6875254Sgavinm 	 */
6885254Sgavinm 	if (AUTHAMD_HAS_ONLINESPARECTL(rev) &&
6895254Sgavinm 	    authamd_chip_once(authamd, AUTHAMD_CFGONCE_ONLNSPRCFG)) {
6905254Sgavinm 		authamd_clear_ecccnt(authamd, B_TRUE);
6915254Sgavinm 	}
6925254Sgavinm 
6935254Sgavinm 	/*
6945254Sgavinm 	 * And since we are claiming the telemetry stop the BIOS receiving
6955254Sgavinm 	 * an SMI on NB threshold overflow.
6965254Sgavinm 	 */
6975254Sgavinm 	if (AUTHAMD_NBMISC_NUM(rev) &&
6985254Sgavinm 	    authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBTHRESH)) {
6995254Sgavinm 		union mcmsr_nbmisc nbm;
7005254Sgavinm 		int i;
7015254Sgavinm 
7025254Sgavinm 		authamd_bankstatus_prewrite(hdl, authamd);
7035254Sgavinm 
7045254Sgavinm 		for (i = 0; i < AUTHAMD_NBMISC_NUM(rev); i++) {
7055254Sgavinm 			if (cmi_hdl_rdmsr(hdl, MC_MSR_NB_MISC(i),
7065254Sgavinm 			    (uint64_t *)&nbm) != CMI_SUCCESS)
7075254Sgavinm 				continue;
7085254Sgavinm 
7095254Sgavinm 			if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) &&
7105254Sgavinm 			    MCMSR_FIELD_F_revFG(&nbm, mcmisc_Valid) &&
7115254Sgavinm 			    MCMSR_FIELD_F_revFG(&nbm, mcmisc_CntP)) {
7125254Sgavinm 				MCMSR_FIELD_F_revFG(&nbm, mcmisc_IntType) = 0;
7135254Sgavinm 			} else if (X86_CHIPREV_ATLEAST(rev,
7145254Sgavinm 			    X86_CHIPREV_AMD_10_REV_A) &&
7155254Sgavinm 			    MCMSR_FIELD_10_revAB(&nbm, mcmisc_Valid) &&
7165254Sgavinm 			    MCMSR_FIELD_10_revAB(&nbm, mcmisc_CntP)) {
7175254Sgavinm 				MCMSR_FIELD_10_revAB(&nbm, mcmisc_IntType) = 0;
7185254Sgavinm 			}
7195254Sgavinm 
7205254Sgavinm 			(void) cmi_hdl_wrmsr(hdl, MC_MSR_NB_MISC(i),
7215254Sgavinm 			    MCMSR_VAL(&nbm));
7225254Sgavinm 		}
7235254Sgavinm 
7245254Sgavinm 		authamd_bankstatus_postwrite(hdl, authamd);
7255254Sgavinm 	}
7265327Sgavinm 
7275327Sgavinm 	/*
7285327Sgavinm 	 * NB MCA Configuration Register.
7295327Sgavinm 	 */
7305327Sgavinm 	if (AUTHAMD_DO_NBMCACFG(rev) &&
7315327Sgavinm 	    authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCACFG)) {
73210947SSrihari.Venkatesan@Sun.COM 		uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
7335327Sgavinm 		    MC_CTL_REG_NBCFG);
7345327Sgavinm 
7355327Sgavinm 		switch (authamd_nb_watchdog_policy) {
7365327Sgavinm 		case AUTHAMD_NB_WDOG_LEAVEALONE:
7375327Sgavinm 			break;
7385327Sgavinm 
7395327Sgavinm 		case AUTHAMD_NB_WDOG_DISABLE:
7405327Sgavinm 			val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK |
7415327Sgavinm 			    AMD_NB_CFG_WDOGTMRCNTSEL_MASK);
7425327Sgavinm 			val |= AMD_NB_CFG_WDOGTMRDIS;
7435327Sgavinm 			break;
7445327Sgavinm 
7455327Sgavinm 		default:
7465327Sgavinm 			cmn_err(CE_NOTE, "authamd_nb_watchdog_policy=%d "
7475327Sgavinm 			    "unrecognised, using default policy",
7485327Sgavinm 			    authamd_nb_watchdog_policy);
7495327Sgavinm 			/*FALLTHRU*/
7505327Sgavinm 
7515327Sgavinm 		case AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED:
7525327Sgavinm 			if (!(val & AMD_NB_CFG_WDOGTMRDIS))
7535327Sgavinm 				break;	/* if enabled leave rate intact */
7545327Sgavinm 			/*FALLTHRU*/
7555327Sgavinm 
7565327Sgavinm 		case AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE:
7575327Sgavinm 			val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK |
7585327Sgavinm 			    AMD_NB_CFG_WDOGTMRCNTSEL_MASK |
7595327Sgavinm 			    AMD_NB_CFG_WDOGTMRDIS);
7605327Sgavinm 			val |= authamd_nb_mcacfg_wdog;
7615327Sgavinm 			break;
7625327Sgavinm 		}
7635327Sgavinm 
7645327Sgavinm 		/*
7655327Sgavinm 		 * Bit 0 of the NB MCA Config register is reserved on family
7665327Sgavinm 		 * 0x10.
7675327Sgavinm 		 */
7685327Sgavinm 		if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
7695327Sgavinm 			authamd_nb_mcacfg_add &= ~AMD_NB_CFG_CPUECCERREN;
7705327Sgavinm 
7715327Sgavinm 		val &= ~authamd_nb_mcacfg_remove;
7725327Sgavinm 		val |= authamd_nb_mcacfg_add;
7735327Sgavinm 
77410947SSrihari.Venkatesan@Sun.COM 		authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
77510947SSrihari.Venkatesan@Sun.COM 		    MC_CTL_REG_NBCFG, val);
7765327Sgavinm 	}
7775327Sgavinm 
7785327Sgavinm 	/*
7795327Sgavinm 	 * Cache scrubbing.  We can't enable DRAM scrubbing since
7805327Sgavinm 	 * we don't know the DRAM base for this node.
7815327Sgavinm 	 */
7825327Sgavinm 	if (AUTHAMD_HAS_CHIPSCRUB(rev) &&
7835327Sgavinm 	    authamd_scrub_policy != AUTHAMD_SCRUB_BIOSDEFAULT &&
7845327Sgavinm 	    authamd_chip_once(authamd, AUTHAMD_CFGONCE_CACHESCRUB)) {
78510947SSrihari.Venkatesan@Sun.COM 		uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
7865327Sgavinm 		    MC_CTL_REG_SCRUBCTL);
7875327Sgavinm 		int l3cap = 0;
7885327Sgavinm 
7895327Sgavinm 		if (AUTHAMD_L3CAPABLE(rev)) {
79010947SSrihari.Venkatesan@Sun.COM 			l3cap = (authamd_pcicfg_read(procnodeid,
79110947SSrihari.Venkatesan@Sun.COM 			    MC_FUNC_MISCCTL, MC_CTL_REG_NBCAP) &
79210947SSrihari.Venkatesan@Sun.COM 			    MC_NBCAP_L3CAPABLE) != 0;
7935327Sgavinm 		}
7945327Sgavinm 
7955327Sgavinm 		authamd_scrub_rate_dcache =
7965327Sgavinm 		    authamd_scrubrate(authamd_scrub_rate_dcache,
7975327Sgavinm 		    (val & AMD_NB_SCRUBCTL_DC_MASK) >> AMD_NB_SCRUBCTL_DC_SHIFT,
7985327Sgavinm 		    "authamd_scrub_rate_dcache");
7995327Sgavinm 
8005327Sgavinm 		authamd_scrub_rate_l2cache =
8015327Sgavinm 		    authamd_scrubrate(authamd_scrub_rate_l2cache,
8025327Sgavinm 		    (val & AMD_NB_SCRUBCTL_L2_MASK) >> AMD_NB_SCRUBCTL_L2_SHIFT,
8035327Sgavinm 		    "authamd_scrub_rate_l2cache");
8045327Sgavinm 
8055327Sgavinm 		authamd_scrub_rate_l3cache = l3cap ?
8065327Sgavinm 		    authamd_scrubrate(authamd_scrub_rate_l3cache,
8075327Sgavinm 		    (val & AMD_NB_SCRUBCTL_L3_MASK) >> AMD_NB_SCRUBCTL_L3_SHIFT,
8085327Sgavinm 		    "authamd_scrub_rate_l3cache") : 0;
8095327Sgavinm 
8105327Sgavinm 		val = AMD_NB_MKSCRUBCTL(authamd_scrub_rate_l3cache,
8115327Sgavinm 		    authamd_scrub_rate_dcache, authamd_scrub_rate_l2cache,
8125327Sgavinm 		    val & AMD_NB_SCRUBCTL_DRAM_MASK);
8135327Sgavinm 
81410947SSrihari.Venkatesan@Sun.COM 		authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
8155327Sgavinm 		    MC_CTL_REG_SCRUBCTL, val);
8165327Sgavinm 	}
8175327Sgavinm 
818*11947Ssrihari.venkatesan@oracle.com 	/*
819*11947Ssrihari.venkatesan@oracle.com 	 * ECC symbol size. Defaults to 4.
820*11947Ssrihari.venkatesan@oracle.com 	 * Set to 8 on systems that support x8 ECC and have it enabled.
821*11947Ssrihari.venkatesan@oracle.com 	 */
822*11947Ssrihari.venkatesan@oracle.com 	if (authamd_chip_once(authamd, AUTHAMD_CFGONCE_ECCSYMSZ)) {
823*11947Ssrihari.venkatesan@oracle.com 		authamd->amd_shared->ans_eccsymsz = "C4";
824*11947Ssrihari.venkatesan@oracle.com 		if (AUTHAMD_SUPPORTS_X8ECC(rev) &&
825*11947Ssrihari.venkatesan@oracle.com 		    (authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
826*11947Ssrihari.venkatesan@oracle.com 		    MC_CTL_REG_EXTNBCFG) & MC_EXTNBCFG_ECCSYMSZ))
827*11947Ssrihari.venkatesan@oracle.com 			authamd->amd_shared->ans_eccsymsz = "C8";
828*11947Ssrihari.venkatesan@oracle.com 	}
8295327Sgavinm }
8305327Sgavinm 
8315327Sgavinm /*
8325327Sgavinm  * cms_poll_ownermask entry point.
8335327Sgavinm  */
8345327Sgavinm uint64_t
8355327Sgavinm authamd_poll_ownermask(cmi_hdl_t hdl, hrtime_t pintvl)
8365327Sgavinm {
8375327Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
838*11947Ssrihari.venkatesan@oracle.com 	struct authamd_nodeshared *ansp = authamd->amd_shared;
8395327Sgavinm 	hrtime_t now = gethrtime_waitfree();
840*11947Ssrihari.venkatesan@oracle.com 	hrtime_t last = ansp->ans_poll_timestamp;
8415327Sgavinm 	int dopoll = 0;
8425327Sgavinm 
8435327Sgavinm 	if (now - last > 2 * pintvl || last == 0) {
844*11947Ssrihari.venkatesan@oracle.com 		ansp->ans_pollowner = hdl;
8455327Sgavinm 		dopoll = 1;
846*11947Ssrihari.venkatesan@oracle.com 	} else if (ansp->ans_pollowner == hdl) {
8475327Sgavinm 		dopoll = 1;
8485327Sgavinm 	}
8495327Sgavinm 
8505327Sgavinm 	if (dopoll)
851*11947Ssrihari.venkatesan@oracle.com 		ansp->ans_poll_timestamp = now;
8525327Sgavinm 
8535327Sgavinm 	return (dopoll ? -1ULL : ~(1 << AMD_MCA_BANK_NB));
8545327Sgavinm 
8555254Sgavinm }
8565254Sgavinm 
8575254Sgavinm /*
8585254Sgavinm  * cms_bank_logout entry point.
8595254Sgavinm  */
8605254Sgavinm /*ARGSUSED*/
8615254Sgavinm void
8625254Sgavinm authamd_bank_logout(cmi_hdl_t hdl, int bank, uint64_t status,
8635254Sgavinm     uint64_t addr, uint64_t misc, void *mslogout)
8645254Sgavinm {
8655254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
8665254Sgavinm 	struct authamd_logout *msl = mslogout;
867*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
8685254Sgavinm 
8695254Sgavinm 	if (msl == NULL)
8705254Sgavinm 		return;
8715254Sgavinm 
8725254Sgavinm 	/*
8735254Sgavinm 	 * For main memory ECC errors on revisions with an Online Spare
8745254Sgavinm 	 * Control Register grab the ECC counts by channel and chip-select
8755254Sgavinm 	 * and reset them to 0.
8765254Sgavinm 	 */
8775254Sgavinm 	if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
8785254Sgavinm 	    AUTHAMD_IS_MEMECCERR(bank, status) &&
8795254Sgavinm 	    AUTHAMD_HAS_ONLINESPARECTL(rev)) {
8805254Sgavinm 		if (authamd_read_ecccnt(authamd, msl))
8815254Sgavinm 			authamd_clear_ecccnt(authamd, B_FALSE);
8825254Sgavinm 	}
8835254Sgavinm }
8845254Sgavinm 
8855254Sgavinm /*
8865254Sgavinm  * cms_error_action entry point
8875254Sgavinm  */
8885254Sgavinm 
8895254Sgavinm int authamd_forgive_uc = 0;	/* For test/debug only */
8905254Sgavinm int authamd_forgive_pcc = 0;	/* For test/debug only */
8915254Sgavinm int authamd_fake_poison = 0;	/* For test/debug only */
8925254Sgavinm 
8935254Sgavinm /*ARGSUSED*/
8945254Sgavinm uint32_t
8955254Sgavinm authamd_error_action(cmi_hdl_t hdl, int ismc, int bank,
8965254Sgavinm     uint64_t status, uint64_t addr, uint64_t misc, void *mslogout)
8975254Sgavinm {
8985254Sgavinm 	authamd_error_disp_t *disp;
8995254Sgavinm 	uint32_t rv = 0;
9005254Sgavinm 
9015254Sgavinm 	if (authamd_forgive_uc)
9025254Sgavinm 		rv |= CMS_ERRSCOPE_CLEARED_UC;
9035254Sgavinm 
9045254Sgavinm 	if (authamd_forgive_pcc)
9055254Sgavinm 		rv |= CMS_ERRSCOPE_CURCONTEXT_OK;
9065254Sgavinm 
9075254Sgavinm 	if (authamd_fake_poison && status & MSR_MC_STATUS_UC)
9085254Sgavinm 		rv |= CMS_ERRSCOPE_POISONED;
9095254Sgavinm 
9105254Sgavinm 	if (rv)
9115254Sgavinm 		return (rv);
9125254Sgavinm 
9135254Sgavinm 	disp = authamd_disp_match(hdl, bank, status, addr, misc, mslogout);
9145254Sgavinm 
9155254Sgavinm 	if (disp == &authamd_gart_disp) {
9165254Sgavinm 		/*
9175254Sgavinm 		 * GART walk errors set UC and possibly PCC (if source CPU)
9185254Sgavinm 		 * but should not be regarded as terminal.
9195254Sgavinm 		 */
9205254Sgavinm 		return (CMS_ERRSCOPE_IGNORE_ERR);
9215254Sgavinm 	}
9225254Sgavinm 
9235254Sgavinm 	/*
9245254Sgavinm 	 * May also want to consider master abort and target abort.  These
9255254Sgavinm 	 * also set UC and PCC (if src CPU) but the requester gets -1
9265254Sgavinm 	 * and I believe the IO stuff in Solaris will handle that.
9275254Sgavinm 	 */
9285254Sgavinm 
9295254Sgavinm 	return (rv);
9305254Sgavinm }
9315254Sgavinm 
9325254Sgavinm /*
9335254Sgavinm  * cms_disp_match entry point
9345254Sgavinm  */
9355254Sgavinm /*ARGSUSED*/
9365254Sgavinm cms_cookie_t
9375254Sgavinm authamd_disp_match(cmi_hdl_t hdl, int bank, uint64_t status,
9385254Sgavinm     uint64_t addr, uint64_t misc, void *mslogout)
9395254Sgavinm {
9405254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
9415254Sgavinm 	/* uint16_t errcode = MCAX86_ERRCODE(status); */
9425254Sgavinm 	uint16_t exterrcode = AMD_EXT_ERRCODE(status);
943*11947Ssrihari.venkatesan@oracle.com 	uint32_t rev = authamd->amd_shared->ans_rev;
9445254Sgavinm 
9455254Sgavinm 	/*
9465254Sgavinm 	 * Recognise main memory ECC errors
9475254Sgavinm 	 */
9485254Sgavinm 	if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
9495254Sgavinm 	    AUTHAMD_IS_MEMECCERR(bank, status)) {
9505254Sgavinm 		if (status & AMD_BANK_STAT_CECC) {
9515254Sgavinm 			return (exterrcode == 0 ? &authamd_memce_disp :
9525254Sgavinm 			    &authamd_ckmemce_disp);
9535254Sgavinm 		} else if (status & AMD_BANK_STAT_UECC) {
9545254Sgavinm 			return (exterrcode == 0 ? &authamd_memue_disp :
9555254Sgavinm 			    &authamd_ckmemue_disp);
9565254Sgavinm 		}
9575254Sgavinm 	}
9585254Sgavinm 
9595254Sgavinm 	/*
9605254Sgavinm 	 * Recognise GART walk errors
9615254Sgavinm 	 */
9625254Sgavinm 	if (AUTHAMD_NOGARTTBLWLK_MC(rev) && AUTHAMD_IS_GARTERR(bank, status))
9635254Sgavinm 		return (&authamd_gart_disp);
9645254Sgavinm 
9655254Sgavinm 	return (NULL);
9665254Sgavinm }
9675254Sgavinm 
9685254Sgavinm /*
9695254Sgavinm  * cms_ereport_class entry point
9705254Sgavinm  */
9715254Sgavinm /*ARGSUSED*/
9725254Sgavinm void
9735254Sgavinm authamd_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie,
9745254Sgavinm     const char **cpuclsp, const char **leafclsp)
9755254Sgavinm {
9765254Sgavinm 	const authamd_error_disp_t *aed = mscookie;
9775254Sgavinm 
9785254Sgavinm 	if (aed == NULL)
9795254Sgavinm 		return;
9805254Sgavinm 
9815254Sgavinm 	if (aed->aad_subclass != NULL)
9825254Sgavinm 		*cpuclsp = aed->aad_subclass;
9835254Sgavinm 	if (aed->aad_leafclass != NULL)
9845254Sgavinm 		*leafclsp = aed->aad_leafclass;
9855254Sgavinm }
9865254Sgavinm 
9875254Sgavinm /*ARGSUSED*/
9885254Sgavinm static void
9895254Sgavinm authamd_ereport_add_resource(cmi_hdl_t hdl, authamd_data_t *authamd,
9905254Sgavinm     nvlist_t *ereport, nv_alloc_t *nva, void *mslogout)
9915254Sgavinm {
9925254Sgavinm 	nvlist_t *elems[AUTHAMD_DRAM_NCHANNEL * AUTHAMD_DRAM_NCS];
9935254Sgavinm 	uint8_t counts[AUTHAMD_DRAM_NCHANNEL * AUTHAMD_DRAM_NCS];
9945254Sgavinm 	authamd_logout_t *msl;
9955254Sgavinm 	nvlist_t *nvl;
9965254Sgavinm 	int nelems = 0;
99710947SSrihari.Venkatesan@Sun.COM 	int i, chan, cs, mc;
99810942STom.Pothier@Sun.COM 	nvlist_t *board_list = NULL;
9995254Sgavinm 
10005254Sgavinm 	if ((msl = mslogout) == NULL)
10015254Sgavinm 		return;
10025254Sgavinm 
100310947SSrihari.Venkatesan@Sun.COM 	/* Assume all processors have the same number of nodes */
1004*11947Ssrihari.venkatesan@oracle.com 	mc = authamd->amd_shared->ans_procnodeid %
100510947SSrihari.Venkatesan@Sun.COM 	    cpuid_get_procnodes_per_pkg(CPU);
100610947SSrihari.Venkatesan@Sun.COM 
10075254Sgavinm 	for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
10085254Sgavinm 		for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
10095254Sgavinm 			if (msl->aal_eccerrcnt[chan][cs] == 0)
10105254Sgavinm 				continue;
10115254Sgavinm 
10125254Sgavinm 			if ((nvl = fm_nvlist_create(nva)) == NULL)
10135254Sgavinm 				continue;
10145254Sgavinm 
10155254Sgavinm 			elems[nelems] = nvl;
10165254Sgavinm 			counts[nelems++] = msl->aal_eccerrcnt[chan][cs];
10175254Sgavinm 
101810942STom.Pothier@Sun.COM 			if (!x86gentopo_legacy) {
101910942STom.Pothier@Sun.COM 				board_list = cmi_hdl_smb_bboard(hdl);
102010942STom.Pothier@Sun.COM 				if (board_list == NULL)
102110942STom.Pothier@Sun.COM 					continue;
102210942STom.Pothier@Sun.COM 				fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION,
102310942STom.Pothier@Sun.COM 				    NULL, NULL, board_list, 4,
102410942STom.Pothier@Sun.COM 				    "chip", cmi_hdl_smb_chipid(hdl),
102510942STom.Pothier@Sun.COM 				    "memory-controller", 0,
102610942STom.Pothier@Sun.COM 				    "dram-channel", chan,
102710942STom.Pothier@Sun.COM 				    "chip-select", cs);
102810942STom.Pothier@Sun.COM 			} else {
102910942STom.Pothier@Sun.COM 				fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION,
103010942STom.Pothier@Sun.COM 				    NULL, NULL, 5,
103110942STom.Pothier@Sun.COM 				    "motherboard", 0,
1032*11947Ssrihari.venkatesan@oracle.com 				    "chip", authamd->amd_shared->ans_chipid,
103310947SSrihari.Venkatesan@Sun.COM 				    "memory-controller", mc,
103410942STom.Pothier@Sun.COM 				    "dram-channel", chan,
103510942STom.Pothier@Sun.COM 				    "chip-select", cs);
103610942STom.Pothier@Sun.COM 			}
10375254Sgavinm 		}
10385254Sgavinm 	}
10395254Sgavinm 
10405254Sgavinm 	if (nelems == 0)
10415254Sgavinm 		return;
10425254Sgavinm 
10435254Sgavinm 	fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_RESOURCE,
10445254Sgavinm 	    DATA_TYPE_NVLIST_ARRAY, nelems, elems,
10455254Sgavinm 	    NULL);
10465254Sgavinm 
10475254Sgavinm 	fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_RESOURCECNT,
10485254Sgavinm 	    DATA_TYPE_UINT8_ARRAY, nelems, &counts[0],
10495254Sgavinm 	    NULL);
10505254Sgavinm 
10515254Sgavinm 	for (i = 0; i < nelems; i++)
10525254Sgavinm 		fm_nvlist_destroy(elems[i], nva ? FM_NVA_RETAIN : FM_NVA_FREE);
10535254Sgavinm }
10545254Sgavinm 
10555254Sgavinm /*
10565254Sgavinm  * cms_ereport_add_logout entry point
10575254Sgavinm  */
10585254Sgavinm /*ARGSUSED*/
10595254Sgavinm void
10605254Sgavinm authamd_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport, nv_alloc_t *nva,
10615254Sgavinm     int bank, uint64_t status, uint64_t addr, uint64_t misc,
10625254Sgavinm     void *mslogout, cms_cookie_t mscookie)
10635254Sgavinm {
10645254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
10655254Sgavinm 	const authamd_error_disp_t *aed = mscookie;
10665254Sgavinm 	uint64_t members;
10675254Sgavinm 
10685254Sgavinm 	if (aed == NULL)
10695254Sgavinm 		return;
10705254Sgavinm 
10715254Sgavinm 	members = aed->aad_ereport_members;
10725254Sgavinm 
10735254Sgavinm 	if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYND) {
10745254Sgavinm 		fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_SYND,
10755254Sgavinm 		    DATA_TYPE_UINT16, (uint16_t)AMD_BANK_SYND(status),
10765254Sgavinm 		    NULL);
10775254Sgavinm 
10785254Sgavinm 		if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYNDTYPE) {
10795254Sgavinm 			fm_payload_set(ereport,
10805254Sgavinm 			    FM_EREPORT_GENAMD_PAYLOAD_NAME_SYNDTYPE,
10815254Sgavinm 			    DATA_TYPE_STRING, "E",
10825254Sgavinm 			    NULL);
10835254Sgavinm 		}
10845254Sgavinm 	}
10855254Sgavinm 
10865254Sgavinm 	if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_CKSYND) {
10875254Sgavinm 		fm_payload_set(ereport, FM_EREPORT_GENAMD_PAYLOAD_NAME_CKSYND,
10885254Sgavinm 		    DATA_TYPE_UINT16, (uint16_t)AMD_NB_STAT_CKSYND(status),
10895254Sgavinm 		    NULL);
10905254Sgavinm 
10915254Sgavinm 		if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_SYNDTYPE) {
10925254Sgavinm 			fm_payload_set(ereport,
10935254Sgavinm 			    FM_EREPORT_GENAMD_PAYLOAD_NAME_SYNDTYPE,
1094*11947Ssrihari.venkatesan@oracle.com 			    DATA_TYPE_STRING, authamd->amd_shared->ans_eccsymsz,
10955254Sgavinm 			    NULL);
10965254Sgavinm 		}
10975254Sgavinm 	}
10985254Sgavinm 
10995254Sgavinm 	if (members & FM_EREPORT_GENAMD_PAYLOAD_FLAG_RESOURCE &&
11005254Sgavinm 	    status & MSR_MC_STATUS_ADDRV) {
11015254Sgavinm 		authamd_ereport_add_resource(hdl, authamd, ereport, nva,
11025254Sgavinm 		    mslogout);
11035254Sgavinm 	}
11045254Sgavinm }
11055254Sgavinm 
11065254Sgavinm /*
11075254Sgavinm  * cms_msrinject entry point
11085254Sgavinm  */
11095254Sgavinm cms_errno_t
11105254Sgavinm authamd_msrinject(cmi_hdl_t hdl, uint_t msr, uint64_t val)
11115254Sgavinm {
11125254Sgavinm 	authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
11135254Sgavinm 	cms_errno_t rv = CMSERR_BADMSRWRITE;
11145254Sgavinm 
11155254Sgavinm 	authamd_bankstatus_prewrite(hdl, authamd);
11165254Sgavinm 	if (cmi_hdl_wrmsr(hdl, msr, val) == CMI_SUCCESS)
11175254Sgavinm 		rv = CMS_SUCCESS;
11185254Sgavinm 	authamd_bankstatus_postwrite(hdl, authamd);
11195254Sgavinm 
11205254Sgavinm 	return (rv);
11215254Sgavinm }
11225254Sgavinm 
112311168SYanmin.Sun@Sun.COM cms_api_ver_t _cms_api_version = CMS_API_VERSION_1;
11245254Sgavinm 
11255254Sgavinm const cms_ops_t _cms_ops = {
11265254Sgavinm 	authamd_init,			/* cms_init */
11275254Sgavinm 	NULL,				/* cms_post_startup */
11285254Sgavinm 	NULL,				/* cms_post_mpstartup */
11295254Sgavinm 	authamd_logout_size,		/* cms_logout_size */
11305254Sgavinm 	authamd_mcgctl_val,		/* cms_mcgctl_val */
11315254Sgavinm 	authamd_bankctl_skipinit,	/* cms_bankctl_skipinit */
11325254Sgavinm 	authamd_bankctl_val,		/* cms_bankctl_val */
11335254Sgavinm 	NULL,				/* cms_bankstatus_skipinit */
11345254Sgavinm 	NULL,				/* cms_bankstatus_val */
11355254Sgavinm 	authamd_mca_init,		/* cms_mca_init */
11365327Sgavinm 	authamd_poll_ownermask,		/* cms_poll_ownermask */
11375254Sgavinm 	authamd_bank_logout,		/* cms_bank_logout */
11385254Sgavinm 	authamd_error_action,		/* cms_error_action */
11395254Sgavinm 	authamd_disp_match,		/* cms_disp_match */
11405254Sgavinm 	authamd_ereport_class,		/* cms_ereport_class */
11415254Sgavinm 	NULL,				/* cms_ereport_detector */
11425254Sgavinm 	NULL,				/* cms_ereport_includestack */
11435254Sgavinm 	authamd_ereport_add_logout,	/* cms_ereport_add_logout */
11445254Sgavinm 	authamd_msrinject,		/* cms_msrinject */
11455254Sgavinm 	NULL,				/* cms_fini */
11465254Sgavinm };
11475254Sgavinm 
11485254Sgavinm static struct modlcpu modlcpu = {
11495254Sgavinm 	&mod_cpuops,
11505254Sgavinm 	"Generic AMD model-specific MCA"
11515254Sgavinm };
11525254Sgavinm 
11535254Sgavinm static struct modlinkage modlinkage = {
11545254Sgavinm 	MODREV_1,
11555254Sgavinm 	(void *)&modlcpu,
11565254Sgavinm 	NULL
11575254Sgavinm };
11585254Sgavinm 
11595254Sgavinm int
11605254Sgavinm _init(void)
11615254Sgavinm {
11625254Sgavinm 	return (mod_install(&modlinkage));
11635254Sgavinm }
11645254Sgavinm 
11655254Sgavinm int
11665254Sgavinm _info(struct modinfo *modinfop)
11675254Sgavinm {
11685254Sgavinm 	return (mod_info(&modlinkage, modinfop));
11695254Sgavinm }
11705254Sgavinm 
11715254Sgavinm int
11725254Sgavinm _fini(void)
11735254Sgavinm {
11745254Sgavinm 	return (mod_remove(&modlinkage));
11755254Sgavinm }
1176