Пример #1
0
/*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);
	}
Пример #2
0
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);
}