More power management updates for v4.9-rc1
- Fix two cpufreq regressions causing undesirable changes in behavior to appear (one in the core and one in the conservative governor) introduced during the 4.8 cycle (Aaro Koskinen, Rafael Wysocki). - Fix the way the intel_pstate driver accesses MSRs related to the hardware-managed P-states (HWP) feature during the initialization which currently is unsafe and may cause the processor to generate a general protection fault (Srinivas Pandruvada). - Rework the intel_pstate's P-state selection algorithm used on Atom processors to avoid known problems with the current one and to make the computation more straightforward, which also happens to improve performance in multiple benchmarks a bit (Rafael Wysocki). - Improve two comments in the intel_pstate driver (Rafael Wysocki). - Fix the desired performance computation in the CPPC cpufreq driver (Hoan Tran). - Fix the devfreq core to avoid printing misleading error messages in some cases (Tobias Jakobi). - Fix the error code path in devfreq_add_device() to use proper locking around list modifications (Axel Lin). - Fix a build failure and remove a couple of redundant updates of variables in the exynos-nocp devfreq driver (Axel Lin). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJYANqMAAoJEILEb/54YlRx+U4P/A1ZJ/93u+ChipehTckNDogR xMCNsUz6Pn9VIdilEnaUcsCaNc93R7e6KjwgSO7Caeriw4syW3YZz2LuGQTihs8b 5vnvVvya9Bw1aXUweeayogMyOYZV1y1G/yzq7/+c02/cgxO8WBPnmGrE17Mhu43q IF1pQJ257e0HgKKspuzy+twRCLwnOqHbvWtQnEi2rzuaGrsK7XZk9yRuaXK4NshQ +M9hrHlw+OdmI+9lLmH8Ap2G68EJ4Q2o69sbAQ6MWgxRU44D0uEqgbT16cIdDs3J c9VCgiqHuhj2bfd9vqNAjr4bGdy4iwcEKyz2nkIl0KEq9tTPtJky8v6WUzV0+rbR xVbGIWg8X5wKe/Ndve2GLDrqhuVJ0hZkRdqpzRgm08VBGpRlmM0Gjqk+uEKqA2n2 IhidwTlzbQFVh437cjqupCKVXPb2POdgNyk4fEK7WVckRR3K7LR+rXoWN1uwW2YJ 9rjQBX0n2UfZ9Ft+gVO6/faWZlqLPmx60lHQSXNHvNY04HfZ5EiRFGEZEX1g0Uep 16nYHpB+qx/GwR7druGQVVY58YEp2g68jbpL2ehr2lLBYVSExy0kiOrS7GpoA0vd ngImjroJ842wQYjfek4Gi8VfGu+tsuMIVdjltOn1sVZ1QvprgF/atZHcN84eV8BU OyEGOQ7H1idEZ14Oa19C =3yoB -----END PGP SIGNATURE----- Merge tag 'pm-extra-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull more power management updates from Rafael Wysocki: "This includes a couple of fixes for cpufreq regressions introduced in 4.8, a rework of the intel_pstate algorithm used on Atom processors (that took some time to test) plus a fix and a couple of cleanups in that driver, a CPPC cpufreq driver fix, and a some devfreq fixes and cleanups (core and exynos-nocp). Specifics: - Fix two cpufreq regressions causing undesirable changes in behavior to appear (one in the core and one in the conservative governor) introduced during the 4.8 cycle (Aaro Koskinen, Rafael Wysocki). - Fix the way the intel_pstate driver accesses MSRs related to the hardware-managed P-states (HWP) feature during the initialization which currently is unsafe and may cause the processor to generate a general protection fault (Srinivas Pandruvada). - Rework the intel_pstate's P-state selection algorithm used on Atom processors to avoid known problems with the current one and to make the computation more straightforward, which also happens to improve performance in multiple benchmarks a bit (Rafael Wysocki). - Improve two comments in the intel_pstate driver (Rafael Wysocki). - Fix the desired performance computation in the CPPC cpufreq driver (Hoan Tran). - Fix the devfreq core to avoid printing misleading error messages in some cases (Tobias Jakobi). - Fix the error code path in devfreq_add_device() to use proper locking around list modifications (Axel Lin). - Fix a build failure and remove a couple of redundant updates of variables in the exynos-nocp devfreq driver (Axel Lin)" * tag 'pm-extra-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: cpufreq: CPPC: Correct desired_perf calculation cpufreq: conservative: Fix next frequency selection cpufreq: skip invalid entries when searching the frequency cpufreq: intel_pstate: Fix struct pstate_adjust_policy kerneldoc cpufreq: intel_pstate: Proportional algorithm for Atom PM / devfreq: Skip status update on uninitialized previous_freq PM / devfreq: Add proper locking around list_del() PM / devfreq: exynos-nocp: Remove redundant code PM / devfreq: exynos-nocp: Select REGMAP_MMIO cpufreq: intel_pstate: Clarify comment in get_target_pstate_use_performance() cpufreq: intel_pstate: Fix unsafe HWP MSR access
This commit is contained in:
Коммит
ef98988ba3
|
@ -80,11 +80,17 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
|
|||
{
|
||||
struct cppc_cpudata *cpu;
|
||||
struct cpufreq_freqs freqs;
|
||||
u32 desired_perf;
|
||||
int ret = 0;
|
||||
|
||||
cpu = all_cpu_data[policy->cpu];
|
||||
|
||||
cpu->perf_ctrls.desired_perf = (u64)target_freq * policy->max / cppc_dmi_max_khz;
|
||||
desired_perf = (u64)target_freq * cpu->perf_caps.highest_perf / cppc_dmi_max_khz;
|
||||
/* Return if it is exactly the same perf */
|
||||
if (desired_perf == cpu->perf_ctrls.desired_perf)
|
||||
return ret;
|
||||
|
||||
cpu->perf_ctrls.desired_perf = desired_perf;
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = target_freq;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
struct cs_policy_dbs_info {
|
||||
struct policy_dbs_info policy_dbs;
|
||||
unsigned int down_skip;
|
||||
unsigned int requested_freq;
|
||||
};
|
||||
|
||||
static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs)
|
||||
|
@ -61,6 +62,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
{
|
||||
struct policy_dbs_info *policy_dbs = policy->governor_data;
|
||||
struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
|
||||
unsigned int requested_freq = dbs_info->requested_freq;
|
||||
struct dbs_data *dbs_data = policy_dbs->dbs_data;
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int load = dbs_update(policy);
|
||||
|
@ -72,10 +74,16 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
if (cs_tuners->freq_step == 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If requested_freq is out of range, it is likely that the limits
|
||||
* changed in the meantime, so fall back to current frequency in that
|
||||
* case.
|
||||
*/
|
||||
if (requested_freq > policy->max || requested_freq < policy->min)
|
||||
requested_freq = policy->cur;
|
||||
|
||||
/* Check for frequency increase */
|
||||
if (load > dbs_data->up_threshold) {
|
||||
unsigned int requested_freq = policy->cur;
|
||||
|
||||
dbs_info->down_skip = 0;
|
||||
|
||||
/* if we are already at full speed then break out early */
|
||||
|
@ -83,8 +91,11 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
goto out;
|
||||
|
||||
requested_freq += get_freq_target(cs_tuners, policy);
|
||||
if (requested_freq > policy->max)
|
||||
requested_freq = policy->max;
|
||||
|
||||
__cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H);
|
||||
dbs_info->requested_freq = requested_freq;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -95,7 +106,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
|
||||
/* Check for frequency decrease */
|
||||
if (load < cs_tuners->down_threshold) {
|
||||
unsigned int freq_target, requested_freq = policy->cur;
|
||||
unsigned int freq_target;
|
||||
/*
|
||||
* if we cannot reduce the frequency anymore, break out early
|
||||
*/
|
||||
|
@ -109,6 +120,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
requested_freq = policy->min;
|
||||
|
||||
__cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L);
|
||||
dbs_info->requested_freq = requested_freq;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -287,6 +299,7 @@ static void cs_start(struct cpufreq_policy *policy)
|
|||
struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
|
||||
|
||||
dbs_info->down_skip = 0;
|
||||
dbs_info->requested_freq = policy->cur;
|
||||
}
|
||||
|
||||
static struct dbs_governor cs_governor = {
|
||||
|
|
|
@ -225,7 +225,7 @@ struct cpudata {
|
|||
static struct cpudata **all_cpu_data;
|
||||
|
||||
/**
|
||||
* struct pid_adjust_policy - Stores static PID configuration data
|
||||
* struct pstate_adjust_policy - Stores static PID configuration data
|
||||
* @sample_rate_ms: PID calculation sample rate in ms
|
||||
* @sample_rate_ns: Sample rate calculation in ns
|
||||
* @deadband: PID deadband
|
||||
|
@ -562,12 +562,12 @@ static void intel_pstate_hwp_set(const struct cpumask *cpumask)
|
|||
int min, hw_min, max, hw_max, cpu, range, adj_range;
|
||||
u64 value, cap;
|
||||
|
||||
rdmsrl(MSR_HWP_CAPABILITIES, cap);
|
||||
hw_min = HWP_LOWEST_PERF(cap);
|
||||
hw_max = HWP_HIGHEST_PERF(cap);
|
||||
range = hw_max - hw_min;
|
||||
|
||||
for_each_cpu(cpu, cpumask) {
|
||||
rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap);
|
||||
hw_min = HWP_LOWEST_PERF(cap);
|
||||
hw_max = HWP_HIGHEST_PERF(cap);
|
||||
range = hw_max - hw_min;
|
||||
|
||||
rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
|
||||
adj_range = limits->min_perf_pct * range / 100;
|
||||
min = hw_min + adj_range;
|
||||
|
@ -1232,6 +1232,7 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
|
|||
{
|
||||
struct sample *sample = &cpu->sample;
|
||||
int32_t busy_frac, boost;
|
||||
int target, avg_pstate;
|
||||
|
||||
busy_frac = div_fp(sample->mperf, sample->tsc);
|
||||
|
||||
|
@ -1242,7 +1243,26 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
|
|||
busy_frac = boost;
|
||||
|
||||
sample->busy_scaled = busy_frac * 100;
|
||||
return get_avg_pstate(cpu) - pid_calc(&cpu->pid, sample->busy_scaled);
|
||||
|
||||
target = limits->no_turbo || limits->turbo_disabled ?
|
||||
cpu->pstate.max_pstate : cpu->pstate.turbo_pstate;
|
||||
target += target >> 2;
|
||||
target = mul_fp(target, busy_frac);
|
||||
if (target < cpu->pstate.min_pstate)
|
||||
target = cpu->pstate.min_pstate;
|
||||
|
||||
/*
|
||||
* If the average P-state during the previous cycle was higher than the
|
||||
* current target, add 50% of the difference to the target to reduce
|
||||
* possible performance oscillations and offset possible performance
|
||||
* loss related to moving the workload from one CPU to another within
|
||||
* a package/module.
|
||||
*/
|
||||
avg_pstate = get_avg_pstate(cpu);
|
||||
if (avg_pstate > target)
|
||||
target += (avg_pstate - target) >> 1;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
|
||||
|
@ -1251,10 +1271,11 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
|
|||
u64 duration_ns;
|
||||
|
||||
/*
|
||||
* perf_scaled is the average performance during the last sampling
|
||||
* period scaled by the ratio of the maximum P-state to the P-state
|
||||
* requested last time (in percent). That measures the system's
|
||||
* response to the previous P-state selection.
|
||||
* perf_scaled is the ratio of the average P-state during the last
|
||||
* sampling period to the P-state requested last time (in percent).
|
||||
*
|
||||
* That measures the system's response to the previous P-state
|
||||
* selection.
|
||||
*/
|
||||
max_pstate = cpu->pstate.max_pstate_physical;
|
||||
current_pstate = cpu->pstate.current_pstate;
|
||||
|
|
|
@ -137,6 +137,10 @@ static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
|
|||
|
||||
cur_time = jiffies;
|
||||
|
||||
/* Immediately exit if previous_freq is not initialized yet. */
|
||||
if (!devfreq->previous_freq)
|
||||
goto out;
|
||||
|
||||
prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
|
||||
if (prev_lev < 0) {
|
||||
ret = prev_lev;
|
||||
|
@ -594,17 +598,19 @@ struct devfreq *devfreq_add_device(struct device *dev,
|
|||
if (devfreq->governor)
|
||||
err = devfreq->governor->event_handler(devfreq,
|
||||
DEVFREQ_GOV_START, NULL);
|
||||
mutex_unlock(&devfreq_list_lock);
|
||||
if (err) {
|
||||
dev_err(dev, "%s: Unable to start governor for the device\n",
|
||||
__func__);
|
||||
goto err_init;
|
||||
}
|
||||
mutex_unlock(&devfreq_list_lock);
|
||||
|
||||
return devfreq;
|
||||
|
||||
err_init:
|
||||
list_del(&devfreq->node);
|
||||
mutex_unlock(&devfreq_list_lock);
|
||||
|
||||
device_unregister(&devfreq->dev);
|
||||
err_out:
|
||||
return ERR_PTR(err);
|
||||
|
|
|
@ -17,6 +17,7 @@ config DEVFREQ_EVENT_EXYNOS_NOCP
|
|||
tristate "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver"
|
||||
depends on ARCH_EXYNOS || COMPILE_TEST
|
||||
select PM_OPP
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
This add the devfreq-event driver for Exynos SoC. It provides NoC
|
||||
(Network on Chip) Probe counters to measure the bandwidth of AXI bus.
|
||||
|
|
|
@ -176,9 +176,6 @@ static int exynos_nocp_get_event(struct devfreq_event_dev *edev,
|
|||
return 0;
|
||||
|
||||
out:
|
||||
edata->load_count = 0;
|
||||
edata->total_count = 0;
|
||||
|
||||
dev_err(nocp->dev, "Failed to read the counter of NoC probe device\n");
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -639,19 +639,19 @@ static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq)
|
||||
{
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
struct cpufreq_frequency_table *pos, *best = table - 1;
|
||||
unsigned int freq;
|
||||
int i, best = -1;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
freq = table[i].frequency;
|
||||
cpufreq_for_each_valid_entry(pos, table) {
|
||||
freq = pos->frequency;
|
||||
|
||||
if (freq >= target_freq)
|
||||
return i;
|
||||
return pos - table;
|
||||
|
||||
best = i;
|
||||
best = pos;
|
||||
}
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
/* Find lowest freq at or above target in a table in descending order */
|
||||
|
@ -659,28 +659,28 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq)
|
||||
{
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
struct cpufreq_frequency_table *pos, *best = table - 1;
|
||||
unsigned int freq;
|
||||
int i, best = -1;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
freq = table[i].frequency;
|
||||
cpufreq_for_each_valid_entry(pos, table) {
|
||||
freq = pos->frequency;
|
||||
|
||||
if (freq == target_freq)
|
||||
return i;
|
||||
return pos - table;
|
||||
|
||||
if (freq > target_freq) {
|
||||
best = i;
|
||||
best = pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No freq found above target_freq */
|
||||
if (best == -1)
|
||||
return i;
|
||||
if (best == table - 1)
|
||||
return pos - table;
|
||||
|
||||
return best;
|
||||
return best - pos;
|
||||
}
|
||||
|
||||
return best;
|
||||
return best - pos;
|
||||
}
|
||||
|
||||
/* Works only on sorted freq-tables */
|
||||
|
@ -700,28 +700,28 @@ static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq)
|
||||
{
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
struct cpufreq_frequency_table *pos, *best = table - 1;
|
||||
unsigned int freq;
|
||||
int i, best = -1;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
freq = table[i].frequency;
|
||||
cpufreq_for_each_valid_entry(pos, table) {
|
||||
freq = pos->frequency;
|
||||
|
||||
if (freq == target_freq)
|
||||
return i;
|
||||
return pos - table;
|
||||
|
||||
if (freq < target_freq) {
|
||||
best = i;
|
||||
best = pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No freq found below target_freq */
|
||||
if (best == -1)
|
||||
return i;
|
||||
if (best == table - 1)
|
||||
return pos - table;
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
/* Find highest freq at or below target in a table in descending order */
|
||||
|
@ -729,19 +729,19 @@ static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq)
|
||||
{
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
struct cpufreq_frequency_table *pos, *best = table - 1;
|
||||
unsigned int freq;
|
||||
int i, best = -1;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
freq = table[i].frequency;
|
||||
cpufreq_for_each_valid_entry(pos, table) {
|
||||
freq = pos->frequency;
|
||||
|
||||
if (freq <= target_freq)
|
||||
return i;
|
||||
return pos - table;
|
||||
|
||||
best = i;
|
||||
best = pos;
|
||||
}
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
/* Works only on sorted freq-tables */
|
||||
|
@ -761,32 +761,32 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq)
|
||||
{
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
struct cpufreq_frequency_table *pos, *best = table - 1;
|
||||
unsigned int freq;
|
||||
int i, best = -1;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
freq = table[i].frequency;
|
||||
cpufreq_for_each_valid_entry(pos, table) {
|
||||
freq = pos->frequency;
|
||||
|
||||
if (freq == target_freq)
|
||||
return i;
|
||||
return pos - table;
|
||||
|
||||
if (freq < target_freq) {
|
||||
best = i;
|
||||
best = pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No freq found below target_freq */
|
||||
if (best == -1)
|
||||
return i;
|
||||
if (best == table - 1)
|
||||
return pos - table;
|
||||
|
||||
/* Choose the closest freq */
|
||||
if (target_freq - table[best].frequency > freq - target_freq)
|
||||
return i;
|
||||
if (target_freq - best->frequency > freq - target_freq)
|
||||
return pos - table;
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
/* Find closest freq to target in a table in descending order */
|
||||
|
@ -794,32 +794,32 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq)
|
||||
{
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
struct cpufreq_frequency_table *pos, *best = table - 1;
|
||||
unsigned int freq;
|
||||
int i, best = -1;
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
freq = table[i].frequency;
|
||||
cpufreq_for_each_valid_entry(pos, table) {
|
||||
freq = pos->frequency;
|
||||
|
||||
if (freq == target_freq)
|
||||
return i;
|
||||
return pos - table;
|
||||
|
||||
if (freq > target_freq) {
|
||||
best = i;
|
||||
best = pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No freq found above target_freq */
|
||||
if (best == -1)
|
||||
return i;
|
||||
if (best == table - 1)
|
||||
return pos - table;
|
||||
|
||||
/* Choose the closest freq */
|
||||
if (table[best].frequency - target_freq > target_freq - freq)
|
||||
return i;
|
||||
if (best->frequency - target_freq > target_freq - freq)
|
||||
return pos - table;
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
return best;
|
||||
return best - table;
|
||||
}
|
||||
|
||||
/* Works only on sorted freq-tables */
|
||||
|
|
Загрузка…
Ссылка в новой задаче