summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2015-12-03 09:37:49 +0530
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-12-07 02:20:10 +0100
commite128c864070055e062f6c90c64c03aad18452ac3 (patch)
tree42f57d730c2d84589821c80c23b0f1f56250b16d /drivers/cpufreq
parent527e9316f8ec44bd53d90fb9f611fa7ffff52bb9 (diff)
cpufreq: ondemand: Update sampling rate only for concerned policies
We are comparing policy->governor against cpufreq_gov_ondemand to make sure that we update sampling rate only for the concerned CPUs. But that isn't enough. In case of governor_per_policy, there can be multiple instances of ondemand governor and we will always end up updating all of them with current code. What we rather need to do, is to compare dbs_data with poilcy->governor_data, which will match only for the policies governed by dbs_data. This code is also racy as the governor might be getting stopped at that time and we may end up scheduling work for a policy, which we have just disabled. Fix that by protecting the entire function with &od_dbs_cdata.mutex, which will prevent against races with policy START/STOP/etc. After these locks are in place, we can safely get the policy via per-cpu dbs_info. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 03ac6ce54042..089ca6a6ca02 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -252,20 +252,39 @@ static void update_sampling_rate(struct dbs_data *dbs_data,
od_tuners->sampling_rate = new_rate = max(new_rate,
dbs_data->min_sampling_rate);
+ /*
+ * Lock governor so that governor start/stop can't execute in parallel.
+ */
+ mutex_lock(&od_dbs_cdata.mutex);
+
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy;
struct od_cpu_dbs_info_s *dbs_info;
+ struct cpu_dbs_info *cdbs;
+ struct cpu_common_dbs_info *shared;
unsigned long next_sampling, appointed_at;
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
+ dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
+ cdbs = &dbs_info->cdbs;
+ shared = cdbs->shared;
+
+ /*
+ * A valid shared and shared->policy means governor hasn't
+ * stopped or exited yet.
+ */
+ if (!shared || !shared->policy)
continue;
- if (policy->governor != &cpufreq_gov_ondemand) {
- cpufreq_cpu_put(policy);
+
+ policy = shared->policy;
+
+ /*
+ * Update sampling rate for CPUs whose policy is governed by
+ * dbs_data. In case of governor_per_policy, only a single
+ * policy will be governed by dbs_data, otherwise there can be
+ * multiple policies that are governed by the same dbs_data.
+ */
+ if (dbs_data != policy->governor_data)
continue;
- }
- dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
- cpufreq_cpu_put(policy);
if (!delayed_work_pending(&dbs_info->cdbs.dwork))
continue;
@@ -281,6 +300,8 @@ static void update_sampling_rate(struct dbs_data *dbs_data,
}
}
+
+ mutex_unlock(&od_dbs_cdata.mutex);
}
static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,