svn commit: r366712 - in head/sys: amd64/amd64 i386/i386 x86/include x86/x86

Konstantin Belousov kib at FreeBSD.org
Wed Oct 14 22:57:52 UTC 2020


Author: kib
Date: Wed Oct 14 22:57:50 2020
New Revision: 366712
URL: https://svnweb.freebsd.org/changeset/base/366712

Log:
  Limit workaround for errata E400 to appropriate AMD cpus.
  
  From Linux sources and several datasheets I looked at, it seems that
  the workaround is only needed on families 0xf and 0x10.  For instance,
  Ryzens do not implement the accessed MSR at all, it is documented as
  reserved.  Also, hypervisors should not allow guest to put CPU into
  idle state, so activate workaround only when on bare hardware.
  
  While there, style the code:
      move MSR defines to specialreg.h
      move identification to initcpu.c
  
  Reported by:	whu
  Reviewed by:	avg
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week
  Differential revision:	https://reviews.freebsd.org/D26470

Modified:
  head/sys/amd64/amd64/initcpu.c
  head/sys/amd64/amd64/machdep.c
  head/sys/i386/i386/initcpu.c
  head/sys/i386/i386/machdep.c
  head/sys/x86/include/specialreg.h
  head/sys/x86/include/x86_var.h
  head/sys/x86/x86/cpu_machdep.c

Modified: head/sys/amd64/amd64/initcpu.c
==============================================================================
--- head/sys/amd64/amd64/initcpu.c	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/amd64/amd64/initcpu.c	Wed Oct 14 22:57:50 2020	(r366712)
@@ -69,6 +69,23 @@ init_amd(void)
 	uint64_t msr;
 
 	/*
+	 * C1E renders the local APIC timer dead, so we disable it by
+	 * reading the Interrupt Pending Message register and clearing
+	 * both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
+	 *
+	 * Reference:
+	 *   "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors"
+	 *   #32559 revision 3.00+
+	 *
+	 * Detect the presence of C1E capability mostly on latest
+	 * dual-cores (or future) k8 family.  Affected models range is
+	 * taken from Linux sources.
+	 */
+	if ((CPUID_TO_FAMILY(cpu_id) == 0xf ||
+	    CPUID_TO_FAMILY(cpu_id) == 0x10) && (cpu_feature2 & CPUID2_HV) == 0)
+		cpu_amdc1e_bug = 1;
+
+	/*
 	 * Work around Erratum 721 for Family 10h and 12h processors.
 	 * These processors may incorrectly update the stack pointer
 	 * after a long series of push and/or near-call instructions,

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/amd64/amd64/machdep.c	Wed Oct 14 22:57:50 2020	(r366712)
@@ -1928,8 +1928,6 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 	if (env != NULL)
 		strlcpy(kernelname, env, sizeof(kernelname));
 
-	cpu_probe_amdc1e();
-
 	kcsan_cpu_init(0);
 
 #ifdef FDT

Modified: head/sys/i386/i386/initcpu.c
==============================================================================
--- head/sys/i386/i386/initcpu.c	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/i386/i386/initcpu.c	Wed Oct 14 22:57:50 2020	(r366712)
@@ -720,8 +720,8 @@ initializecpu(void)
 				break;
 			}
 			break;
-#ifdef CPU_ATHLON_SSE_HACK
 		case CPU_VENDOR_AMD:
+#ifdef CPU_ATHLON_SSE_HACK
 			/*
 			 * Sometimes the BIOS doesn't enable SSE instructions.
 			 * According to AMD document 20734, the mobile
@@ -738,8 +738,16 @@ initializecpu(void)
 				do_cpuid(1, regs);
 				cpu_feature = regs[3];
 			}
-			break;
 #endif
+			/*
+			 * Detect C1E that breaks APIC.  See comment in
+			 * amd64/initcpu.c.
+			 */
+			if ((CPUID_TO_FAMILY(cpu_id) == 0xf ||
+			    CPUID_TO_FAMILY(cpu_id) == 0x10) &&
+			    (cpu_feature2 & CPUID2_HV) == 0)
+				cpu_amdc1e_bug = 1;
+			break;
 		case CPU_VENDOR_CENTAUR:
 			init_via();
 			break;

Modified: head/sys/i386/i386/machdep.c
==============================================================================
--- head/sys/i386/i386/machdep.c	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/i386/i386/machdep.c	Wed Oct 14 22:57:50 2020	(r366712)
@@ -2505,8 +2505,6 @@ init386(int first)
 	thread0.td_pcb->pcb_ext = 0;
 	thread0.td_frame = &proc0_tf;
 
-	cpu_probe_amdc1e();
-
 #ifdef FDT
 	x86_init_fdt();
 #endif

