diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-05-04 08:01:10 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-05-04 08:09:16 -0400 |
commit | 6d45b719cbd51f014bb1b5dd8ed99068d78d36af (patch) | |
tree | c49822a308038696cbea7e1ea466a6b3248b1efd | |
parent | ba41e1bc28bd862089b0fc00e8136aa258a62b21 (diff) |
intel_pstate: Fix intel_pstate_get()
After commit 8fa520af5081 "intel_pstate: Remove freq calculation from
intel_pstate_calc_busy()" intel_pstate_get() calls get_avg_frequency()
to compute the average frequency, which is problematic for two reasons.
First, intel_pstate_get() may be invoked before the driver reads the
CPU feedback registers for the first time and if that happens,
get_avg_frequency() will attempt to divide by zero.
Second, the get_avg_frequency() call in intel_pstate_get() is racy
with respect to intel_pstate_sample() and it may end up returning
completely meaningless values for this reason.
Moreover, after commit 7349ec0470b6 "intel_pstate: Move
intel_pstate_calc_busy() into get_target_pstate_use_performance()"
sample.core_pct_busy is never computed on Atom, but it is used in
intel_pstate_adjust_busy_pstate() in that case too.
To address those problems notice that if sample.core_pct_busy
was used in the average frequency computation carried out by
get_avg_frequency(), both the divide by zero problem and the
race with respect to intel_pstate_sample() would be avoided.
Accordingly, move the invocation of intel_pstate_calc_busy() from
get_target_pstate_use_performance() to intel_pstate_update_util(),
which also will take care of the uninitialized sample.core_pct_busy
on Atom, and modify get_avg_frequency() to use sample.core_pct_busy
as per the above.
Reported-by: kernel test robot <ying.huang@linux.intel.com>
Link: http://marc.info/?l=linux-kernel&m=146226437623173&w=4
Fixes: 8fa520af5081 "intel_pstate: Remove freq calculation from intel_pstate_calc_busy()"
Fixes: 7349ec0470b6 "intel_pstate: Move intel_pstate_calc_busy() into get_target_pstate_use_performance()"
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 66f7f0071cab..b230ebaae66c 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c | |||
@@ -1070,8 +1070,9 @@ static inline bool intel_pstate_sample(struct cpudata *cpu, u64 time) | |||
1070 | 1070 | ||
1071 | static inline int32_t get_avg_frequency(struct cpudata *cpu) | 1071 | static inline int32_t get_avg_frequency(struct cpudata *cpu) |
1072 | { | 1072 | { |
1073 | return div64_u64(cpu->pstate.max_pstate_physical * cpu->sample.aperf * | 1073 | return fp_toint(mul_fp(cpu->sample.core_pct_busy, |
1074 | cpu->pstate.scaling, cpu->sample.mperf); | 1074 | int_tofp(cpu->pstate.max_pstate_physical * |
1075 | cpu->pstate.scaling / 100))); | ||
1075 | } | 1076 | } |
1076 | 1077 | ||
1077 | static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) | 1078 | static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) |
@@ -1114,8 +1115,6 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) | |||
1114 | int32_t core_busy, max_pstate, current_pstate, sample_ratio; | 1115 | int32_t core_busy, max_pstate, current_pstate, sample_ratio; |
1115 | u64 duration_ns; | 1116 | u64 duration_ns; |
1116 | 1117 | ||
1117 | intel_pstate_calc_busy(cpu); | ||
1118 | |||
1119 | /* | 1118 | /* |
1120 | * core_busy is the ratio of actual performance to max | 1119 | * core_busy is the ratio of actual performance to max |
1121 | * max_pstate is the max non turbo pstate available | 1120 | * max_pstate is the max non turbo pstate available |
@@ -1199,8 +1198,11 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time, | |||
1199 | if ((s64)delta_ns >= pid_params.sample_rate_ns) { | 1198 | if ((s64)delta_ns >= pid_params.sample_rate_ns) { |
1200 | bool sample_taken = intel_pstate_sample(cpu, time); | 1199 | bool sample_taken = intel_pstate_sample(cpu, time); |
1201 | 1200 | ||
1202 | if (sample_taken && !hwp_active) | 1201 | if (sample_taken) { |
1203 | intel_pstate_adjust_busy_pstate(cpu); | 1202 | intel_pstate_calc_busy(cpu); |
1203 | if (!hwp_active) | ||
1204 | intel_pstate_adjust_busy_pstate(cpu); | ||
1205 | } | ||
1204 | } | 1206 | } |
1205 | } | 1207 | } |
1206 | 1208 | ||