svn commit: r357378 - in head/sys/x86: cpufreq include

Conrad Meyer cem at FreeBSD.org
Sat Feb 1 19:49:14 UTC 2020


Author: cem
Date: Sat Feb  1 19:49:13 2020
New Revision: 357378
URL: https://svnweb.freebsd.org/changeset/base/357378

Log:
  hwpstate_intel(4): Add fallback EPP using PERF_BIAS MSR
  
  Per Intel SDM (Vol 3b Part 2), if HWP indicates EPP (energy-performance
  preference) is not supported, the hardware instead uses the ENERGY_PERF_BIAS
  MSR.  In the epp sysctl handler, fall back to that MSR if HWP does not
  support EPP and CPUID indicates the ENERGY_PERF_BIAS MSR is supported.

Modified:
  head/sys/x86/cpufreq/hwpstate_intel.c
  head/sys/x86/include/specialreg.h

Modified: head/sys/x86/cpufreq/hwpstate_intel.c
==============================================================================
--- head/sys/x86/cpufreq/hwpstate_intel.c	Sat Feb  1 19:46:02 2020	(r357377)
+++ head/sys/x86/cpufreq/hwpstate_intel.c	Sat Feb  1 19:49:13 2020	(r357378)
@@ -88,6 +88,7 @@ struct hwp_softc {
 	bool			hwp_activity_window;
 	bool			hwp_pref_ctrl;
 	bool			hwp_pkg_ctrl;
+	bool			hwp_perf_bias;
 
 	uint64_t		req; /* Cached copy of last request */
 
@@ -215,6 +216,26 @@ raw_to_percent(int x)
 	return (round10(x * 1000 / 0xff));
 }
 
+/* Range of MSR_IA32_ENERGY_PERF_BIAS is more limited: 0-0xf. */
+static inline int
+percent_to_raw_perf_bias(int x)
+{
+	/*
+	 * Round up so that raw values present as nice round human numbers and
+	 * also round-trip to the same raw value.
+	 */
+	MPASS(x <= 100 && x >= 0);
+	return (((0xf * x) + 50) / 100);
+}
+
+static inline int
+raw_to_percent_perf_bias(int x)
+{
+	/* Rounding to nice human numbers despite a step interval of 6.67%. */
+	MPASS(x <= 0xf && x >= 0);
+	return (((x * 20) / 0xf) * 5);
+}
+
 static int
 sysctl_epp_select(SYSCTL_HANDLER_ARGS)
 {
@@ -227,7 +248,7 @@ sysctl_epp_select(SYSCTL_HANDLER_ARGS)
 
 	dev = oidp->oid_arg1;
 	sc = device_get_softc(dev);
-	if (!sc->hwp_pref_ctrl)
+	if (!sc->hwp_pref_ctrl && !sc->hwp_perf_bias)
 		return (ENODEV);
 
 	pc = cpu_get_pcpu(dev);
@@ -238,11 +259,24 @@ sysctl_epp_select(SYSCTL_HANDLER_ARGS)
 	sched_bind(curthread, pc->pc_cpuid);
 	thread_unlock(curthread);
 
-	ret = rdmsr_safe(MSR_IA32_HWP_REQUEST, &requested);
-	if (ret)
-		goto out;
-	val = (requested & IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE) >> 24;
-	val = raw_to_percent(val);
+	if (sc->hwp_pref_ctrl) {
+		ret = rdmsr_safe(MSR_IA32_HWP_REQUEST, &requested);
+		if (ret)
+			goto out;
+		val = (requested & IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE) >> 24;
+		val = raw_to_percent(val);
+	} else {
+		/*
+		 * If cpuid indicates EPP is not supported, the HWP controller
+		 * uses MSR_IA32_ENERGY_PERF_BIAS instead (Intel SDM §14.4.4).
+		 * This register is per-core (but not HT).
+		 */
+		ret = rdmsr_safe(MSR_IA32_ENERGY_PERF_BIAS, &requested);
+		if (ret)
+			goto out;
+		val = requested & IA32_ENERGY_PERF_BIAS_POLICY_HINT_MASK;
+		val = raw_to_percent_perf_bias(val);
+	}
 
 	MPASS(val >= 0 && val <= 100);
 
@@ -255,12 +289,18 @@ sysctl_epp_select(SYSCTL_HANDLER_ARGS)
 		goto out;
 	}
 
-	val = percent_to_raw(val);
+	if (sc->hwp_pref_ctrl) {
+		val = percent_to_raw(val);
 
-	requested &= ~IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE;
-	requested |= val << 24;
+		requested &= ~IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE;
+		requested |= val << 24;
 
-	ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, requested);
+		ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, requested);
+	} else {
+		requested = percent_to_raw_perf_bias(val);
+		MPASS((requested & ~IA32_ENERGY_PERF_BIAS_POLICY_HINT_MASK) == 0);
+		ret = wrmsr_safe(MSR_IA32_ENERGY_PERF_BIAS, requested);
+	}
 
 out:
 	thread_lock(curthread);
@@ -405,6 +445,7 @@ intel_hwpstate_attach(device_t dev)
 	sc = device_get_softc(dev);
 	sc->dev = dev;
 
+	/* eax */
 	if (cpu_power_eax & CPUTPM1_HWP_NOTIFICATION)
 		sc->hwp_notifications = true;
 	if (cpu_power_eax & CPUTPM1_HWP_ACTIVITY_WINDOW)
@@ -413,6 +454,10 @@ intel_hwpstate_attach(device_t dev)
 		sc->hwp_pref_ctrl = true;
 	if (cpu_power_eax & CPUTPM1_HWP_PKG)
 		sc->hwp_pkg_ctrl = true;
+
+	/* ecx */
+	if (cpu_power_ecx & CPUID_PERF_BIAS)
+		sc->hwp_perf_bias = true;
 
 	ret = set_autonomous_hwp(sc);
 	if (ret)

Modified: head/sys/x86/include/specialreg.h
==============================================================================
--- head/sys/x86/include/specialreg.h	Sat Feb  1 19:46:02 2020	(r357377)
+++ head/sys/x86/include/specialreg.h	Sat Feb  1 19:49:13 2020	(r357378)
@@ -812,6 +812,9 @@
 #define	IA32_HWP_REQUEST_MAXIMUM_PERFORMANCE		(0xffULL << 8)
 #define	IA32_HWP_MINIMUM_PERFORMANCE			(0xffULL << 0)
 
+/* MSR IA32_ENERGY_PERF_BIAS */
+#define	IA32_ENERGY_PERF_BIAS_POLICY_HINT_MASK		(0xfULL << 0)
+
 /*
  * PAT modes.
  */


More information about the svn-src-head mailing list