/*ARGSUSED*/ void authamd_mca_init(cmi_hdl_t hdl, int nbanks) { authamd_data_t *authamd = cms_hdl_getcmsdata(hdl); uint32_t rev = authamd->amd_shared->ans_rev; uint_t procnodeid = authamd->amd_shared->ans_procnodeid; /* * On chips with a NB online spare control register take control * and clear ECC counts. */ if (AUTHAMD_HAS_ONLINESPARECTL(rev) && authamd_chip_once(authamd, AUTHAMD_CFGONCE_ONLNSPRCFG)) { authamd_clear_ecccnt(authamd, B_TRUE); } /* * And since we are claiming the telemetry stop the BIOS receiving * an SMI on NB threshold overflow. */ if (AUTHAMD_NBMISC_NUM(rev) && authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBTHRESH)) { union mcmsr_nbmisc nbm; int i; authamd_bankstatus_prewrite(hdl, authamd); for (i = 0; i < AUTHAMD_NBMISC_NUM(rev); i++) { if (cmi_hdl_rdmsr(hdl, MC_MSR_NB_MISC(i), (uint64_t *)&nbm) != CMI_SUCCESS) continue; if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) && MCMSR_FIELD_F_revFG(&nbm, mcmisc_Valid) && MCMSR_FIELD_F_revFG(&nbm, mcmisc_CntP)) { MCMSR_FIELD_F_revFG(&nbm, mcmisc_IntType) = 0; } else if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A) && MCMSR_FIELD_10_revAB(&nbm, mcmisc_Valid) && MCMSR_FIELD_10_revAB(&nbm, mcmisc_CntP)) { MCMSR_FIELD_10_revAB(&nbm, mcmisc_IntType) = 0; } (void) cmi_hdl_wrmsr(hdl, MC_MSR_NB_MISC(i), MCMSR_VAL(&nbm)); } authamd_bankstatus_postwrite(hdl, authamd); } /* * NB MCA Configuration Register. */ if (AUTHAMD_DO_NBMCACFG(rev) && authamd_chip_once(authamd, AUTHAMD_CFGONCE_NBMCACFG)) { uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL, MC_CTL_REG_NBCFG); switch (authamd_nb_watchdog_policy) { case AUTHAMD_NB_WDOG_LEAVEALONE: break; case AUTHAMD_NB_WDOG_DISABLE: val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK | AMD_NB_CFG_WDOGTMRCNTSEL_MASK); val |= AMD_NB_CFG_WDOGTMRDIS; break; default: cmn_err(CE_NOTE, "authamd_nb_watchdog_policy=%d " "unrecognised, using default policy", authamd_nb_watchdog_policy); /*FALLTHRU*/ case AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED: if (!(val & AMD_NB_CFG_WDOGTMRDIS)) break; /* if enabled leave rate intact */ /*FALLTHRU*/ case AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE: val &= ~(AMD_NB_CFG_WDOGTMRBASESEL_MASK | AMD_NB_CFG_WDOGTMRCNTSEL_MASK | AMD_NB_CFG_WDOGTMRDIS); val |= authamd_nb_mcacfg_wdog; break; } /* * Bit 0 of the NB MCA Config register is reserved on family * 0x10. */ if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A)) authamd_nb_mcacfg_add &= ~AMD_NB_CFG_CPUECCERREN; val &= ~authamd_nb_mcacfg_remove; val |= authamd_nb_mcacfg_add; authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL, MC_CTL_REG_NBCFG, val); } /* * Cache scrubbing. We can't enable DRAM scrubbing since * we don't know the DRAM base for this node. */ if (AUTHAMD_HAS_CHIPSCRUB(rev) && authamd_scrub_policy != AUTHAMD_SCRUB_BIOSDEFAULT && authamd_chip_once(authamd, AUTHAMD_CFGONCE_CACHESCRUB)) { uint32_t val = authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL, MC_CTL_REG_SCRUBCTL); int l3cap = 0; if (AUTHAMD_L3CAPABLE(rev)) { l3cap = (authamd_pcicfg_read(procnodeid, MC_FUNC_MISCCTL, MC_CTL_REG_NBCAP) & MC_NBCAP_L3CAPABLE) != 0; } authamd_scrub_rate_dcache = authamd_scrubrate(authamd_scrub_rate_dcache, (val & AMD_NB_SCRUBCTL_DC_MASK) >> AMD_NB_SCRUBCTL_DC_SHIFT, "authamd_scrub_rate_dcache"); authamd_scrub_rate_l2cache = authamd_scrubrate(authamd_scrub_rate_l2cache, (val & AMD_NB_SCRUBCTL_L2_MASK) >> AMD_NB_SCRUBCTL_L2_SHIFT, "authamd_scrub_rate_l2cache"); authamd_scrub_rate_l3cache = l3cap ? authamd_scrubrate(authamd_scrub_rate_l3cache, (val & AMD_NB_SCRUBCTL_L3_MASK) >> AMD_NB_SCRUBCTL_L3_SHIFT, "authamd_scrub_rate_l3cache") : 0; val = AMD_NB_MKSCRUBCTL(authamd_scrub_rate_l3cache, authamd_scrub_rate_dcache, authamd_scrub_rate_l2cache, val & AMD_NB_SCRUBCTL_DRAM_MASK); authamd_pcicfg_write(procnodeid, MC_FUNC_MISCCTL, MC_CTL_REG_SCRUBCTL, val); }
static int opt_pcbe_init(void) { amd_event_t *evp; amd_generic_event_t *gevp; amd_family = cpuid_getfamily(CPU); /* * Make sure this really _is_ an Opteron or Athlon 64 system. The kernel * loads this module based on its name in the module directory, but it * could have been renamed. */ if (cpuid_getvendor(CPU) != X86_VENDOR_AMD || amd_family < 0xf) return (-1); if (amd_family == 0xf) /* Some tools expect this string for family 0fh */ snprintf(amd_pcbe_impl_name, sizeof (amd_pcbe_impl_name), "AMD Opteron & Athlon64"); else snprintf(amd_pcbe_impl_name, sizeof (amd_pcbe_impl_name), "AMD Family %02xh%s", amd_family, AMD_PCBE_SUPPORTED(amd_family) ? "" :" (unsupported)"); /* * Figure out processor revision here and assign appropriate * event configuration. */ if (amd_family == 0xf) { uint32_t rev; rev = cpuid_getchiprev(CPU); if (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F)) amd_pcbe_cpuref = amd_fam_f_NPT_bkdg; else amd_pcbe_cpuref = amd_fam_f_rev_ae_bkdg; amd_events = family_f_events; amd_generic_events = opt_generic_events; } else if (amd_family == 0x10) { amd_pcbe_cpuref = amd_fam_10h_bkdg; amd_events = family_10h_events; amd_generic_events = family_10h_generic_events; } else if (amd_family == 0x11) { amd_pcbe_cpuref = amd_fam_11h_bkdg; amd_events = family_11h_events; amd_generic_events = opt_generic_events; } else { amd_pcbe_cpuref = amd_generic_bkdg; snprintf(amd_pcbe_cpuref, AMD_CPUREF_SIZE, "See BIOS and Kernel Developer's Guide " \ "(BKDG) For AMD Family %02xh Processors. " \ "(Note that this pcbe does not explicitly " \ "support this family)", amd_family); /* * For families that are not explicitly supported we'll use * events for family 0xf. Even if they are not quite right, * it's OK --- we state that pcbe is unsupported. */ amd_events = family_f_events; amd_generic_events = opt_generic_events; } /* * Construct event list. * * First pass: Calculate size needed. We'll need an additional byte * for the NULL pointer during the last strcat. * * Second pass: Copy strings. */ for (evp = amd_events; evp->name != NULL; evp++) evlist_sz += strlen(evp->name) + 1; for (gevp = amd_generic_events; gevp->name != NULL; gevp++) evlist_sz += strlen(gevp->name) + 1; evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP); evlist[0] = '\0'; for (evp = amd_events; evp->name != NULL; evp++) { (void) strcat(evlist, evp->name); (void) strcat(evlist, ","); } for (gevp = amd_generic_events; gevp->name != NULL; gevp++) { (void) strcat(evlist, gevp->name); (void) strcat(evlist, ","); } /* * Remove trailing comma. */ evlist[evlist_sz - 1] = '\0'; return (0); }