summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c2
-rw-r--r--usr/src/uts/i86pc/cpu/authenticamd/authamd.h6
-rw-r--r--usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c209
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c19
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c8
-rw-r--r--usr/src/uts/intel/sys/mc_amd.h7
-rw-r--r--usr/src/uts/intel/sys/mca_amd.h5
7 files changed, 246 insertions, 10 deletions
diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c
index 09a9e919db..6c3ad8b3f9 100644
--- a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c
+++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c
@@ -433,7 +433,7 @@ ao_nb_cfg(ao_ms_data_t *ao, uint32_t rev)
/*FALLTHRU*/
case AO_NB_WDOG_ENABLE_IF_DISABLED:
- if (val & AMD_NB_CFG_WDOGTMRDIS)
+ if (!(val & AMD_NB_CFG_WDOGTMRDIS))
break; /* if enabled leave rate intact */
/*FALLTHRU*/
diff --git a/usr/src/uts/i86pc/cpu/authenticamd/authamd.h b/usr/src/uts/i86pc/cpu/authenticamd/authamd.h
index 15199981f7..be5b675939 100644
--- a/usr/src/uts/i86pc/cpu/authenticamd/authamd.h
+++ b/usr/src/uts/i86pc/cpu/authenticamd/authamd.h
@@ -73,11 +73,15 @@ struct authamd_chipshared {
uint_t acs_family; /* family number */
uint32_t acs_rev; /* revision per cpuid_getchiprev */
volatile ulong_t acs_cfgonce; /* Config performed once per chip */
+ hrtime_t acs_poll_timestamp; /* Checks poll owner is alive */
+ cmi_hdl_t acs_pollowner; /* poller of shared resources */
};
enum authamd_cfgonce_bitnum {
AUTHAMD_CFGONCE_ONLNSPRCFG,
- AUTHAMD_CFGONCE_NBTHRESH
+ AUTHAMD_CFGONCE_NBTHRESH,
+ AUTHAMD_CFGONCE_NBMCACFG,
+ AUTHAMD_CFGONCE_CACHESCRUB
};
/*
diff --git a/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c b/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c
index ef158a3c86..1109d3a4aa 100644
--- a/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c
+++ b/usr/src/uts/i86pc/cpu/authenticamd/authamd_main.c
@@ -50,6 +50,7 @@
#include <sys/controlregs.h>
#include <sys/pghw.h>
#include <sys/sunddi.h>
+#include <sys/sysmacros.h>
#include <sys/cpu_module_ms_impl.h>
#include "authamd.h"
@@ -99,6 +100,20 @@ int authamd_ms_support_disable = 0;
X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
/*
+ * Families/revisions for which we will perform NB MCA Config changes
+ */
+#define AUTHAMD_DO_NBMCACFG(rev) \
+ (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) || \
+ X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
+
+/*
+ * Families/revisions that have chip cache scrubbers.
+ */
+#define AUTHAMD_HAS_CHIPSCRUB(rev) \
+ (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_F_REV_F) || \
+ X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
+
+/*
* Families/revisions that have a NB misc register or registers -
* evaluates to 0 if no support, otherwise the number of MC4_MISCj.
*/
@@ -115,6 +130,12 @@ int authamd_ms_support_disable = 0;
X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
/*
+ * Families/revisions that are potentially L3 capable
+ */
+#define AUTHAMD_L3CAPABLE(rev) \
+ (X86_CHIPREV_ATLEAST(rev, X86_CHIPREV_AMD_10_REV_A))
+
+/*
* We recognise main memory ECC errors for AUTHAMD_MEMECC_RECOGNISED
* revisions as:
*
@@ -539,6 +560,74 @@ authamd_bankctl_val(cmi_hdl_t hdl, int bank, uint64_t proposed)
}
/*
+ * Bits to add to NB MCA config (after watchdog config).
+ */
+uint32_t authamd_nb_mcacfg_add = AMD_NB_CFG_ADD_CMN;
+
+/*
+ * Bits to remove from NB MCA config (after watchdog config)
+ */
+uint32_t authamd_nb_mcacfg_remove = AMD_NB_CFG_REMOVE_CMN;
+
+/*
+ * NB Watchdog policy, and rate we use if enabling.
+ */
+enum {
+ AUTHAMD_NB_WDOG_LEAVEALONE,
+ AUTHAMD_NB_WDOG_DISABLE,
+ AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED,
+ AUTHAMD_NB_WDOG_ENABLE_FORCE_RATE
+} authamd_nb_watchdog_policy = AUTHAMD_NB_WDOG_ENABLE_IF_DISABLED;
+
+uint32_t authamd_nb_mcacfg_wdog = AMD_NB_CFG_WDOGTMRCNTSEL_4095 |
+ AMD_NB_CFG_WDOGTMRBASESEL_1MS;
+
+/*
+ * Per-core cache scrubbing policy and rates.
+ */
+enum {
+ AUTHAMD_SCRUB_BIOSDEFAULT, /* leave as BIOS configured */
+ AUTHAMD_SCRUB_FIXED, /* assign our chosen rate */
+ AUTHAMD_SCRUB_MAX /* use higher of ours and BIOS rate */
+} authamd_scrub_policy = AUTHAMD_SCRUB_MAX;
+
+uint32_t authamd_scrub_rate_dcache = 0xf; /* 64K per 0.67 seconds */
+uint32_t authamd_scrub_rate_l2cache = 0xe; /* 1MB per 5.3 seconds */
+uint32_t authamd_scrub_rate_l3cache = 0xd; /* 1MB per 2.7 seconds */
+
+static uint32_t
+authamd_scrubrate(uint32_t osrate, uint32_t biosrate, const char *varnm)
+{
+ uint32_t rate;
+
+ if (osrate > AMD_NB_SCRUBCTL_RATE_MAX) {
+ cmn_err(CE_WARN, "%s is too large, resetting to 0x%x\n",
+ varnm, AMD_NB_SCRUBCTL_RATE_MAX);
+ osrate = AMD_NB_SCRUBCTL_RATE_MAX;
+ }
+
+ switch (authamd_scrub_policy) {
+ case AUTHAMD_SCRUB_FIXED:
+ rate = osrate;
+ break;
+
+ default:
+ cmn_err(CE_WARN, "Unknown authamd_scrub_policy %d - "
+ "using default policy of AUTHAMD_SCRUB_MAX",
+ authamd_scrub_policy);
+ /*FALLTHRU*/
+
+ case AUTHAMD_SCRUB_MAX:
+ if (osrate != 0 && biosrate != 0)
+ rate = MIN(osrate, biosrate); /* small is fast */
+ else
+ rate = osrate ? osrate : biosrate;
+ }
+
+ return (rate);
+}
+
+/*
* cms_mca_init entry point.
*/
/*ARGSUSED*/
@@ -547,6 +636,7 @@ authamd_mca_init(cmi_hdl_t hdl, int nbanks)
{
authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
uint32_t rev = authamd->amd_shared->acs_rev;
+ uint_t chipid = authamd->amd_shared->acs_chipid;
/*
* On chips with a NB online spare control register take control
@@ -590,6 +680,123 @@ authamd_mca_init(cmi_hdl_t hdl, int nbanks)
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(chipid, 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(chipid, 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(chipid, MC_FUNC_MISCCTL,
+ MC_CTL_REG_SCRUBCTL);
+ int l3cap = 0;
+
+ if (AUTHAMD_L3CAPABLE(rev)) {
+ l3cap = (authamd_pcicfg_read(chipid, 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(chipid, MC_FUNC_MISCCTL,
+ MC_CTL_REG_SCRUBCTL, val);
+ }
+
+}
+
+/*
+ * cms_poll_ownermask entry point.
+ */
+uint64_t
+authamd_poll_ownermask(cmi_hdl_t hdl, hrtime_t pintvl)
+{
+ authamd_data_t *authamd = cms_hdl_getcmsdata(hdl);
+ struct authamd_chipshared *acsp = authamd->amd_shared;
+ hrtime_t now = gethrtime_waitfree();
+ hrtime_t last = acsp->acs_poll_timestamp;
+ int dopoll = 0;
+
+ if (now - last > 2 * pintvl || last == 0) {
+ acsp->acs_pollowner = hdl;
+ dopoll = 1;
+ } else if (acsp->acs_pollowner == hdl) {
+ dopoll = 1;
+ }
+
+ if (dopoll)
+ acsp->acs_poll_timestamp = now;
+
+ return (dopoll ? -1ULL : ~(1 << AMD_MCA_BANK_NB));
+
}
/*
@@ -853,7 +1060,7 @@ const cms_ops_t _cms_ops = {
NULL, /* cms_bankstatus_skipinit */
NULL, /* cms_bankstatus_val */
authamd_mca_init, /* cms_mca_init */
- NULL, /* cms_poll_ownermask */
+ authamd_poll_ownermask, /* cms_poll_ownermask */
authamd_bank_logout, /* cms_bank_logout */
authamd_error_action, /* cms_error_action */
authamd_disp_match, /* cms_disp_match */
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
index 60f52fb578..2847cdb532 100644
--- a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c
@@ -1118,9 +1118,22 @@ gcpu_mca_init(cmi_hdl_t hdl)
(void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC(i, ADDR),
&bcfgp->bios_bank_addr);
- if (bcfgp->bios_bank_status & MSR_MC_STATUS_MISCV)
- (void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC(i, MISC),
- &bcfgp->bios_bank_misc);
+ /*
+ * In some old BIOS the status value after boot can indicate
+ * MISCV when there is actually no MISC register for
+ * that bank. The following read could therefore
+ * aggravate a general protection fault. This should be
+ * caught by on_trap, but the #GP fault handler is busted
+ * and can suffer a double fault even before we get to
+ * trap() to check for on_trap protection. Until that
+ * issue is fixed we remove the one access that we know
+ * can cause a #GP.
+ *
+ * if (bcfgp->bios_bank_status & MSR_MC_STATUS_MISCV)
+ * (void) cmi_hdl_rdmsr(hdl, IA32_MSR_MC(i, MISC),
+ * &bcfgp->bios_bank_misc);
+ */
+ bcfgp->bios_bank_misc = 0;
if (!(mca->gcpu_actv_banks & 1 << i))
continue;
diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c
index a0bdde9f05..3db31cb000 100644
--- a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c
+++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_poll.c
@@ -201,6 +201,9 @@ gcpu_ntv_mca_poll_wrapper(cmi_hdl_t hdl, int what)
{
gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
+ if (gcpu->gcpu_mca.gcpu_mca_lgsz == 0)
+ return;
+
kpreempt_disable();
mutex_enter(&gcpu->gcpu_shared->gcpus_poll_lock);
gcpu_ntv_mca_poll(hdl, what);
@@ -260,6 +263,8 @@ gcpu_ntv_mca_poll_offline(void *arg, cpu_t *cpu, void *cyh_arg)
* common logging code.
*/
+static int gcpu_mca_poll_inits;
+
void
gcpu_mca_poll_init(cmi_hdl_t hdl)
{
@@ -276,6 +281,7 @@ gcpu_mca_poll_init(cmi_hdl_t hdl)
}
mca->gcpu_mca_polltrace.mptc_tbufs = tbufs;
mca->gcpu_mca_polltrace.mptc_curtrace = 0;
+ gcpu_mca_poll_inits++;
break;
}
@@ -300,7 +306,7 @@ gcpu_ntv_mca_poll_start(void)
#ifndef __xpv
cyc_omni_handler_t cyo;
- if (gcpu_mca_poll_interval == 0)
+ if (gcpu_mca_poll_interval == 0 || gcpu_mca_poll_inits == 0)
return;
cyo.cyo_online = gcpu_ntv_mca_poll_online;
diff --git a/usr/src/uts/intel/sys/mc_amd.h b/usr/src/uts/intel/sys/mc_amd.h
index 79b03d9e70..5b0315a099 100644
--- a/usr/src/uts/intel/sys/mc_amd.h
+++ b/usr/src/uts/intel/sys/mc_amd.h
@@ -191,14 +191,17 @@ enum mc_funcnum {
#define MC_DC_REG_DRAMMISC 0xa0 /* DRAM Miscellaneous */
/*
- * Function 3 (misc control) offset for NB MCA config, scrubber control
- * and online spare control.
+ * Function 3 (misc control) offset for NB MCA config, scrubber control,
+ * online spare control and NB capabilities.
*/
#define MC_CTL_REG_NBCFG 0x44 /* MCA NB configuration register */
#define MC_CTL_REG_SCRUBCTL 0x58 /* Scrub control register */
#define MC_CTL_REG_SCRUBADDR_LO 0x5c /* DRAM Scrub Address Low */
#define MC_CTL_REG_SCRUBADDR_HI 0x60 /* DRAM Scrub Address High */
#define MC_CTL_REG_SPARECTL 0xb0 /* On-line spare control register */
+#define MC_CTL_REG_NBCAP 0xe8 /* NB Capabilities */
+
+#define MC_NBCAP_L3CAPABLE 0x02000000
/*
* MC4_MISC MSR and MC4_MISCj MSRs
diff --git a/usr/src/uts/intel/sys/mca_amd.h b/usr/src/uts/intel/sys/mca_amd.h
index d583b71221..998ff980bf 100644
--- a/usr/src/uts/intel/sys/mca_amd.h
+++ b/usr/src/uts/intel/sys/mca_amd.h
@@ -374,6 +374,8 @@ extern "C" {
#define AMD_NB_SCRUBCTL_L2_SHIFT 8
#define AMD_NB_SCRUBCTL_DC_MASK 0x001f0000
#define AMD_NB_SCRUBCTL_DC_SHIFT 16
+#define AMD_NB_SCRUBCTL_L3_MASK 0x1f000000
+#define AMD_NB_SCRUBCTL_L3_SHIFT 24
#define AMD_NB_SCRUBCTL_RATE_NONE 0
#define AMD_NB_SCRUBCTL_RATE_MAX 0x16
@@ -389,7 +391,8 @@ extern "C" {
#define AMD_NB_SCRUBADDR_MKHI(addr) \
(((addr) >> 32) & AMD_NB_SCRUBADDR_HI_MASK)
-#define AMD_NB_MKSCRUBCTL(dc, l2, dr) ( \
+#define AMD_NB_MKSCRUBCTL(l3, dc, l2, dr) ( \
+ (((l3) << AMD_NB_SCRUBCTL_L3_SHIFT) & AMD_NB_SCRUBCTL_L3_MASK) | \
(((dc) << AMD_NB_SCRUBCTL_DC_SHIFT) & AMD_NB_SCRUBCTL_DC_MASK) | \
(((l2) << AMD_NB_SCRUBCTL_L2_SHIFT) & AMD_NB_SCRUBCTL_L2_MASK) | \
(((dr) << AMD_NB_SCRUBCTL_DRAM_SHIFT) & AMD_NB_SCRUBCTL_DRAM_MASK))