aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-03 19:19:34 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-07 17:02:50 -0400
commit71c3461ef7c67024792d283b88630245a6c169ba (patch)
treec8b39798b85731763bc3a2f9fd72b57a18a864b5
parent308b60e71541518f3fe97171b4daf71adc607f3d (diff)
cpufreq: Do not hold driver module references for additional policy CPUs
The cpufreq core is a little inconsistent in the way it uses the driver module refcount. Namely, if __cpufreq_add_dev() is called for a CPU that doesn't share the policy object with any other CPUs, the driver module refcount it grabs to start with will be dropped by it before returning and will be equal to whatever it had been before that function was invoked. However, if the given CPU does share the policy object with other CPUs, either cpufreq_add_policy_cpu() is called to link the new CPU to the existing policy, or cpufreq_add_dev_symlink() is used to link the other CPUs sharing the policy with it to the just created policy object. In that case, because both cpufreq_add_policy_cpu() and cpufreq_add_dev_symlink() call cpufreq_cpu_get() for the given policy (the latter possibly many times) without the balancing cpufreq_cpu_put() (unless there is an error), the driver module refcount will be left by __cpufreq_add_dev() with a nonzero value (different from the initial one). To remove that inconsistency make cpufreq_add_policy_cpu() execute cpufreq_cpu_put() for the given policy before returning, which decrements the driver module refcount so that it will be equal to its initial value after __cpufreq_add_dev() returns. Also remove the cpufreq_cpu_get() call from cpufreq_add_dev_symlink(), since both the policy refcount and the driver module refcount are nonzero when it is called and they don't need to be bumped up by it. Accordingly, drop the cpufreq_cpu_put() from __cpufreq_remove_dev(), since it is only necessary to balance the cpufreq_cpu_get() called by cpufreq_add_policy_cpu() or cpufreq_add_dev_symlink(). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
-rw-r--r--drivers/cpufreq/cpufreq.c28
1 files changed, 7 insertions, 21 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 576b312645a5..c8b2ca0f44ae 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -818,14 +818,11 @@ static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
818 continue; 818 continue;
819 819
820 pr_debug("Adding link for CPU: %u\n", j); 820 pr_debug("Adding link for CPU: %u\n", j);
821 cpufreq_cpu_get(policy->cpu);
822 cpu_dev = get_cpu_device(j); 821 cpu_dev = get_cpu_device(j);
823 ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, 822 ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
824 "cpufreq"); 823 "cpufreq");
825 if (ret) { 824 if (ret)
826 cpufreq_cpu_put(policy); 825 break;
827 return ret;
828 }
829 } 826 }
830 return ret; 827 return ret;
831} 828}
@@ -908,7 +905,8 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
908 unsigned long flags; 905 unsigned long flags;
909 906
910 policy = cpufreq_cpu_get(sibling); 907 policy = cpufreq_cpu_get(sibling);
911 WARN_ON(!policy); 908 if (WARN_ON_ONCE(!policy))
909 return -ENODATA;
912 910
913 if (has_target) 911 if (has_target)
914 __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 912 __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
@@ -930,16 +928,10 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
930 } 928 }
931 929
932 /* Don't touch sysfs links during light-weight init */ 930 /* Don't touch sysfs links during light-weight init */
933 if (frozen) { 931 if (!frozen)
934 /* Drop the extra refcount that we took above */ 932 ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
935 cpufreq_cpu_put(policy);
936 return 0;
937 }
938
939 ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
940 if (ret)
941 cpufreq_cpu_put(policy);
942 933
934 cpufreq_cpu_put(policy);
943 return ret; 935 return ret;
944} 936}
945#endif 937#endif
@@ -1298,12 +1290,6 @@ static int __cpufreq_remove_dev(struct device *dev,
1298 if (!frozen) 1290 if (!frozen)
1299 cpufreq_policy_free(data); 1291 cpufreq_policy_free(data);
1300 } else { 1292 } else {
1301
1302 if (!frozen) {
1303 pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
1304 cpufreq_cpu_put(data);
1305 }
1306
1307 if (cpufreq_driver->target) { 1293 if (cpufreq_driver->target) {
1308 __cpufreq_governor(data, CPUFREQ_GOV_START); 1294 __cpufreq_governor(data, CPUFREQ_GOV_START);
1309 __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 1295 __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);