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.
This commit is contained in:
cem 2020-02-01 19:49:13 +00:00
parent 495b57cd9b
commit c12b25ef11
2 changed files with 58 additions and 10 deletions

View File

@ -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)
@ -414,6 +455,10 @@ intel_hwpstate_attach(device_t dev)
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)
return (ret);

View File

@ -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.
*/