Modified: head/sys/x86/include/specialreg.h
==============================================================================
--- head/sys/x86/include/specialreg.h	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/x86/include/specialreg.h	Wed Oct 14 22:57:50 2020	(r366712)
@@ -1126,6 +1126,7 @@
 #define	MSR_NB_CFG1	0xc001001f	/* NB configuration 1 */
 #define	MSR_K8_UCODE_UPDATE 0xc0010020	/* update microcode */
 #define	MSR_MC0_CTL_MASK 0xc0010044
+#define	MSR_AMDK8_IPM	0xc0010055
 #define	MSR_P_STATE_LIMIT 0xc0010061	/* P-state Current Limit Register */
 #define	MSR_P_STATE_CONTROL 0xc0010062	/* P-state Control Register */
 #define	MSR_P_STATE_STATUS 0xc0010063	/* P-state Status Register */
@@ -1142,6 +1143,9 @@
 
 /* MSR_VM_CR related */
 #define	VM_CR_SVMDIS		0x10	/* SVM: disabled by BIOS */
+
+#define	AMDK8_SMIONCMPHALT	(1ULL << 27)
+#define	AMDK8_C1EONCMPHALT	(1ULL << 28)
 
 /* VIA ACE crypto featureset: for via_feature_rng */
 #define	VIA_HAS_RNG		1	/* cpu has RNG */

Modified: head/sys/x86/include/x86_var.h
==============================================================================
--- head/sys/x86/include/x86_var.h	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/x86/include/x86_var.h	Wed Oct 14 22:57:50 2020	(r366712)
@@ -94,6 +94,7 @@ extern	int	hw_ssb_active;
 extern	int	x86_taa_enable;
 extern	int	cpu_flush_rsb_ctxsw;
 extern	int	x86_rngds_mitg_enable;
+extern	int	cpu_amdc1e_bug;
 
 struct	pcb;
 struct	thread;

Modified: head/sys/x86/x86/cpu_machdep.c
==============================================================================
--- head/sys/x86/x86/cpu_machdep.c	Wed Oct 14 22:51:40 2020	(r366711)
+++ head/sys/x86/x86/cpu_machdep.c	Wed Oct 14 22:57:50 2020	(r366712)
@@ -486,7 +486,9 @@ cpu_mwait_usable(void)
 }
 
 void (*cpu_idle_hook)(sbintime_t) = NULL;	/* ACPI idle hook. */
-static int	cpu_ident_amdc1e = 0;	/* AMD C1E supported. */
+
+int cpu_amdc1e_bug = 0;			/* AMD C1E APIC workaround required. */
+
 static int	idle_mwait = 1;		/* Use MONITOR/MWAIT for short idle. */
 SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait,
     0, "Use MONITOR/MWAIT for short idle");
@@ -587,35 +589,6 @@ cpu_idle_spin(sbintime_t sbt)
 	}
 }
 
-/*
- * C1E renders the local APIC timer dead, so we disable it by
- * reading the Interrupt Pending Message register and clearing
- * both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
- * 
- * Reference:
- *   "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors"
- *   #32559 revision 3.00+
- */
-#define	MSR_AMDK8_IPM		0xc0010055
-#define	AMDK8_SMIONCMPHALT	(1ULL << 27)
-#define	AMDK8_C1EONCMPHALT	(1ULL << 28)
-#define	AMDK8_CMPHALT		(AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT)
-
-void
-cpu_probe_amdc1e(void)
-{
-
-	/*
-	 * Detect the presence of C1E capability mostly on latest
-	 * dual-cores (or future) k8 family.
-	 */
-	if (cpu_vendor_id == CPU_VENDOR_AMD &&
-	    (cpu_id & 0x00000f00) == 0x00000f00 &&
-	    (cpu_id & 0x0fff0000) >=  0x00040000) {
-		cpu_ident_amdc1e = 1;
-	}
-}
-
 void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi;
 
 void
@@ -645,10 +618,11 @@ cpu_idle(int busy)
 	}
 
 	/* Apply AMD APIC timer C1E workaround. */
-	if (cpu_ident_amdc1e && cpu_disable_c3_sleep) {
+	if (cpu_amdc1e_bug && cpu_disable_c3_sleep) {
 		msr = rdmsr(MSR_AMDK8_IPM);
-		if (msr & AMDK8_CMPHALT)
-			wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT);
+		if ((msr & (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT)) != 0)
+			wrmsr(MSR_AMDK8_IPM, msr & ~(AMDK8_SMIONCMPHALT |
+			    AMDK8_C1EONCMPHALT));
 	}
 
 	/* Call main idle method. */


More information about the svn-src-head mailing list