aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpufreq/cpufreq.c63
1 files changed, 31 insertions, 32 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 02d534da22dd..fab042e1ee90 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -845,8 +845,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
845 845
846#ifdef CONFIG_HOTPLUG_CPU 846#ifdef CONFIG_HOTPLUG_CPU
847static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, 847static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
848 unsigned int cpu, struct device *dev, 848 unsigned int cpu, struct device *dev)
849 bool frozen)
850{ 849{
851 int ret = 0; 850 int ret = 0;
852 unsigned long flags; 851 unsigned long flags;
@@ -877,11 +876,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
877 } 876 }
878 } 877 }
879 878
880 /* Don't touch sysfs links during light-weight init */ 879 return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
881 if (!frozen)
882 ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
883
884 return ret;
885} 880}
886#endif 881#endif
887 882
@@ -926,6 +921,27 @@ err_free_policy:
926 return NULL; 921 return NULL;
927} 922}
928 923
924static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
925{
926 struct kobject *kobj;
927 struct completion *cmp;
928
929 down_read(&policy->rwsem);
930 kobj = &policy->kobj;
931 cmp = &policy->kobj_unregister;
932 up_read(&policy->rwsem);
933 kobject_put(kobj);
934
935 /*
936 * We need to make sure that the underlying kobj is
937 * actually not referenced anymore by anybody before we
938 * proceed with unloading.
939 */
940 pr_debug("waiting for dropping of refcount\n");
941 wait_for_completion(cmp);
942 pr_debug("wait complete\n");
943}
944
929static void cpufreq_policy_free(struct cpufreq_policy *policy) 945static void cpufreq_policy_free(struct cpufreq_policy *policy)
930{ 946{
931 free_cpumask_var(policy->related_cpus); 947 free_cpumask_var(policy->related_cpus);
@@ -986,7 +1002,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
986 list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { 1002 list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
987 if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { 1003 if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
988 read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1004 read_unlock_irqrestore(&cpufreq_driver_lock, flags);
989 ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen); 1005 ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev);
990 up_read(&cpufreq_rwsem); 1006 up_read(&cpufreq_rwsem);
991 return ret; 1007 return ret;
992 } 1008 }
@@ -1096,7 +1112,10 @@ err_get_freq:
1096 if (cpufreq_driver->exit) 1112 if (cpufreq_driver->exit)
1097 cpufreq_driver->exit(policy); 1113 cpufreq_driver->exit(policy);
1098err_set_policy_cpu: 1114err_set_policy_cpu:
1115 if (frozen)
1116 cpufreq_policy_put_kobj(policy);
1099 cpufreq_policy_free(policy); 1117 cpufreq_policy_free(policy);
1118
1100nomem_out: 1119nomem_out:
1101 up_read(&cpufreq_rwsem); 1120 up_read(&cpufreq_rwsem);
1102 1121
@@ -1118,7 +1137,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
1118} 1137}
1119 1138
1120static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, 1139static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
1121 unsigned int old_cpu, bool frozen) 1140 unsigned int old_cpu)
1122{ 1141{
1123 struct device *cpu_dev; 1142 struct device *cpu_dev;
1124 int ret; 1143 int ret;
@@ -1126,10 +1145,6 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
1126 /* first sibling now owns the new sysfs dir */ 1145 /* first sibling now owns the new sysfs dir */
1127 cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); 1146 cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
1128 1147
1129 /* Don't touch sysfs files during light-weight tear-down */
1130 if (frozen)
1131 return cpu_dev->id;
1132
1133 sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); 1148 sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
1134 ret = kobject_move(&policy->kobj, &cpu_dev->kobj); 1149 ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
1135 if (ret) { 1150 if (ret) {
@@ -1196,7 +1211,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
1196 if (!frozen) 1211 if (!frozen)
1197 sysfs_remove_link(&dev->kobj, "cpufreq"); 1212 sysfs_remove_link(&dev->kobj, "cpufreq");
1198 } else if (cpus > 1) { 1213 } else if (cpus > 1) {
1199 new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); 1214 new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
1200 if (new_cpu >= 0) { 1215 if (new_cpu >= 0) {
1201 update_policy_cpu(policy, new_cpu); 1216 update_policy_cpu(policy, new_cpu);
1202 1217
@@ -1218,8 +1233,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
1218 int ret; 1233 int ret;
1219 unsigned long flags; 1234 unsigned long flags;
1220 struct cpufreq_policy *policy; 1235 struct cpufreq_policy *policy;
1221 struct kobject *kobj;
1222 struct completion *cmp;
1223 1236
1224 read_lock_irqsave(&cpufreq_driver_lock, flags); 1237 read_lock_irqsave(&cpufreq_driver_lock, flags);
1225 policy = per_cpu(cpufreq_cpu_data, cpu); 1238 policy = per_cpu(cpufreq_cpu_data, cpu);
@@ -1249,22 +1262,8 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
1249 } 1262 }
1250 } 1263 }
1251 1264
1252 if (!frozen) { 1265 if (!frozen)
1253 down_read(&policy->rwsem); 1266 cpufreq_policy_put_kobj(policy);
1254 kobj = &policy->kobj;
1255 cmp = &policy->kobj_unregister;
1256 up_read(&policy->rwsem);
1257 kobject_put(kobj);
1258
1259 /*
1260 * We need to make sure that the underlying kobj is
1261 * actually not referenced anymore by anybody before we
1262 * proceed with unloading.
1263 */
1264 pr_debug("waiting for dropping of refcount\n");
1265 wait_for_completion(cmp);
1266 pr_debug("wait complete\n");
1267 }
1268 1267
1269 /* 1268 /*
1270 * Perform the ->exit() even during light-weight tear-down, 1269 * Perform the ->exit() even during light-weight tear-down,