summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorPeter Boonstoppel <pboonstoppel@nvidia.com>2012-03-01 16:04:27 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2012-07-17 13:44:36 +0530
commitd7265cee28c83ad51444894f61da2ec8ab9bf993 (patch)
treeaf821f2d6110da9c8e045fa3848536dcd0d8a376 /drivers/cpufreq
parenta89f58d995bb7fafc73d10a41509d4b2edc55725 (diff)
cpufreq: protect cpufreq_stats_free_table with spinlock
Prevents crash on cpufreq_stat_notifier_trans when cpufreq_stats_table has been freed due to a core being hotplugged out. Bug 948348 Change-Id: I2640a9a23c9a79cad8c76bfefd243a07162d2004 Signed-off-by: Peter Boonstoppel <pboonstoppel@nvidia.com> (cherry picked from commit 03070a4b0b8eb74825c99c6bbfb108ddb36a041c) Reviewed-on: http://git-master/r/114248 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq_stats.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 9a1341e9a02e..63c9d568d8a2 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -59,6 +59,11 @@ static int cpufreq_stats_update(unsigned int cpu)
cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, cpu);
+ if (!stat) {
+ spin_unlock(&cpufreq_stats_lock);
+ return 0;
+ }
+
if (stat->time_in_state && stat->last_index >= 0)
stat->time_in_state[stat->last_index] +=
cur_time - stat->last_time;
@@ -169,12 +174,17 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
*/
static void cpufreq_stats_free_table(unsigned int cpu)
{
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+ struct cpufreq_stats *stat;
+
+ spin_lock(&cpufreq_stats_lock);
+ stat = per_cpu(cpufreq_stats_table, cpu);
+ per_cpu(cpufreq_stats_table, cpu) = NULL;
+ spin_unlock(&cpufreq_stats_lock);
+
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
- per_cpu(cpufreq_stats_table, cpu) = NULL;
}
/* must be called early in the CPU removal sequence (before
@@ -298,19 +308,23 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
if (val != CPUFREQ_POSTCHANGE)
return 0;
+ cpufreq_stats_update(freq->cpu);
+
+ spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, freq->cpu);
- if (!stat)
+ if (!stat) {
+ spin_unlock(&cpufreq_stats_lock);
return 0;
+ }
old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
- cpufreq_stats_update(freq->cpu);
-
- if (old_index == new_index)
+ if (old_index == new_index) {
+ spin_unlock(&cpufreq_stats_lock);
return 0;
+ }
- spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
if (old_index >= 0 && new_index >= 0)