aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-10-12 15:47:03 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-10-13 08:42:06 -0400
commitabb6627910a1e783c8e034b35b7c80e5e7f98f41 (patch)
treec346d3f1add775bacbec9e0dc51f8f3e88ecfec7 /drivers/cpufreq
parent899bb6642f2a2f2cd3f77abd6c5a14550e3b37e6 (diff)
cpufreq: conservative: Fix next frequency selection
Commit d352cf47d93e (cpufreq: conservative: Do not use transition notifications) overlooked the case when the "frequency step" used by the conservative governor is small relative to the distances between the available frequencies and broke the algorithm by using policy->cur instead of the previously requested frequency when computing the next one. As a result, the governor may not be able to go outside of a narrow range between two consecutive available frequencies. Fix the problem by making the governor save the previously requested frequency and select the next one relative that value (unless it is out of range, in which case policy->cur will be used instead). Fixes: d352cf47d93e (cpufreq: conservative: Do not use transition notifications) Link: https://bugzilla.kernel.org/show_bug.cgi?id=177171 Reported-and-tested-by: Aleksey Rybalkin <aleksey@rybalkin.org> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Cc: 4.8+ <stable@vger.kernel.org> # 4.8+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 18da4f8051d3..13475890d792 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -17,6 +17,7 @@
17struct cs_policy_dbs_info { 17struct cs_policy_dbs_info {
18 struct policy_dbs_info policy_dbs; 18 struct policy_dbs_info policy_dbs;
19 unsigned int down_skip; 19 unsigned int down_skip;
20 unsigned int requested_freq;
20}; 21};
21 22
22static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs) 23static 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)
61{ 62{
62 struct policy_dbs_info *policy_dbs = policy->governor_data; 63 struct policy_dbs_info *policy_dbs = policy->governor_data;
63 struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs); 64 struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
65 unsigned int requested_freq = dbs_info->requested_freq;
64 struct dbs_data *dbs_data = policy_dbs->dbs_data; 66 struct dbs_data *dbs_data = policy_dbs->dbs_data;
65 struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; 67 struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
66 unsigned int load = dbs_update(policy); 68 unsigned int load = dbs_update(policy);
@@ -72,10 +74,16 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
72 if (cs_tuners->freq_step == 0) 74 if (cs_tuners->freq_step == 0)
73 goto out; 75 goto out;
74 76
77 /*
78 * If requested_freq is out of range, it is likely that the limits
79 * changed in the meantime, so fall back to current frequency in that
80 * case.
81 */
82 if (requested_freq > policy->max || requested_freq < policy->min)
83 requested_freq = policy->cur;
84
75 /* Check for frequency increase */ 85 /* Check for frequency increase */
76 if (load > dbs_data->up_threshold) { 86 if (load > dbs_data->up_threshold) {
77 unsigned int requested_freq = policy->cur;
78
79 dbs_info->down_skip = 0; 87 dbs_info->down_skip = 0;
80 88
81 /* if we are already at full speed then break out early */ 89 /* 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)
83 goto out; 91 goto out;
84 92
85 requested_freq += get_freq_target(cs_tuners, policy); 93 requested_freq += get_freq_target(cs_tuners, policy);
94 if (requested_freq > policy->max)
95 requested_freq = policy->max;
86 96
87 __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H); 97 __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H);
98 dbs_info->requested_freq = requested_freq;
88 goto out; 99 goto out;
89 } 100 }
90 101
@@ -95,7 +106,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
95 106
96 /* Check for frequency decrease */ 107 /* Check for frequency decrease */
97 if (load < cs_tuners->down_threshold) { 108 if (load < cs_tuners->down_threshold) {
98 unsigned int freq_target, requested_freq = policy->cur; 109 unsigned int freq_target;
99 /* 110 /*
100 * if we cannot reduce the frequency anymore, break out early 111 * if we cannot reduce the frequency anymore, break out early
101 */ 112 */
@@ -109,6 +120,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
109 requested_freq = policy->min; 120 requested_freq = policy->min;
110 121
111 __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L); 122 __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L);
123 dbs_info->requested_freq = requested_freq;
112 } 124 }
113 125
114 out: 126 out:
@@ -287,6 +299,7 @@ static void cs_start(struct cpufreq_policy *policy)
287 struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data); 299 struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
288 300
289 dbs_info->down_skip = 0; 301 dbs_info->down_skip = 0;
302 dbs_info->requested_freq = policy->cur;
290} 303}
291 304
292static struct dbs_governor cs_governor = { 305static struct dbs_governor cs_governor = {