svn commit: r348109 - in head/sys/x86: include x86
Andrew Gallatin
gallatin at FreeBSD.org
Wed May 22 13:44:17 UTC 2019
Author: gallatin
Date: Wed May 22 13:44:15 2019
New Revision: 348109
URL: https://svnweb.freebsd.org/changeset/base/348109
Log:
x86 MCA: introduce MCA hooks for different vendor implementations
This is needed for AMD SMCA processors, as SMCA uses different
MSR address for access MCA banks.
Use IA32 specific msr_ops as defualt, and use SMCA-specific msr_ops
when on an SMCA-enabled processor
Submitted by: chandu from amd dot com
Reviewed by: cem
Differential Revision: https://reviews.freebsd.org/D18055
Modified:
head/sys/x86/include/specialreg.h
head/sys/x86/x86/mca.c
Modified: head/sys/x86/include/specialreg.h
==============================================================================
--- head/sys/x86/include/specialreg.h Wed May 22 08:30:03 2019 (r348108)
+++ head/sys/x86/include/specialreg.h Wed May 22 13:44:15 2019 (r348109)
@@ -944,6 +944,16 @@
#define MC_MISC_AMD_PTR_MASK 0x00000000ff000000 /* Pointer to additional registers */
#define MC_MISC_AMD_PTR_SHIFT 24
+/* AMD Scalable MCA */
+#define MSR_SMCA_MC0_CTL 0xc0002000
+#define MSR_SMCA_MC0_STATUS 0xc0002001
+#define MSR_SMCA_MC0_ADDR 0xc0002002
+#define MSR_SMCA_MC0_MISC0 0xc0002003
+#define MSR_SMCA_MC_CTL(x) (MSR_SMCA_MC0_CTL + 0x10 * (x))
+#define MSR_SMCA_MC_STATUS(x) (MSR_SMCA_MC0_STATUS + 0x10 * (x))
+#define MSR_SMCA_MC_ADDR(x) (MSR_SMCA_MC0_ADDR + 0x10 * (x))
+#define MSR_SMCA_MC_MISC(x) (MSR_SMCA_MC0_MISC0 + 0x10 * (x))
+
/*
* The following four 3-byte registers control the non-cacheable regions.
* These registers must be written as three separate bytes.
Modified: head/sys/x86/x86/mca.c
==============================================================================
--- head/sys/x86/x86/mca.c Wed May 22 08:30:03 2019 (r348108)
+++ head/sys/x86/x86/mca.c Wed May 22 13:44:15 2019 (r348109)
@@ -90,6 +90,13 @@ struct mca_internal {
STAILQ_ENTRY(mca_internal) link;
};
+struct mca_enumerator_ops {
+ unsigned int (*ctl)(int);
+ unsigned int (*status)(int);
+ unsigned int (*addr)(int);
+ unsigned int (*misc)(int);
+};
+
static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture");
static volatile int mca_count; /* Number of records stored. */
@@ -124,6 +131,61 @@ static struct taskqueue *mca_tq;
static struct task mca_refill_task, mca_scan_task;
static struct mtx mca_lock;
+static unsigned int
+mca_ia32_ctl_reg(int bank)
+{
+ return (MSR_MC_CTL(bank));
+}
+
+static unsigned int
+mca_ia32_status_reg(int bank)
+{
+ return (MSR_MC_STATUS(bank));
+}
+
+static unsigned int
+mca_ia32_addr_reg(int bank)
+{
+ return (MSR_MC_ADDR(bank));
+}
+
+static unsigned int
+mca_ia32_misc_reg(int bank)
+{
+ return (MSR_MC_MISC(bank));
+}
+
+static unsigned int
+mca_smca_ctl_reg(int bank)
+{
+ return (MSR_SMCA_MC_CTL(bank));
+}
+
+static unsigned int
+mca_smca_status_reg(int bank)
+{
+ return (MSR_SMCA_MC_STATUS(bank));
+}
+
+static unsigned int
+mca_smca_addr_reg(int bank)
+{
+ return (MSR_SMCA_MC_ADDR(bank));
+}
+
+static unsigned int
+mca_smca_misc_reg(int bank)
+{
+ return (MSR_SMCA_MC_MISC(bank));
+}
+
+static struct mca_enumerator_ops mca_msr_ops = {
+ .ctl = mca_ia32_ctl_reg,
+ .status = mca_ia32_status_reg,
+ .addr = mca_ia32_addr_reg,
+ .misc = mca_ia32_misc_reg
+};
+
#ifdef DEV_APIC
static struct cmc_state **cmc_state; /* Indexed by cpuid, bank. */
static struct amd_et_state **amd_et_state; /* Indexed by cpuid, bank. */
@@ -462,7 +524,7 @@ mca_check_status(int bank, struct mca_record *rec)
uint64_t status;
u_int p[4];
- status = rdmsr(MSR_MC_STATUS(bank));
+ status = rdmsr(mca_msr_ops.status(bank));
if (!(status & MC_STATUS_VAL))
return (0);
@@ -471,10 +533,10 @@ mca_check_status(int bank, struct mca_record *rec)
rec->mr_bank = bank;
rec->mr_addr = 0;
if (status & MC_STATUS_ADDRV)
- rec->mr_addr = rdmsr(MSR_MC_ADDR(bank));
+ rec->mr_addr = rdmsr(mca_msr_ops.addr(bank));
rec->mr_misc = 0;
if (status & MC_STATUS_MISCV)
- rec->mr_misc = rdmsr(MSR_MC_MISC(bank));
+ rec->mr_misc = rdmsr(mca_msr_ops.misc(bank));
rec->mr_tsc = rdtsc();
rec->mr_apic_id = PCPU_GET(apic_id);
rec->mr_mcg_cap = rdmsr(MSR_MCG_CAP);
@@ -488,7 +550,7 @@ mca_check_status(int bank, struct mca_record *rec)
* errors so that the BIOS can see them.
*/
if (!(rec->mr_status & (MC_STATUS_PCC | MC_STATUS_UC))) {
- wrmsr(MSR_MC_STATUS(bank), 0);
+ wrmsr(mca_msr_ops.status(bank), 0);
do_cpuid(0, p);
}
return (1);
@@ -648,7 +710,7 @@ amd_thresholding_update(enum scan_mode mode, int bank,
int count;
cc = &amd_et_state[PCPU_GET(cpuid)][bank];
- misc = rdmsr(MSR_MC_MISC(bank));
+ misc = rdmsr(mca_msr_ops.misc(bank));
count = (misc & MC_MISC_AMD_CNT_MASK) >> MC_MISC_AMD_CNT_SHIFT;
count = count - (MC_MISC_AMD_CNT_MAX - cc->cur_threshold);
@@ -660,7 +722,7 @@ amd_thresholding_update(enum scan_mode mode, int bank,
misc |= (uint64_t)(MC_MISC_AMD_CNT_MAX - cc->cur_threshold)
<< MC_MISC_AMD_CNT_SHIFT;
misc &= ~MC_MISC_AMD_OVERFLOW;
- wrmsr(MSR_MC_MISC(bank), misc);
+ wrmsr(mca_msr_ops.misc(bank), misc);
if (mode == CMCI && valid)
cc->last_intr = time_uptime;
}
@@ -978,7 +1040,7 @@ amd_thresholding_start(struct amd_et_state *cc, int ba
KASSERT(amd_elvt >= 0, ("ELVT offset is not set"));
- misc = rdmsr(MSR_MC_MISC(bank));
+ misc = rdmsr(mca_msr_ops.misc(bank));
misc &= ~MC_MISC_AMD_INT_MASK;
misc |= MC_MISC_AMD_INT_LVT;
@@ -993,7 +1055,7 @@ amd_thresholding_start(struct amd_et_state *cc, int ba
misc &= ~MC_MISC_AMD_OVERFLOW;
misc |= MC_MISC_AMD_CNTEN;
- wrmsr(MSR_MC_MISC(bank), misc);
+ wrmsr(mca_msr_ops.misc(bank), misc);
}
static void
@@ -1011,7 +1073,7 @@ amd_thresholding_monitor(int i)
return;
/* The counter must be valid and present. */
- misc = rdmsr(MSR_MC_MISC(i));
+ misc = rdmsr(mca_msr_ops.misc(i));
if ((misc & (MC_MISC_AMD_VAL | MC_MISC_AMD_CNTP)) !=
(MC_MISC_AMD_VAL | MC_MISC_AMD_CNTP))
return;
@@ -1119,6 +1181,12 @@ _mca_init(int boot)
if ((mask & (1UL << 5)) == 0)
wrmsr(MSR_MC0_CTL_MASK, mask | (1UL << 5));
}
+ if (amd_rascap & AMDRAS_SCALABLE_MCA) {
+ mca_msr_ops.ctl = mca_smca_ctl_reg;
+ mca_msr_ops.status = mca_smca_status_reg;
+ mca_msr_ops.addr = mca_smca_addr_reg;
+ mca_msr_ops.misc = mca_smca_misc_reg;
+ }
/*
* The cmci_monitor() must not be executed
@@ -1142,12 +1210,13 @@ _mca_init(int boot)
skip = 1;
} else if (cpu_vendor_id == CPU_VENDOR_AMD) {
/* BKDG for Family 10h: unset GartTblWkEn. */
- if (i == MC_AMDNB_BANK && family >= 0xf)
+ if (i == MC_AMDNB_BANK && family >= 0xf &&
+ family < 0x17)
ctl &= ~(1UL << 10);
}
if (!skip)
- wrmsr(MSR_MC_CTL(i), ctl);
+ wrmsr(mca_msr_ops.ctl(i), ctl);
#ifdef DEV_APIC
if (cmci_supported(mcg_cap)) {
@@ -1164,7 +1233,7 @@ _mca_init(int boot)
#endif
/* Clear all errors. */
- wrmsr(MSR_MC_STATUS(i), 0);
+ wrmsr(mca_msr_ops.status(i), 0);
}
if (boot)
mtx_unlock_spin(&mca_lock);
More information about the svn-src-head
mailing list