diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-09-12 07:04:11 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-09-12 07:04:11 -0400 |
commit | f1728fd1599112239ed5cebc7be9810264db6792 (patch) | |
tree | de36bb207a71db98c7170b57c557017e340831b7 | |
parent | 0df03a30c333d67ee9b4c37f32d423624f48fe05 (diff) | |
parent | 44871c9c7f7963f8869dd8bc9620221c9e9db153 (diff) |
Merge branch 'pm-cpufreq'
* pm-cpufreq:
cpufreq: Acquire the lock in cpufreq_policy_restore() for reading
cpufreq: Prevent problems in update_policy_cpu() if last_cpu == new_cpu
cpufreq: Restructure if/else block to avoid unintended behavior
cpufreq: Fix crash in cpufreq-stats during suspend/resume
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5a64f66d36e0..43c24aa756f6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -906,11 +906,11 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) | |||
906 | struct cpufreq_policy *policy; | 906 | struct cpufreq_policy *policy; |
907 | unsigned long flags; | 907 | unsigned long flags; |
908 | 908 | ||
909 | write_lock_irqsave(&cpufreq_driver_lock, flags); | 909 | read_lock_irqsave(&cpufreq_driver_lock, flags); |
910 | 910 | ||
911 | policy = per_cpu(cpufreq_cpu_data_fallback, cpu); | 911 | policy = per_cpu(cpufreq_cpu_data_fallback, cpu); |
912 | 912 | ||
913 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 913 | read_unlock_irqrestore(&cpufreq_driver_lock, flags); |
914 | 914 | ||
915 | return policy; | 915 | return policy; |
916 | } | 916 | } |
@@ -947,6 +947,21 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) | |||
947 | kfree(policy); | 947 | kfree(policy); |
948 | } | 948 | } |
949 | 949 | ||
950 | static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) | ||
951 | { | ||
952 | if (cpu == policy->cpu) | ||
953 | return; | ||
954 | |||
955 | policy->last_cpu = policy->cpu; | ||
956 | policy->cpu = cpu; | ||
957 | |||
958 | #ifdef CONFIG_CPU_FREQ_TABLE | ||
959 | cpufreq_frequency_table_update_policy_cpu(policy); | ||
960 | #endif | ||
961 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, | ||
962 | CPUFREQ_UPDATE_POLICY_CPU, policy); | ||
963 | } | ||
964 | |||
950 | static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, | 965 | static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, |
951 | bool frozen) | 966 | bool frozen) |
952 | { | 967 | { |
@@ -1000,7 +1015,18 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, | |||
1000 | if (!policy) | 1015 | if (!policy) |
1001 | goto nomem_out; | 1016 | goto nomem_out; |
1002 | 1017 | ||
1003 | policy->cpu = cpu; | 1018 | |
1019 | /* | ||
1020 | * In the resume path, since we restore a saved policy, the assignment | ||
1021 | * to policy->cpu is like an update of the existing policy, rather than | ||
1022 | * the creation of a brand new one. So we need to perform this update | ||
1023 | * by invoking update_policy_cpu(). | ||
1024 | */ | ||
1025 | if (frozen && cpu != policy->cpu) | ||
1026 | update_policy_cpu(policy, cpu); | ||
1027 | else | ||
1028 | policy->cpu = cpu; | ||
1029 | |||
1004 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | 1030 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; |
1005 | cpumask_copy(policy->cpus, cpumask_of(cpu)); | 1031 | cpumask_copy(policy->cpus, cpumask_of(cpu)); |
1006 | 1032 | ||
@@ -1092,18 +1118,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
1092 | return __cpufreq_add_dev(dev, sif, false); | 1118 | return __cpufreq_add_dev(dev, sif, false); |
1093 | } | 1119 | } |
1094 | 1120 | ||
1095 | static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) | ||
1096 | { | ||
1097 | policy->last_cpu = policy->cpu; | ||
1098 | policy->cpu = cpu; | ||
1099 | |||
1100 | #ifdef CONFIG_CPU_FREQ_TABLE | ||
1101 | cpufreq_frequency_table_update_policy_cpu(policy); | ||
1102 | #endif | ||
1103 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, | ||
1104 | CPUFREQ_UPDATE_POLICY_CPU, policy); | ||
1105 | } | ||
1106 | |||
1107 | static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, | 1121 | static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, |
1108 | unsigned int old_cpu, bool frozen) | 1122 | unsigned int old_cpu, bool frozen) |
1109 | { | 1123 | { |
@@ -1182,8 +1196,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
1182 | cpumask_clear_cpu(cpu, policy->cpus); | 1196 | cpumask_clear_cpu(cpu, policy->cpus); |
1183 | unlock_policy_rwsem_write(cpu); | 1197 | unlock_policy_rwsem_write(cpu); |
1184 | 1198 | ||
1185 | if (cpu != policy->cpu && !frozen) { | 1199 | if (cpu != policy->cpu) { |
1186 | sysfs_remove_link(&dev->kobj, "cpufreq"); | 1200 | if (!frozen) |
1201 | sysfs_remove_link(&dev->kobj, "cpufreq"); | ||
1187 | } else if (cpus > 1) { | 1202 | } else if (cpus > 1) { |
1188 | 1203 | ||
1189 | new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); | 1204 | new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); |