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 /*
2312437SAdrian.Frost@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245254Sgavinm */
255254Sgavinm
265254Sgavinm /*
275254Sgavinm * "Generic AMD" model-specific support. If no more-specific support can
285254Sgavinm * be found, or such modules declines to initialize, then for AuthenticAMD
295254Sgavinm * cpus this module can have a crack at providing some AMD model-specific
305254Sgavinm * support that at least goes beyond common MCA architectural features
315254Sgavinm * if not down to the nitty-gritty level for a particular model. We
325254Sgavinm * are layered on top of a cpu module, likely cpu.generic, so there is no
335254Sgavinm * need for us to perform common architecturally-accessible functions.
345254Sgavinm */
355254Sgavinm
365254Sgavinm #include <sys/types.h>
375254Sgavinm #include <sys/cmn_err.h>
385254Sgavinm #include <sys/modctl.h>
395254Sgavinm #include <sys/cpu_module.h>
405254Sgavinm #include <sys/mca_x86.h>
415254Sgavinm #include <sys/pci_cfgspace.h>
425254Sgavinm #include <sys/x86_archext.h>
435254Sgavinm #include <sys/mc_amd.h>
445254Sgavinm #include <sys/fm/protocol.h>
455254Sgavinm #include <sys/fm/cpu/GENAMD.h>
4610942STom.Pothier@Sun.COM #include <sys/fm/smb/fmsmb.h>
4710942STom.Pothier@Sun.COM #include <sys/fm/util.h>
485254Sgavinm #include <sys/nvpair.h>
495254Sgavinm #include <sys/controlregs.h>
505254Sgavinm #include <sys/pghw.h>
515254Sgavinm #include <sys/sunddi.h>
525327Sgavinm #include <sys/sysmacros.h>
535254Sgavinm #include <sys/cpu_module_ms_impl.h>
545254Sgavinm
555254Sgavinm #include "authamd.h"
565254Sgavinm
5710942STom.Pothier@Sun.COM extern int x86gentopo_legacy; /* x86 generic topo support */
5810942STom.Pothier@Sun.COM
595254Sgavinm int authamd_ms_support_disable = 0;
605254Sgavinm
615254Sgavinm #define AUTHAMD_F_REVS_BCDE \
625254Sgavinm (X86_CHIPREV_AMD_F_REV_B | X86_CHIPREV_AMD_F_REV_C0 | \
635254Sgavinm X86_CHIPREV_AMD_F_REV_CG | X86_CHIPREV_AMD_F_REV_D | \
645254Sgavinm X86_CHIPREV_AMD_F_REV_E)
655254Sgavinm
665254Sgavinm #define AUTHAMD_F_REVS_FG \
675254Sgavinm (X86_CHIPREV_AMD_F_REV_F | X86_CHIPREV_AMD_F_REV_G)
685254Sgavinm
695254Sgavinm #define AUTHAMD_10_REVS_AB \
705254Sgavinm (X86_CHIPREV_AMD_10_REV_A | X86_CHIPREV_AMD_10_REV_B)
715254Sgavinm
725254Sgavinm /*
735254Sgavinm * Bitmasks of support for various features. Try to enable features
745254Sgavinm * via inclusion in one of these bitmasks and check that at the
755254Sgavinm * feature imlementation - that way new family support may often simply
765254Sgavinm * simply need to update these bitmasks.
775254Sgavinm */
785254Sgavinm
795254Sgavinm /*
805639Sgavinm * Models that include an on-chip NorthBridge.
815639Sgavinm */
825639Sgavinm #define AUTHAMD_NBONCHIP(rev) \
835639Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
845639Sgavinm X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
855639Sgavinm
865639Sgavinm /*
875254Sgavinm * Families/revisions for which we can recognise main memory ECC errors.
885254Sgavinm */
895254Sgavinm #define AUTHAMD_MEMECC_RECOGNISED(rev) \
905254Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
915254Sgavinm X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
925254Sgavinm
935254Sgavinm /*
945254Sgavinm * Families/revisions that have an Online Spare Control Register
955254Sgavinm */
965254Sgavinm #define AUTHAMD_HAS_ONLINESPARECTL(rev) \
975254Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) || \
985254Sgavinm X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
995254Sgavinm
1005254Sgavinm /*
1015327Sgavinm * Families/revisions for which we will perform NB MCA Config changes
1025327Sgavinm */
1035327Sgavinm #define AUTHAMD_DO_NBMCACFG(rev) \
1045639Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
1055327Sgavinm X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1065327Sgavinm
1075327Sgavinm /*
1085327Sgavinm * Families/revisions that have chip cache scrubbers.
1095327Sgavinm */
1105327Sgavinm #define AUTHAMD_HAS_CHIPSCRUB(rev) \
1115639Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
1125327Sgavinm X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1135327Sgavinm
1145327Sgavinm /*
1155254Sgavinm * Families/revisions that have a NB misc register or registers -
1165254Sgavinm * evaluates to 0 if no support, otherwise the number of MC4_MISCj.
1175254Sgavinm */
1185254Sgavinm #define AUTHAMD_NBMISC_NUM(rev) \
1195254Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F)? 1 : \
1205254Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A) ? 3 : 0))
1215254Sgavinm
1225254Sgavinm /*
1235254Sgavinm * Families/revision for which we wish not to machine check for GART
1245254Sgavinm * table walk errors - bit 10 of NB CTL.
1255254Sgavinm */
1265254Sgavinm #define AUTHAMD_NOGARTTBLWLK_MC(rev) \
1275254Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_B) || \
1285254Sgavinm X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1295254Sgavinm
1305254Sgavinm /*
1315327Sgavinm * Families/revisions that are potentially L3 capable
1325327Sgavinm */
1335327Sgavinm #define AUTHAMD_L3CAPABLE(rev) \
1345327Sgavinm (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
1355327Sgavinm
1365327Sgavinm /*
13711947Ssrihari.venkatesan@oracle.com * Families/revisions that support x8 ChipKill ECC
13811947Ssrihari.venkatesan@oracle.com */
13911947Ssrihari.venkatesan@oracle.com #define AUTHAMD_SUPPORTS_X8ECC(rev) \
14011947Ssrihari.venkatesan@oracle.com (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_D))
14111947Ssrihari.venkatesan@oracle.com
14211947Ssrihari.venkatesan@oracle.com /*
1435254Sgavinm * We recognise main memory ECC errors for AUTHAMD_MEMECC_RECOGNISED
1445254Sgavinm * revisions as:
1455254Sgavinm *
1465254Sgavinm * - being reported by the NB
1475254Sgavinm * - being a compound bus/interconnect error (external to chip)
1485254Sgavinm * - having LL of LG
1495254Sgavinm * - having II of MEM (but could still be a master/target abort)
1505254Sgavinm * - having CECC or UECC set
1515254Sgavinm *
1525254Sgavinm * We do not check the extended error code (first nibble of the
1535254Sgavinm * model-specific error code on AMD) since this has changed from
1545254Sgavinm * family 0xf to family 0x10 (ext code 0 now reserved on family 0x10).
1555254Sgavinm * Instead we use CECC/UECC to separate off the master/target
1565254Sgavinm * abort cases.
1575254Sgavinm *
1585254Sgavinm * We insist that the detector be the NorthBridge bank; although
1595254Sgavinm * IC/DC can report some main memory errors, they do not capture
1605254Sgavinm * an address at sufficient resolution to be useful and the NB will
1615254Sgavinm * report most errors.
1625254Sgavinm */
1635254Sgavinm #define AUTHAMD_IS_MEMECCERR(bank, status) \
1645254Sgavinm ((bank) == AMD_MCA_BANK_NB && \
1655254Sgavinm MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status)) && \
1665254Sgavinm MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
1675254Sgavinm MCAX86_ERRCODE_II(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_II_MEM && \
1685254Sgavinm ((status) & (AMD_BANK_STAT_CECC | AMD_BANK_STAT_UECC)))
1695254Sgavinm
1705254Sgavinm static authamd_error_disp_t authamd_memce_disp = {
1715254Sgavinm FM_EREPORT_CPU_GENAMD,
1725254Sgavinm FM_EREPORT_CPU_GENAMD_MEM_CE,
1735254Sgavinm FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_CE
1745254Sgavinm };
1755254Sgavinm
1765254Sgavinm static authamd_error_disp_t authamd_memue_disp = {
1775254Sgavinm FM_EREPORT_CPU_GENAMD,
1785254Sgavinm FM_EREPORT_CPU_GENAMD_MEM_UE,
1795254Sgavinm FM_EREPORT_GENAMD_PAYLOAD_FLAGS_MEM_UE
1805254Sgavinm };
1815254Sgavinm
1825254Sgavinm static authamd_error_disp_t authamd_ckmemce_disp = {
1835254Sgavinm FM_EREPORT_CPU_GENAMD,
1845254Sgavinm FM_EREPORT_CPU_GENAMD_CKMEM_CE,
1855254Sgavinm FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_CE
1865254Sgavinm };
1875254Sgavinm
1885254Sgavinm static authamd_error_disp_t authamd_ckmemue_disp = {
1895254Sgavinm FM_EREPORT_CPU_GENAMD,
1905254Sgavinm FM_EREPORT_CPU_GENAMD_CKMEM_UE,
1915254Sgavinm FM_EREPORT_GENAMD_PAYLOAD_FLAGS_CKMEM_UE
1925254Sgavinm };
1935254Sgavinm
1945254Sgavinm /*
1955254Sgavinm * We recognise GART walk errors as:
1965254Sgavinm *
1975254Sgavinm * - being reported by the NB
1985254Sgavinm * - being a compound TLB error
1995254Sgavinm * - having LL of LG and TT of GEN
2005254Sgavinm * - having UC set
2015254Sgavinm * - possibly having PCC set (if source CPU)
2025254Sgavinm */
2035254Sgavinm #define AUTHAMD_IS_GARTERR(bank, status) \
2045254Sgavinm ((bank) == AMD_MCA_BANK_NB && \
2055254Sgavinm MCAX86_ERRCODE_ISTLB(MCAX86_ERRCODE(status)) && \
2065254Sgavinm MCAX86_ERRCODE_LL(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_LL_LG && \
2075254Sgavinm MCAX86_ERRCODE_TT(MCAX86_ERRCODE(status)) == MCAX86_ERRCODE_TT_GEN && \
2085254Sgavinm (status) & MSR_MC_STATUS_UC)
2095254Sgavinm
2105254Sgavinm static authamd_error_disp_t authamd_gart_disp = {
2115254Sgavinm FM_EREPORT_CPU_GENAMD, /* use generic subclass */
2125254Sgavinm FM_EREPORT_CPU_GENADM_GARTTBLWLK, /* use generic leafclass */
2135254Sgavinm 0 /* no additional payload */
2145254Sgavinm };
2155254Sgavinm
2165254Sgavinm
21710947SSrihari.Venkatesan@Sun.COM static struct authamd_nodeshared *authamd_shared[AUTHAMD_MAX_NODES];
2185254Sgavinm
2195254Sgavinm static int
authamd_chip_once(authamd_data_t * authamd,enum authamd_cfgonce_bitnum what)2205254Sgavinm authamd_chip_once(authamd_data_t *authamd, enum authamd_cfgonce_bitnum what)
2215254Sgavinm {
22211947Ssrihari.venkatesan@oracle.com return (atomic_set_long_excl(&authamd->amd_shared->ans_cfgonce,
2235254Sgavinm what) == 0 ? B_TRUE : B_FALSE);
2245254Sgavinm }
2255254Sgavinm
2265254Sgavinm static void
authamd_pcicfg_write(uint_t procnodeid,uint_t func,uint_t reg,uint32_t val)22710947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(uint_t procnodeid, uint_t func, uint_t reg, uint32_t val)
2285254Sgavinm {
22910947SSrihari.Venkatesan@Sun.COM ASSERT(procnodeid + 24 <= 31);
2305254Sgavinm ASSERT((func & 7) == func);
23111947Ssrihari.venkatesan@oracle.com ASSERT((reg & 3) == 0 && reg < 4096);
2325254Sgavinm
23310947SSrihari.Venkatesan@Sun.COM cmi_pci_putl(0, procnodeid + 24, func, reg, 0, val);
2345254Sgavinm }
2355254Sgavinm
2365254Sgavinm static uint32_t
authamd_pcicfg_read(uint_t procnodeid,uint_t func,uint_t reg)23710947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_read(uint_t procnodeid, uint_t func, uint_t reg)
2385254Sgavinm {
23910947SSrihari.Venkatesan@Sun.COM ASSERT(procnodeid + 24 <= 31);
2405254Sgavinm ASSERT((func & 7) == func);
24111947Ssrihari.venkatesan@oracle.com ASSERT((reg & 3) == 0 && reg < 4096);
2425254Sgavinm
24310947SSrihari.Venkatesan@Sun.COM return (cmi_pci_getl(0, procnodeid + 24, func, reg, 0, 0));
2445254Sgavinm }
2455254Sgavinm
2465254Sgavinm void
authamd_bankstatus_prewrite(cmi_hdl_t hdl,authamd_data_t * authamd)2475254Sgavinm authamd_bankstatus_prewrite(cmi_hdl_t hdl, authamd_data_t *authamd)
2485254Sgavinm {
2495254Sgavinm uint64_t hwcr;
2505254Sgavinm
2515254Sgavinm if (cmi_hdl_rdmsr(hdl, MSR_AMD_HWCR, &hwcr) != CMI_SUCCESS)
2525254Sgavinm return;
2535254Sgavinm
2545254Sgavinm authamd->amd_hwcr = hwcr;
2555254Sgavinm
2565254Sgavinm if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
2575254Sgavinm hwcr |= AMD_HWCR_MCI_STATUS_WREN;
2585254Sgavinm (void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
2595254Sgavinm }
2605254Sgavinm }
2615254Sgavinm
2625254Sgavinm void
authamd_bankstatus_postwrite(cmi_hdl_t hdl,authamd_data_t * authamd)2635254Sgavinm authamd_bankstatus_postwrite(cmi_hdl_t hdl, authamd_data_t *authamd)
2645254Sgavinm {
2655254Sgavinm uint64_t hwcr = authamd->amd_hwcr;
2665254Sgavinm
2675254Sgavinm if (!(hwcr & AMD_HWCR_MCI_STATUS_WREN)) {
2685254Sgavinm hwcr &= ~AMD_HWCR_MCI_STATUS_WREN;
2695254Sgavinm (void) cmi_hdl_wrmsr(hdl, MSR_AMD_HWCR, hwcr);
2705254Sgavinm }
2715254Sgavinm }
2725254Sgavinm
2735254Sgavinm /*
2745254Sgavinm * Read EccCnt repeatedly for all possible channel/chip-select combos:
2755254Sgavinm *
2765254Sgavinm * - read sparectl register
2775254Sgavinm * - if EccErrCntWrEn is set, clear that bit in the just-read value
2785254Sgavinm * and write it back to sparectl; this *may* clobber the EccCnt
2795254Sgavinm * for the channel/chip-select combination currently selected, so
2805254Sgavinm * we leave this bit clear if we had to clear it
2815254Sgavinm * - cycle through all channel/chip-select combinations writing each
2825254Sgavinm * combination to sparectl before reading the register back for
2835254Sgavinm * EccCnt for that combination; since EccErrCntWrEn is clear
2845254Sgavinm * the writes to select what count to read will not themselves
2855254Sgavinm * zero any counts
2865254Sgavinm */
2875254Sgavinm static int
authamd_read_ecccnt(authamd_data_t * authamd,struct authamd_logout * msl)2885254Sgavinm authamd_read_ecccnt(authamd_data_t *authamd, struct authamd_logout *msl)
2895254Sgavinm {
2905254Sgavinm union mcreg_sparectl sparectl;
29111947Ssrihari.venkatesan@oracle.com uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
29211947Ssrihari.venkatesan@oracle.com uint_t family = authamd->amd_shared->ans_family;
29311947Ssrihari.venkatesan@oracle.com uint32_t rev = authamd->amd_shared->ans_rev;
2945254Sgavinm int chan, cs;
2955254Sgavinm
2965254Sgavinm /*
2975254Sgavinm * Check for feature support; this macro will test down to the
2985254Sgavinm * family revision number, whereafter we'll switch on family
2995254Sgavinm * assuming that future revisions will use the same register
3005254Sgavinm * format.
3015254Sgavinm */
3025254Sgavinm if (!AUTHAMD_HAS_ONLINESPARECTL(rev)) {
3035254Sgavinm bzero(&msl->aal_eccerrcnt, sizeof (msl->aal_eccerrcnt));
3045254Sgavinm return (0);
3055254Sgavinm }
3065254Sgavinm
3075254Sgavinm MCREG_VAL32(&sparectl) =
30810947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
30910947SSrihari.Venkatesan@Sun.COM MC_CTL_REG_SPARECTL);
3105254Sgavinm
3115254Sgavinm switch (family) {
3125254Sgavinm case AUTHAMD_FAMILY_F:
3135254Sgavinm MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 0;
3145254Sgavinm break;
3155254Sgavinm
3165254Sgavinm case AUTHAMD_FAMILY_10:
3175254Sgavinm MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 0;
3185254Sgavinm break;
3195254Sgavinm }
3205254Sgavinm
3215254Sgavinm for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
3225254Sgavinm switch (family) {
3235254Sgavinm case AUTHAMD_FAMILY_F:
3245254Sgavinm MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
3255254Sgavinm chan;
3265254Sgavinm break;
3275254Sgavinm
3285254Sgavinm case AUTHAMD_FAMILY_10:
3295254Sgavinm MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
3305254Sgavinm chan;
3315254Sgavinm break;
3325254Sgavinm }
3335254Sgavinm
3345254Sgavinm for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
3355254Sgavinm switch (family) {
3365254Sgavinm case AUTHAMD_FAMILY_F:
3375254Sgavinm MCREG_FIELD_F_revFG(&sparectl,
3385254Sgavinm EccErrCntDramCs) = cs;
3395254Sgavinm break;
3405254Sgavinm
3415254Sgavinm case AUTHAMD_FAMILY_10:
3425254Sgavinm MCREG_FIELD_10_revAB(&sparectl,
3435254Sgavinm EccErrCntDramCs) = cs;
3445254Sgavinm break;
3455254Sgavinm }
3465254Sgavinm
34710947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
3485254Sgavinm MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
3495254Sgavinm
35010947SSrihari.Venkatesan@Sun.COM MCREG_VAL32(&sparectl) = authamd_pcicfg_read(procnodeid,
3515254Sgavinm MC_FUNC_MISCCTL, MC_CTL_REG_SPARECTL);
3525254Sgavinm
3535254Sgavinm switch (family) {
3545254Sgavinm case AUTHAMD_FAMILY_F:
3555254Sgavinm msl->aal_eccerrcnt[chan][cs] =
3565254Sgavinm MCREG_FIELD_F_revFG(&sparectl, EccErrCnt);
3575254Sgavinm break;
3585254Sgavinm case AUTHAMD_FAMILY_10:
3595254Sgavinm msl->aal_eccerrcnt[chan][cs] =
3605254Sgavinm MCREG_FIELD_10_revAB(&sparectl, EccErrCnt);
3615254Sgavinm break;
3625254Sgavinm }
3635254Sgavinm }
3645254Sgavinm }
3655254Sgavinm
3665254Sgavinm return (1);
3675254Sgavinm }
3685254Sgavinm
3695254Sgavinm /*
3705254Sgavinm * Clear EccCnt for all possible channel/chip-select combos:
3715254Sgavinm *
3725254Sgavinm * - set EccErrCntWrEn in sparectl, if necessary
3735254Sgavinm * - write 0 to EccCnt for all channel/chip-select combinations
3745254Sgavinm * - clear EccErrCntWrEn
3755254Sgavinm *
3765254Sgavinm * If requested also disable the interrupts taken on counter overflow
3775254Sgavinm * and on swap done.
3785254Sgavinm */
3795254Sgavinm static void
authamd_clear_ecccnt(authamd_data_t * authamd,boolean_t clrint)3805254Sgavinm authamd_clear_ecccnt(authamd_data_t *authamd, boolean_t clrint)
3815254Sgavinm {
3825254Sgavinm union mcreg_sparectl sparectl;
38311947Ssrihari.venkatesan@oracle.com uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
38411947Ssrihari.venkatesan@oracle.com uint_t family = authamd->amd_shared->ans_family;
38511947Ssrihari.venkatesan@oracle.com uint32_t rev = authamd->amd_shared->ans_rev;
3865254Sgavinm int chan, cs;
3875254Sgavinm
3885254Sgavinm if (!AUTHAMD_HAS_ONLINESPARECTL(rev))
3895254Sgavinm return;
3905254Sgavinm
3915254Sgavinm MCREG_VAL32(&sparectl) =
39210947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
39310947SSrihari.Venkatesan@Sun.COM MC_CTL_REG_SPARECTL);
3945254Sgavinm
3955254Sgavinm switch (family) {
3965254Sgavinm case AUTHAMD_FAMILY_F:
3975254Sgavinm MCREG_FIELD_F_revFG(&sparectl, EccErrCntWrEn) = 1;
3985254Sgavinm if (clrint) {
3995254Sgavinm MCREG_FIELD_F_revFG(&sparectl, EccErrInt) = 0;
4005254Sgavinm MCREG_FIELD_F_revFG(&sparectl, SwapDoneInt) = 0;
4015254Sgavinm }
4025254Sgavinm break;
4035254Sgavinm
4045254Sgavinm case AUTHAMD_FAMILY_10:
4055254Sgavinm MCREG_FIELD_10_revAB(&sparectl, EccErrCntWrEn) = 1;
4065254Sgavinm if (clrint) {
4075254Sgavinm MCREG_FIELD_10_revAB(&sparectl, EccErrInt) = 0;
4085254Sgavinm MCREG_FIELD_10_revAB(&sparectl, SwapDoneInt) = 0;
4095254Sgavinm }
4105254Sgavinm break;
4115254Sgavinm }
4125254Sgavinm
41310947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
4145254Sgavinm MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
4155254Sgavinm
4165254Sgavinm for (chan = 0; chan < AUTHAMD_DRAM_NCHANNEL; chan++) {
4175254Sgavinm switch (family) {
4185254Sgavinm case AUTHAMD_FAMILY_F:
4195254Sgavinm MCREG_FIELD_F_revFG(&sparectl, EccErrCntDramChan) =
4205254Sgavinm chan;
4215254Sgavinm break;
4225254Sgavinm
4235254Sgavinm case AUTHAMD_FAMILY_10:
4245254Sgavinm MCREG_FIELD_10_revAB(&sparectl, EccErrCntDramChan) =
4255254Sgavinm chan;
4265254Sgavinm break;
4275254Sgavinm }
4285254Sgavinm
4295254Sgavinm for (cs = 0; cs < AUTHAMD_DRAM_NCS; cs++) {
4305254Sgavinm switch (family) {
4315254Sgavinm case AUTHAMD_FAMILY_F:
4325254Sgavinm MCREG_FIELD_F_revFG(&sparectl,
4335254Sgavinm EccErrCntDramCs) = cs;
4345254Sgavinm MCREG_FIELD_F_revFG(&sparectl,
4355254Sgavinm EccErrCnt) = 0;
4365254Sgavinm break;
4375254Sgavinm
4385254Sgavinm case AUTHAMD_FAMILY_10:
4395254Sgavinm MCREG_FIELD_10_revAB(&sparectl,
4405254Sgavinm EccErrCntDramCs) = cs;
4415254Sgavinm MCREG_FIELD_10_revAB(&sparectl,
4425254Sgavinm EccErrCnt) = 0;
4435254Sgavinm break;
4445254Sgavinm }
4455254Sgavinm
44610947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
4475254Sgavinm MC_CTL_REG_SPARECTL, MCREG_VAL32(&sparectl));
4485254Sgavinm }
4495254Sgavinm }
4505254Sgavinm }
4515254Sgavinm
45210026SKuriakose.Kuruvilla@Sun.COM
45310026SKuriakose.Kuruvilla@Sun.COM /*
45410026SKuriakose.Kuruvilla@Sun.COM * Return
45510026SKuriakose.Kuruvilla@Sun.COM * 1: supported
45610026SKuriakose.Kuruvilla@Sun.COM * 0: unsupported
45710026SKuriakose.Kuruvilla@Sun.COM */
45810026SKuriakose.Kuruvilla@Sun.COM static int
authamd_supported(cmi_hdl_t hdl)45910947SSrihari.Venkatesan@Sun.COM authamd_supported(cmi_hdl_t hdl)
46010026SKuriakose.Kuruvilla@Sun.COM {
46110947SSrihari.Venkatesan@Sun.COM uint_t family = cmi_hdl_family(hdl);
46210026SKuriakose.Kuruvilla@Sun.COM
46310947SSrihari.Venkatesan@Sun.COM switch (family) {
46410947SSrihari.Venkatesan@Sun.COM case AUTHAMD_FAMILY_6:
46510947SSrihari.Venkatesan@Sun.COM case AUTHAMD_FAMILY_F:
46610947SSrihari.Venkatesan@Sun.COM case AUTHAMD_FAMILY_10:
46710947SSrihari.Venkatesan@Sun.COM return (1);
46810947SSrihari.Venkatesan@Sun.COM default:
46910947SSrihari.Venkatesan@Sun.COM return (0);
47010026SKuriakose.Kuruvilla@Sun.COM }
47110026SKuriakose.Kuruvilla@Sun.COM }
47210026SKuriakose.Kuruvilla@Sun.COM
4735254Sgavinm /*
4745254Sgavinm * cms_init entry point.
4755254Sgavinm *
4765254Sgavinm * This module provides broad model-specific support for AMD families
4775254Sgavinm * 0x6, 0xf and 0x10. Future families will have to be evaluated once their
4785254Sgavinm * documentation is available.
4795254Sgavinm */
4805254Sgavinm int
authamd_init(cmi_hdl_t hdl,void ** datap)4815254Sgavinm authamd_init(cmi_hdl_t hdl, void **datap)
4825254Sgavinm {
4835254Sgavinm uint_t chipid = cmi_hdl_chipid(hdl);
48410947SSrihari.Venkatesan@Sun.COM uint_t procnodeid = cmi_hdl_procnodeid(hdl);
48510947SSrihari.Venkatesan@Sun.COM struct authamd_nodeshared *sp, *osp;
4865254Sgavinm uint_t family = cmi_hdl_family(hdl);
48710026SKuriakose.Kuruvilla@Sun.COM uint32_t rev = cmi_hdl_chiprev(hdl);
4885254Sgavinm authamd_data_t *authamd;
4895254Sgavinm uint64_t cap;
4905254Sgavinm
49110026SKuriakose.Kuruvilla@Sun.COM if (authamd_ms_support_disable ||
49210947SSrihari.Venkatesan@Sun.COM !authamd_supported(hdl))
4935254Sgavinm return (ENOTSUP);
4945254Sgavinm
495*12826Skuriakose.kuruvilla@oracle.com if (!is_x86_feature(x86_featureset, X86FSET_MCA))
4965254Sgavinm return (ENOTSUP);
4975254Sgavinm
4985254Sgavinm if (cmi_hdl_rdmsr(hdl, IA32_MSR_MCG_CAP, &cap) != CMI_SUCCESS)
4995254Sgavinm return (ENOTSUP);
5005254Sgavinm
5015254Sgavinm if (!(cap & MCG_CAP_CTL_P))
5025254Sgavinm return (ENOTSUP);
5035254Sgavinm
5045254Sgavinm authamd = *datap = kmem_zalloc(sizeof (authamd_data_t), KM_SLEEP);
5055254Sgavinm cmi_hdl_hold(hdl); /* release in fini */
5065254Sgavinm authamd->amd_hdl = hdl;
5075254Sgavinm
50810947SSrihari.Venkatesan@Sun.COM if ((sp = authamd_shared[procnodeid]) == NULL) {
50910947SSrihari.Venkatesan@Sun.COM sp = kmem_zalloc(sizeof (struct authamd_nodeshared), KM_SLEEP);
51011947Ssrihari.venkatesan@oracle.com sp->ans_chipid = chipid;
51111947Ssrihari.venkatesan@oracle.com sp->ans_procnodeid = procnodeid;
51211947Ssrihari.venkatesan@oracle.com sp->ans_family = family;
51311947Ssrihari.venkatesan@oracle.com sp->ans_rev = rev;
5146000Sgavinm membar_producer();
5156000Sgavinm
51610947SSrihari.Venkatesan@Sun.COM osp = atomic_cas_ptr(&authamd_shared[procnodeid], NULL, sp);
5175254Sgavinm if (osp != NULL) {
51810947SSrihari.Venkatesan@Sun.COM kmem_free(sp, sizeof (struct authamd_nodeshared));
5195254Sgavinm sp = osp;
5205254Sgavinm }
5215254Sgavinm }
5225254Sgavinm authamd->amd_shared = sp;
5235254Sgavinm
5245254Sgavinm return (0);
5255254Sgavinm }
5265254Sgavinm
5275254Sgavinm /*
5285254Sgavinm * cms_logout_size entry point.
5295254Sgavinm */
5305254Sgavinm /*ARGSUSED*/
5315254Sgavinm size_t
authamd_logout_size(cmi_hdl_t hdl)5325254Sgavinm authamd_logout_size(cmi_hdl_t hdl)
5335254Sgavinm {
5345254Sgavinm return (sizeof (struct authamd_logout));
5355254Sgavinm }
5365254Sgavinm
5375254Sgavinm /*
5385254Sgavinm * cms_mcgctl_val entry point
5395254Sgavinm *
5405254Sgavinm * Instead of setting all bits to 1 we can set just those for the
5415254Sgavinm * error detector banks known to exist.
5425254Sgavinm */
5435254Sgavinm /*ARGSUSED*/
5445254Sgavinm uint64_t
authamd_mcgctl_val(cmi_hdl_t hdl,int nbanks,uint64_t proposed)5455254Sgavinm authamd_mcgctl_val(cmi_hdl_t hdl, int nbanks, uint64_t proposed)
5465254Sgavinm {
5475254Sgavinm return (nbanks < 64 ? (1ULL << nbanks) - 1 : proposed);
5485254Sgavinm }
5495254Sgavinm
5505254Sgavinm /*
5515254Sgavinm * cms_bankctl_skipinit entry point
5525254Sgavinm *
5535254Sgavinm * On K6 we do not initialize MC0_CTL since, reportedly, this bank (for DC)
5545254Sgavinm * may produce spurious machine checks.
5555639Sgavinm *
5565639Sgavinm * Only allow a single core to setup the NorthBridge MCi_CTL register.
5575254Sgavinm */
5585254Sgavinm /*ARGSUSED*/
5595254Sgavinm boolean_t
authamd_bankctl_skipinit(cmi_hdl_t hdl,int bank)5605254Sgavinm authamd_bankctl_skipinit(cmi_hdl_t hdl, int bank)
5615254Sgavinm {
5625254Sgavinm authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
56311947Ssrihari.venkatesan@oracle.com uint32_t rev = authamd->amd_shared->ans_rev;
5645254Sgavinm
56511947Ssrihari.venkatesan@oracle.com if (authamd->amd_shared->ans_family == AUTHAMD_FAMILY_6)
5665639Sgavinm return (bank == 0 ? B_TRUE : B_FALSE);
5675639Sgavinm
5685639Sgavinm if (AUTHAMD_NBONCHIP(rev) && bank == AMD_MCA_BANK_NB) {
5695639Sgavinm return (authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCA) ==
5705639Sgavinm B_TRUE ? B_FALSE : B_TRUE);
5715639Sgavinm }
5725639Sgavinm
5735639Sgavinm return (B_FALSE);
5745254Sgavinm }
5755254Sgavinm
5765254Sgavinm /*
5775254Sgavinm * cms_bankctl_val entry point
5785254Sgavinm */
5795254Sgavinm uint64_t
authamd_bankctl_val(cmi_hdl_t hdl,int bank,uint64_t proposed)5805254Sgavinm authamd_bankctl_val(cmi_hdl_t hdl, int bank, uint64_t proposed)
5815254Sgavinm {
5825254Sgavinm authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
58311947Ssrihari.venkatesan@oracle.com uint32_t rev = authamd->amd_shared->ans_rev;
5845254Sgavinm uint64_t val = proposed;
5855254Sgavinm
5865254Sgavinm /*
5875254Sgavinm * The Intel MCA says we can write all 1's to enable #MC for
5885254Sgavinm * all errors, and AMD docs say much the same. But, depending
5895254Sgavinm * perhaps on other config registers, taking machine checks
5905254Sgavinm * for some errors such as GART TLB errors and master/target
5915254Sgavinm * aborts may be bad - they set UC and sometime also PCC, but
5925254Sgavinm * we should not always panic for these error types.
5935254Sgavinm *
5945254Sgavinm * Our cms_error_action entry point can suppress such panics,
5955254Sgavinm * however we can also use the cms_bankctl_val entry point to
5965254Sgavinm * veto enabling of some of the known villains in the first place.
5975254Sgavinm */
5985254Sgavinm if (bank == AMD_MCA_BANK_NB && AUTHAMD_NOGARTTBLWLK_MC(rev))
5995254Sgavinm val &= ~AMD_NB_EN_GARTTBLWK;
6005254Sgavinm
6015254Sgavinm return (val);
6025254Sgavinm }
6035254Sgavinm
6045254Sgavinm /*
6055327Sgavinm * Bits to add to NB MCA config (after watchdog config).
6065327Sgavinm */
6075327Sgavinm uint32_t authamd_nb_mcacfg_add = AMD_NB_CFG_ADD_CMN;
6085327Sgavinm
6095327Sgavinm /*
6105327Sgavinm * Bits to remove from NB MCA config (after watchdog config)
6115327Sgavinm */
6125327Sgavinm uint32_t authamd_nb_mcacfg_remove = AMD_NB_CFG_REMOVE_CMN;
6135327Sgavinm
6145327Sgavinm /*
6155327Sgavinm * NB Watchdog policy, and rate we use if enabling.
6165327Sgavinm */
6175327Sgavinm enum {
6185327Sgavinm AUTHAMD_NB_WDOG_LEAVEALONE,
6195327Sgavinm AUTHAMD_NB_WDOG_DISABLE,
6205327Sgavinm AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED,
6215327Sgavinm AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE
6225327Sgavinm } authamd_nb_watchdog_policy = AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED;
6235327Sgavinm
6245327Sgavinm uint32_t authamd_nb_mcacfg_wdog = AMD_NB_CFG_WDOGTMRCNTSEL_4095 |
6255327Sgavinm AMD_NB_CFG_WDOGTMRBASESEL_1MS;
6265327Sgavinm
6275327Sgavinm /*
6285327Sgavinm * Per-core cache scrubbing policy and rates.
6295327Sgavinm */
6305327Sgavinm enum {
6315327Sgavinm AUTHAMD_SCRUB_BIOSDEFAULT, /* leave as BIOS configured */
6325327Sgavinm AUTHAMD_SCRUB_FIXED, /* assign our chosen rate */
6335327Sgavinm AUTHAMD_SCRUB_MAX /* use higher of ours and BIOS rate */
6345327Sgavinm } authamd_scrub_policy = AUTHAMD_SCRUB_MAX;
6355327Sgavinm
6365327Sgavinm uint32_t authamd_scrub_rate_dcache = 0xf; /* 64K per 0.67 seconds */
6375327Sgavinm uint32_t authamd_scrub_rate_l2cache = 0xe; /* 1MB per 5.3 seconds */
6385327Sgavinm uint32_t authamd_scrub_rate_l3cache = 0xd; /* 1MB per 2.7 seconds */
6395327Sgavinm
6405327Sgavinm static uint32_t
authamd_scrubrate(uint32_t osrate,uint32_t biosrate,const char * varnm)6415327Sgavinm authamd_scrubrate(uint32_t osrate, uint32_t biosrate, const char *varnm)
6425327Sgavinm {
6435327Sgavinm uint32_t rate;
6445327Sgavinm
6455327Sgavinm if (osrate > AMD_NB_SCRUBCTL_RATE_MAX) {
6465327Sgavinm cmn_err(CE_WARN, "%s is too large, resetting to 0x%x\n",
6475327Sgavinm varnm, AMD_NB_SCRUBCTL_RATE_MAX);
6485327Sgavinm osrate = AMD_NB_SCRUBCTL_RATE_MAX;
6495327Sgavinm }
6505327Sgavinm
6515327Sgavinm switch (authamd_scrub_policy) {
6525327Sgavinm case AUTHAMD_SCRUB_FIXED:
6535327Sgavinm rate = osrate;
6545327Sgavinm break;
6555327Sgavinm
6565327Sgavinm default:
6575327Sgavinm cmn_err(CE_WARN, "Unknown authamd_scrub_policy %d - "
6585327Sgavinm "using default policy of AUTHAMD_SCRUB_MAX",
6595327Sgavinm authamd_scrub_policy);
6605327Sgavinm /*FALLTHRU*/
6615327Sgavinm
6625327Sgavinm case AUTHAMD_SCRUB_MAX:
6635327Sgavinm if (osrate != 0 && biosrate != 0)
6645327Sgavinm rate = MIN(osrate, biosrate); /* small is fast */
6655327Sgavinm else
6665327Sgavinm rate = osrate ? osrate : biosrate;
6675327Sgavinm }
6685327Sgavinm
6695327Sgavinm return (rate);
6705327Sgavinm }
6715327Sgavinm
6725327Sgavinm /*
6735254Sgavinm * cms_mca_init entry point.
6745254Sgavinm */
6755254Sgavinm /*ARGSUSED*/
6765254Sgavinm void
authamd_mca_init(cmi_hdl_t hdl,int nbanks)6775254Sgavinm authamd_mca_init(cmi_hdl_t hdl, int nbanks)
6785254Sgavinm {
6795254Sgavinm authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
68011947Ssrihari.venkatesan@oracle.com uint32_t rev = authamd->amd_shared->ans_rev;
68111947Ssrihari.venkatesan@oracle.com uint_t procnodeid = authamd->amd_shared->ans_procnodeid;
6825254Sgavinm
6835254Sgavinm /*
6845254Sgavinm * On chips with a NB online spare control register take control
6855254Sgavinm * and clear ECC counts.
6865254Sgavinm */
6875254Sgavinm if (AUTHAMD_HAS_ONLINESPARECTL(rev) &&
6885254Sgavinm authamd_chip_once(authamd, AUTHAMD_CFGONCE_ONLNSPRCFG)) {
6895254Sgavinm authamd_clear_ecccnt(authamd, B_TRUE);
6905254Sgavinm }
6915254Sgavinm
6925254Sgavinm /*
6935254Sgavinm * And since we are claiming the telemetry stop the BIOS receiving
6945254Sgavinm * an SMI on NB threshold overflow.
6955254Sgavinm */
6965254Sgavinm if (AUTHAMD_NBMISC_NUM(rev) &&
6975254Sgavinm authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBTHRESH)) {
6985254Sgavinm union mcmsr_nbmisc nbm;
6995254Sgavinm int i;
7005254Sgavinm
7015254Sgavinm authamd_bankstatus_prewrite(hdl, authamd);
7025254Sgavinm
7035254Sgavinm for (i = 0; i < AUTHAMD_NBMISC_NUM(rev); i++) {
7045254Sgavinm if (cmi_hdl_rdmsr(hdl, MC_MSR_NB_MISC(i),
7055254Sgavinm (uint64_t *)&nbm) != CMI_SUCCESS)
7065254Sgavinm continue;
7075254Sgavinm
7085254Sgavinm if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) &&
7095254Sgavinm MCMSR_FIELD_F_revFG(&nbm, mcmisc_Valid) &&
7105254Sgavinm MCMSR_FIELD_F_revFG(&nbm, mcmisc_CntP)) {
7115254Sgavinm MCMSR_FIELD_F_revFG(&nbm, mcmisc_IntType) = 0;
7125254Sgavinm } else if (X86_CHIPREV_ATLEAST(rev,
7135254Sgavinm X86_CHIPREV_AMD_10_REV_A) &&
7145254Sgavinm MCMSR_FIELD_10_revAB(&nbm, mcmisc_Valid) &&
7155254Sgavinm MCMSR_FIELD_10_revAB(&nbm, mcmisc_CntP)) {
7165254Sgavinm MCMSR_FIELD_10_revAB(&nbm, mcmisc_IntType) = 0;
7175254Sgavinm }
7185254Sgavinm
7195254Sgavinm (void) cmi_hdl_wrmsr(hdl, MC_MSR_NB_MISC(i),
7205254Sgavinm MCMSR_VAL(&nbm));
7215254Sgavinm }
7225254Sgavinm
7235254Sgavinm authamd_bankstatus_postwrite(hdl, authamd);
7245254Sgavinm }
7255327Sgavinm
7265327Sgavinm /*
7275327Sgavinm * NB MCA Configuration Register.
7285327Sgavinm */
7295327Sgavinm if (AUTHAMD_DO_NBMCACFG(rev) &&
7305327Sgavinm authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCACFG)) {
73110947SSrihari.Venkatesan@Sun.COM uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
7325327Sgavinm MC_CTL_REG_NBCFG);
7335327Sgavinm
7345327Sgavinm switch (authamd_nb_watchdog_policy) {
7355327Sgavinm case AUTHAMD_NB_WDOG_LEAVEALONE:
7365327Sgavinm break;
7375327Sgavinm
7385327Sgavinm case AUTHAMD_NB_WDOG_DISABLE:
7395327Sgavinm val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK |
7405327Sgavinm AMD_NB_CFG_WDOGTMRCNTSEL_MASK);
7415327Sgavinm val |= AMD_NB_CFG_WDOGTMRDIS;
7425327Sgavinm break;
7435327Sgavinm
7445327Sgavinm default:
7455327Sgavinm cmn_err(CE_NOTE, "authamd_nb_watchdog_policy=%d "
7465327Sgavinm "unrecognised, using default policy",
7475327Sgavinm authamd_nb_watchdog_policy);
7485327Sgavinm /*FALLTHRU*/
7495327Sgavinm
7505327Sgavinm case AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED:
7515327Sgavinm if (!(val & AMD_NB_CFG_WDOGTMRDIS))
7525327Sgavinm break; /* if enabled leave rate intact */
7535327Sgavinm /*FALLTHRU*/
7545327Sgavinm
7555327Sgavinm case AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE:
7565327Sgavinm val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK |
7575327Sgavinm AMD_NB_CFG_WDOGTMRCNTSEL_MASK |
7585327Sgavinm AMD_NB_CFG_WDOGTMRDIS);
7595327Sgavinm val |= authamd_nb_mcacfg_wdog;
7605327Sgavinm break;
7615327Sgavinm }
7625327Sgavinm
7635327Sgavinm /*
7645327Sgavinm * Bit 0 of the NB MCA Config register is reserved on family
7655327Sgavinm * 0x10.
7665327Sgavinm */
7675327Sgavinm if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
7685327Sgavinm authamd_nb_mcacfg_add &= ~AMD_NB_CFG_CPUECCERREN;
7695327Sgavinm
7705327Sgavinm val &= ~authamd_nb_mcacfg_remove;
7715327Sgavinm val |= authamd_nb_mcacfg_add;
7725327Sgavinm
77310947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
77410947SSrihari.Venkatesan@Sun.COM MC_CTL_REG_NBCFG, val);
7755327Sgavinm }
7765327Sgavinm
7775327Sgavinm /*
7785327Sgavinm * Cache scrubbing. We can't enable DRAM scrubbing since
7795327Sgavinm * we don't know the DRAM base for this node.
7805327Sgavinm */
7815327Sgavinm if (AUTHAMD_HAS_CHIPSCRUB(rev) &&
7825327Sgavinm authamd_scrub_policy != AUTHAMD_SCRUB_BIOSDEFAULT &&
7835327Sgavinm authamd_chip_once(authamd, AUTHAMD_CFGONCE_CACHESCRUB)) {
78410947SSrihari.Venkatesan@Sun.COM uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
7855327Sgavinm MC_CTL_REG_SCRUBCTL);
7865327Sgavinm int l3cap = 0;
7875327Sgavinm
7885327Sgavinm if (AUTHAMD_L3CAPABLE(rev)) {
78910947SSrihari.Venkatesan@Sun.COM l3cap = (authamd_pcicfg_read(procnodeid,
79010947SSrihari.Venkatesan@Sun.COM MC_FUNC_MISCCTL, MC_CTL_REG_NBCAP) &
79110947SSrihari.Venkatesan@Sun.COM MC_NBCAP_L3CAPABLE) != 0;
7925327Sgavinm }
7935327Sgavinm
7945327Sgavinm authamd_scrub_rate_dcache =
7955327Sgavinm authamd_scrubrate(authamd_scrub_rate_dcache,
7965327Sgavinm (val & AMD_NB_SCRUBCTL_DC_MASK) >> AMD_NB_SCRUBCTL_DC_SHIFT,
7975327Sgavinm "authamd_scrub_rate_dcache");
7985327Sgavinm
7995327Sgavinm authamd_scrub_rate_l2cache =
8005327Sgavinm authamd_scrubrate(authamd_scrub_rate_l2cache,
8015327Sgavinm (val & AMD_NB_SCRUBCTL_L2_MASK) >> AMD_NB_SCRUBCTL_L2_SHIFT,
8025327Sgavinm "authamd_scrub_rate_l2cache");
8035327Sgavinm
8045327Sgavinm authamd_scrub_rate_l3cache = l3cap ?
8055327Sgavinm authamd_scrubrate(authamd_scrub_rate_l3cache,
8065327Sgavinm (val & AMD_NB_SCRUBCTL_L3_MASK) >> AMD_NB_SCRUBCTL_L3_SHIFT,
8075327Sgavinm "authamd_scrub_rate_l3cache") : 0;
8085327Sgavinm
8095327Sgavinm val = AMD_NB_MKSCRUBCTL(authamd_scrub_rate_l3cache,
8105327Sgavinm authamd_scrub_rate_dcache, authamd_scrub_rate_l2cache,
8115327Sgavinm val & AMD_NB_SCRUBCTL_DRAM_MASK);
8125327Sgavinm
81310947SSrihari.Venkatesan@Sun.COM authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL,
8145327Sgavinm MC_CTL_REG_SCRUBCTL, val);
8155327Sgavinm }
8165327Sgavinm
81711947Ssrihari.venkatesan@oracle.com /*
81811947Ssrihari.venkatesan@oracle.com * ECC symbol size. Defaults to 4.
81911947Ssrihari.venkatesan@oracle.com * Set to 8 on systems that support x8 ECC and have it enabled.
82011947Ssrihari.venkatesan@oracle.com */
82111947Ssrihari.venkatesan@oracle.com if (authamd_chip_once(authamd, AUTHAMD_CFGONCE_ECCSYMSZ)) {
82211947Ssrihari.venkatesan@oracle.com authamd->amd_shared->ans_eccsymsz = "C4";
82311947Ssrihari.venkatesan@oracle.com if (AUTHAMD_SUPPORTS_X8ECC(rev) &&
82411947Ssrihari.venkatesan@oracle.com (authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL,
82511947Ssrihari.venkatesan@oracle.com MC_CTL_REG_EXTNBCFG) & MC_EXTNBCFG_ECCSYMSZ))
82611947Ssrihari.venkatesan@oracle.com authamd->amd_shared->ans_eccsymsz = "C8";
82711947Ssrihari.venkatesan@oracle.com }
8285327Sgavinm }
8295327Sgavinm
8305327Sgavinm /*
8315327Sgavinm * cms_poll_ownermask entry point.
8325327Sgavinm */
8335327Sgavinm uint64_t
authamd_poll_ownermask(cmi_hdl_t hdl,hrtime_t pintvl)8345327Sgavinm authamd_poll_ownermask(cmi_hdl_t hdl, hrtime_t pintvl)
8355327Sgavinm {
8365327Sgavinm authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
83711947Ssrihari.venkatesan@oracle.com struct authamd_nodeshared *ansp = authamd->amd_shared;
8385327Sgavinm hrtime_t now = gethrtime_waitfree();
83911947Ssrihari.venkatesan@oracle.com hrtime_t last = ansp->ans_poll_timestamp;
8405327Sgavinm int dopoll = 0;
8415327Sgavinm
8425327Sgavinm if (now - last > 2 * pintvl || last == 0) {
84311947Ssrihari.venkatesan@oracle.com ansp->ans_pollowner = hdl;
8445327Sgavinm dopoll = 1;
84511947Ssrihari.venkatesan@oracle.com } else if (ansp->ans_pollowner == hdl) {
8465327Sgavinm dopoll = 1;
8475327Sgavinm }
8485327Sgavinm
8495327Sgavinm if (dopoll)
85011947Ssrihari.venkatesan@oracle.com ansp->ans_poll_timestamp = now;
8515327Sgavinm
8525327Sgavinm return (dopoll ? -1ULL : ~(1 << AMD_MCA_BANK_NB));
8535327Sgavinm
8545254Sgavinm }
8555254Sgavinm
8565254Sgavinm /*
8575254Sgavinm * cms_bank_logout entry point.
8585254Sgavinm */
8595254Sgavinm /*ARGSUSED*/
8605254Sgavinm void
authamd_bank_logout(cmi_hdl_t hdl,int bank,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)8615254Sgavinm authamd_bank_logout(cmi_hdl_t hdl, int bank, uint64_t status,
8625254Sgavinm uint64_t addr, uint64_t misc, void *mslogout)
8635254Sgavinm {
8645254Sgavinm authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
8655254Sgavinm struct authamd_logout *msl = mslogout;
86611947Ssrihari.venkatesan@oracle.com uint32_t rev = authamd->amd_shared->ans_rev;
8675254Sgavinm
8685254Sgavinm if (msl == NULL)
8695254Sgavinm return;
8705254Sgavinm
8715254Sgavinm /*
8725254Sgavinm * For main memory ECC errors on revisions with an Online Spare
8735254Sgavinm * Control Register grab the ECC counts by channel and chip-select
8745254Sgavinm * and reset them to 0.
8755254Sgavinm */
8765254Sgavinm if (AUTHAMD_MEMECC_RECOGNISED(rev) &&
8775254Sgavinm AUTHAMD_IS_MEMECCERR(bank, status) &&
8785254Sgavinm AUTHAMD_HAS_ONLINESPARECTL(rev)) {
8795254Sgavinm if (authamd_read_ecccnt(authamd, msl))
8805254Sgavinm authamd_clear_ecccnt(authamd, B_FALSE);
8815254Sgavinm }
8825254Sgavinm }
8835254Sgavinm
8845254Sgavinm /*
8855254Sgavinm * cms_error_action entry point
8865254Sgavinm */
8875254Sgavinm
8885254Sgavinm int authamd_forgive_uc = 0; /* For test/debug only */
8895254Sgavinm int authamd_forgive_pcc = 0; /* For test/debug only */
8905254Sgavinm int authamd_fake_poison = 0; /* For test/debug only */
8915254Sgavinm
8925254Sgavinm /*ARGSUSED*/
8935254Sgavinm uint32_t
authamd_error_action(cmi_hdl_t hdl,int ismc,int bank,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)8945254Sgavinm authamd_error_action(cmi_hdl_t hdl, int ismc, int bank,
8955254Sgavinm uint64_t status, uint64_t addr, uint64_t misc, void *mslogout)
8965254Sgavinm {
8975254Sgavinm authamd_error_disp_t *disp;
8985254Sgavinm uint32_t rv = 0;
8995254Sgavinm
9005254Sgavinm if (authamd_forgive_uc)
9015254Sgavinm rv |= CMS_ERRSCOPE_CLEARED_UC;
9025254Sgavinm
9035254Sgavinm if (authamd_forgive_pcc)
9045254Sgavinm rv |= CMS_ERRSCOPE_CURCONTEXT_OK;
9055254Sgavinm
9065254Sgavinm if (authamd_fake_poison && status & MSR_MC_STATUS_UC)
9075254Sgavinm rv |= CMS_ERRSCOPE_POISONED;
9085254Sgavinm
9095254Sgavinm if (rv)
9105254Sgavinm return (rv);
9115254Sgavinm
91212437SAdrian.Frost@Sun.COM disp = authamd_disp_match(hdl, ismc, bank, status, addr, misc,
91312437SAdrian.Frost@Sun.COM 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
authamd_disp_match(cmi_hdl_t hdl,int ismc,int bank,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout)93712437SAdrian.Frost@Sun.COM authamd_disp_match(cmi_hdl_t hdl, int ismc, 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);
94311947Ssrihari.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
authamd_ereport_class(cmi_hdl_t hdl,cms_cookie_t mscookie,const char ** cpuclsp,const char ** leafclsp)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
authamd_ereport_add_resource(cmi_hdl_t hdl,authamd_data_t * authamd,nvlist_t * ereport,nv_alloc_t * nva,void * mslogout)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 */
100411947Ssrihari.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,
103211947Ssrihari.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
authamd_ereport_add_logout(cmi_hdl_t hdl,nvlist_t * ereport,nv_alloc_t * nva,int bank,uint64_t status,uint64_t addr,uint64_t misc,void * mslogout,cms_cookie_t mscookie)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,
109411947Ssrihari.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
authamd_msrinject(cmi_hdl_t hdl,uint_t msr,uint64_t val)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
112312437SAdrian.Frost@Sun.COM cms_api_ver_t _cms_api_version = CMS_API_VERSION_2;
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
_init(void)11605254Sgavinm _init(void)
11615254Sgavinm {
11625254Sgavinm return (mod_install(&modlinkage));
11635254Sgavinm }
11645254Sgavinm
11655254Sgavinm int
_info(struct modinfo * modinfop)11665254Sgavinm _info(struct modinfo *modinfop)
11675254Sgavinm {
11685254Sgavinm return (mod_info(&modlinkage, modinfop));
11695254Sgavinm }
11705254Sgavinm
11715254Sgavinm int
_fini(void)11725254Sgavinm _fini(void)
11735254Sgavinm {
11745254Sgavinm return (mod_remove(&modlinkage));
11755254Sgavinm }
1176