Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 May 2019 13:44:16 +0000 (UTC)
From:      Andrew Gallatin <gallatin@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r348109 - in head/sys/x86: include x86
Message-ID:  <201905221344.x4MDiGGV056469@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905221344.x4MDiGGV056469>