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); |
