aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorBrennan Shacklett <brennan@genyes.org>2013-10-21 12:20:32 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-13 16:48:04 -0500
commite34ce30f3226936bf8f43dc3d2616acd268a8cd2 (patch)
tree163e64e7cc930711c6502d6403beec54a7a5a75c /drivers/cpufreq
parent3dc642a3984abb4e34b7514a5d569a50402410b7 (diff)
intel_pstate: Improve accuracy by not truncating until final result
commit d253d2a52676cfa3d89b8f0737a08ce7db665207 upstream. This patch addresses Bug 60727 (https://bugzilla.kernel.org/show_bug.cgi?id=60727) which was due to the truncation of intermediate values in the calculations, which causes the code to consistently underestimate the current cpu frequency, specifically 100% cpu utilization was truncated down to the setpoint of 97%. This patch fixes the problem by keeping the results of all intermediate calculations as fixed point numbers rather scaling them back and forth between integers and fixed point. References: https://bugzilla.kernel.org/show_bug.cgi?id=60727 Signed-off-by: Brennan Shacklett <bpshacklett@gmail.com> Acked-by: Dirk Brandewie <dirk.j.brandewie@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/intel_pstate.c33
1 files changed, 15 insertions, 18 deletions
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index ac3ff4d53baa..f82563d7a7fd 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -48,7 +48,7 @@ static inline int32_t div_fp(int32_t x, int32_t y)
48} 48}
49 49
50struct sample { 50struct sample {
51 int core_pct_busy; 51 int32_t core_pct_busy;
52 u64 aperf; 52 u64 aperf;
53 u64 mperf; 53 u64 mperf;
54 int freq; 54 int freq;
@@ -68,7 +68,7 @@ struct _pid {
68 int32_t i_gain; 68 int32_t i_gain;
69 int32_t d_gain; 69 int32_t d_gain;
70 int deadband; 70 int deadband;
71 int last_err; 71 int32_t last_err;
72}; 72};
73 73
74struct cpudata { 74struct cpudata {
@@ -153,16 +153,15 @@ static inline void pid_d_gain_set(struct _pid *pid, int percent)
153 pid->d_gain = div_fp(int_tofp(percent), int_tofp(100)); 153 pid->d_gain = div_fp(int_tofp(percent), int_tofp(100));
154} 154}
155 155
156static signed int pid_calc(struct _pid *pid, int busy) 156static signed int pid_calc(struct _pid *pid, int32_t busy)
157{ 157{
158 signed int err, result; 158 signed int result;
159 int32_t pterm, dterm, fp_error; 159 int32_t pterm, dterm, fp_error;
160 int32_t integral_limit; 160 int32_t integral_limit;
161 161
162 err = pid->setpoint - busy; 162 fp_error = int_tofp(pid->setpoint) - busy;
163 fp_error = int_tofp(err);
164 163
165 if (abs(err) <= pid->deadband) 164 if (abs(fp_error) <= int_tofp(pid->deadband))
166 return 0; 165 return 0;
167 166
168 pterm = mul_fp(pid->p_gain, fp_error); 167 pterm = mul_fp(pid->p_gain, fp_error);
@@ -176,8 +175,8 @@ static signed int pid_calc(struct _pid *pid, int busy)
176 if (pid->integral < -integral_limit) 175 if (pid->integral < -integral_limit)
177 pid->integral = -integral_limit; 176 pid->integral = -integral_limit;
178 177
179 dterm = mul_fp(pid->d_gain, (err - pid->last_err)); 178 dterm = mul_fp(pid->d_gain, fp_error - pid->last_err);
180 pid->last_err = err; 179 pid->last_err = fp_error;
181 180
182 result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm; 181 result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm;
183 182
@@ -435,8 +434,9 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
435 struct sample *sample) 434 struct sample *sample)
436{ 435{
437 u64 core_pct; 436 u64 core_pct;
438 core_pct = div64_u64(sample->aperf * 100, sample->mperf); 437 core_pct = div64_u64(int_tofp(sample->aperf * 100),
439 sample->freq = cpu->pstate.max_pstate * core_pct * 1000; 438 sample->mperf);
439 sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000);
440 440
441 sample->core_pct_busy = core_pct; 441 sample->core_pct_busy = core_pct;
442} 442}
@@ -468,22 +468,19 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
468 mod_timer_pinned(&cpu->timer, jiffies + delay); 468 mod_timer_pinned(&cpu->timer, jiffies + delay);
469} 469}
470 470
471static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu) 471static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
472{ 472{
473 int32_t busy_scaled;
474 int32_t core_busy, max_pstate, current_pstate; 473 int32_t core_busy, max_pstate, current_pstate;
475 474
476 core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy); 475 core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
477 max_pstate = int_tofp(cpu->pstate.max_pstate); 476 max_pstate = int_tofp(cpu->pstate.max_pstate);
478 current_pstate = int_tofp(cpu->pstate.current_pstate); 477 current_pstate = int_tofp(cpu->pstate.current_pstate);
479 busy_scaled = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); 478 return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
480
481 return fp_toint(busy_scaled);
482} 479}
483 480
484static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) 481static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
485{ 482{
486 int busy_scaled; 483 int32_t busy_scaled;
487 struct _pid *pid; 484 struct _pid *pid;
488 signed int ctl = 0; 485 signed int ctl = 0;
489 int steps; 486 int steps;