diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2013-01-14 08:23:03 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-01 18:01:14 -0500 |
commit | b8eed8af94f9203e0cc39245ea335f4b8dc1ed31 (patch) | |
tree | 39c9e57baa6daf91295c331c6b995c9d6286b2bc /drivers/cpufreq/cpufreq_stats.c | |
parent | f85178048c083520bd920921744dd2c4a797fbc5 (diff) |
cpufreq: Simplify __cpufreq_remove_dev()
__cpufreq_remove_dev() is called on multiple occasions: cpufreq_driver
unregister and cpu removals.
Current implementation of this routine is overly complex without much need. If
the cpu to be removed is the policy->cpu, we remove the policy first and add all
other cpus again from policy->cpus and then finally call __cpufreq_remove_dev()
again to remove the cpu to be deleted. Haahhhh..
There exist a simple solution to removal of a cpu:
- Simply use the old policy structure
- update its fields like: policy->cpu, etc.
- notify any users of cpufreq, which depend on changing policy->cpu
Hence this patch, which tries to implement the above theory. It is tested well
by myself on ARM big.LITTLE TC2 SoC, which has 5 cores (2 A15 and 3 A7). Both
A15's share same struct policy and all A7's share same policy structure.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/cpufreq_stats.c')
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 9d7732b81044..beef6b54382b 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c | |||
@@ -170,11 +170,13 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) | |||
170 | static void cpufreq_stats_free_table(unsigned int cpu) | 170 | static void cpufreq_stats_free_table(unsigned int cpu) |
171 | { | 171 | { |
172 | struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); | 172 | struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); |
173 | |||
173 | if (stat) { | 174 | if (stat) { |
175 | pr_debug("%s: Free stat table\n", __func__); | ||
174 | kfree(stat->time_in_state); | 176 | kfree(stat->time_in_state); |
175 | kfree(stat); | 177 | kfree(stat); |
178 | per_cpu(cpufreq_stats_table, cpu) = NULL; | ||
176 | } | 179 | } |
177 | per_cpu(cpufreq_stats_table, cpu) = NULL; | ||
178 | } | 180 | } |
179 | 181 | ||
180 | /* must be called early in the CPU removal sequence (before | 182 | /* must be called early in the CPU removal sequence (before |
@@ -183,8 +185,10 @@ static void cpufreq_stats_free_table(unsigned int cpu) | |||
183 | static void cpufreq_stats_free_sysfs(unsigned int cpu) | 185 | static void cpufreq_stats_free_sysfs(unsigned int cpu) |
184 | { | 186 | { |
185 | struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); | 187 | struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); |
186 | if (policy && policy->cpu == cpu) | 188 | if (policy && (cpumask_weight(policy->cpus) == 1)) { |
189 | pr_debug("%s: Free sysfs stat\n", __func__); | ||
187 | sysfs_remove_group(&policy->kobj, &stats_attr_group); | 190 | sysfs_remove_group(&policy->kobj, &stats_attr_group); |
191 | } | ||
188 | if (policy) | 192 | if (policy) |
189 | cpufreq_cpu_put(policy); | 193 | cpufreq_cpu_put(policy); |
190 | } | 194 | } |
@@ -262,6 +266,19 @@ error_get_fail: | |||
262 | return ret; | 266 | return ret; |
263 | } | 267 | } |
264 | 268 | ||
269 | static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) | ||
270 | { | ||
271 | struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, | ||
272 | policy->last_cpu); | ||
273 | |||
274 | pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n", | ||
275 | policy->cpu, policy->last_cpu); | ||
276 | per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table, | ||
277 | policy->last_cpu); | ||
278 | per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL; | ||
279 | stat->cpu = policy->cpu; | ||
280 | } | ||
281 | |||
265 | static int cpufreq_stat_notifier_policy(struct notifier_block *nb, | 282 | static int cpufreq_stat_notifier_policy(struct notifier_block *nb, |
266 | unsigned long val, void *data) | 283 | unsigned long val, void *data) |
267 | { | 284 | { |
@@ -269,6 +286,12 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, | |||
269 | struct cpufreq_policy *policy = data; | 286 | struct cpufreq_policy *policy = data; |
270 | struct cpufreq_frequency_table *table; | 287 | struct cpufreq_frequency_table *table; |
271 | unsigned int cpu = policy->cpu; | 288 | unsigned int cpu = policy->cpu; |
289 | |||
290 | if (val == CPUFREQ_UPDATE_POLICY_CPU) { | ||
291 | cpufreq_stats_update_policy_cpu(policy); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
272 | if (val != CPUFREQ_NOTIFY) | 295 | if (val != CPUFREQ_NOTIFY) |
273 | return 0; | 296 | return 0; |
274 | table = cpufreq_frequency_get_table(cpu); | 297 | table = cpufreq_frequency_get_table(cpu); |