aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrennan Shacklett <brennan@genyes.org>2013-10-21 12:20:32 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-10-21 19:15:38 -0400
commitd253d2a52676cfa3d89b8f0737a08ce7db665207 (patch)
tree0764df6b50b68dea4c7d2984b5b9e599ef12f0f8
parent31d141e3a666269a3b6fcccddb0351caf7454240 (diff)
intel_pstate: Improve accuracy by not truncating until final result
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>
-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 badf6206b2b2..8b8677f92700 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
@@ -436,8 +435,9 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
436 struct sample *sample) 435 struct sample *sample)
437{ 436{
438 u64 core_pct; 437 u64 core_pct;
439 core_pct = div64_u64(sample->aperf * 100, sample->mperf); 438 core_pct = div64_u64(int_tofp(sample->aperf * 100),
440 sample->freq = cpu->pstate.max_pstate * core_pct * 1000; 439 sample->mperf);
440 sample->freq = fp_toint(cpu->pstate.max_pstate * core_pct * 1000);
441 441
442 sample->core_pct_busy = core_pct; 442 sample->core_pct_busy = core_pct;
443} 443}
@@ -469,22 +469,19 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
469 mod_timer_pinned(&cpu->timer, jiffies + delay); 469 mod_timer_pinned(&cpu->timer, jiffies + delay);
470} 470}
471 471
472static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu) 472static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
473{ 473{
474 int32_t busy_scaled;
475 int32_t core_busy, max_pstate, current_pstate; 474 int32_t core_busy, max_pstate, current_pstate;
476 475
477 core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy); 476 core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
478 max_pstate = int_tofp(cpu->pstate.max_pstate); 477 max_pstate = int_tofp(cpu->pstate.max_pstate);
479 current_pstate = int_tofp(cpu->pstate.current_pstate); 478 current_pstate = int_tofp(cpu->pstate.current_pstate);
480 busy_scaled = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); 479 return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
481
482 return fp_toint(busy_scaled);
483} 480}
484 481
485static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) 482static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
486{ 483{
487 int busy_scaled; 484 int32_t busy_scaled;
488 struct _pid *pid; 485 struct _pid *pid;
489 signed int ctl = 0; 486 signed int ctl = 0;
490 int steps; 487 int steps;