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