aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2013-08-06 13:23:11 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-09 21:24:47 -0400
commit6eed9404ab3c4baea54ce4c7e862e69df1d39f38 (patch)
tree92a27a7908110c7bba019c46e5d3427b6dee42fe
parentfe492f3f0332e23cc6ca4913e5a2ed78e1888902 (diff)
cpufreq: Use rwsem for protecting critical sections
Critical sections of the cpufreq core are protected with the help of the driver module owner's refcount, which isn't the correct approach, because it causes rmmod to return an error when some routine has updated that refcount. Let's use rwsem for this purpose instead. Only cpufreq_unregister_driver() will use write sem and everybody else will use read sem. [rjw: Subject & changelog] Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/cpufreq/cpufreq.c135
1 files changed, 57 insertions, 78 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f149e14f77c7..c9bbfeef92e3 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -91,6 +91,12 @@ static void unlock_policy_rwsem_##mode(int cpu) \
91unlock_policy_rwsem(read, cpu); 91unlock_policy_rwsem(read, cpu);
92unlock_policy_rwsem(write, cpu); 92unlock_policy_rwsem(write, cpu);
93 93
94/*
95 * rwsem to guarantee that cpufreq driver module doesn't unload during critical
96 * sections
97 */
98static DECLARE_RWSEM(cpufreq_rwsem);
99
94/* internal prototypes */ 100/* internal prototypes */
95static int __cpufreq_governor(struct cpufreq_policy *policy, 101static int __cpufreq_governor(struct cpufreq_policy *policy,
96 unsigned int event); 102 unsigned int event);
@@ -178,78 +184,46 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
178} 184}
179EXPORT_SYMBOL_GPL(get_cpu_idle_time); 185EXPORT_SYMBOL_GPL(get_cpu_idle_time);
180 186
181static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) 187struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
182{ 188{
183 struct cpufreq_policy *policy; 189 struct cpufreq_policy *policy = NULL;
184 unsigned long flags; 190 unsigned long flags;
185 191
186 if (cpu >= nr_cpu_ids) 192 if (cpufreq_disabled() || (cpu >= nr_cpu_ids))
187 goto err_out; 193 return NULL;
194
195 if (!down_read_trylock(&cpufreq_rwsem))
196 return NULL;
188 197
189 /* get the cpufreq driver */ 198 /* get the cpufreq driver */
190 read_lock_irqsave(&cpufreq_driver_lock, flags); 199 read_lock_irqsave(&cpufreq_driver_lock, flags);
191 200
192 if (!cpufreq_driver) 201 if (cpufreq_driver) {
193 goto err_out_unlock; 202 /* get the CPU */
194 203 policy = per_cpu(cpufreq_cpu_data, cpu);
195 if (!try_module_get(cpufreq_driver->owner)) 204 if (policy)
196 goto err_out_unlock; 205 kobject_get(&policy->kobj);
206 }
197 207
198 /* get the CPU */ 208 read_unlock_irqrestore(&cpufreq_driver_lock, flags);
199 policy = per_cpu(cpufreq_cpu_data, cpu);
200 209
201 if (!policy) 210 if (!policy)
202 goto err_out_put_module; 211 up_read(&cpufreq_rwsem);
203
204 if (!sysfs && !kobject_get(&policy->kobj))
205 goto err_out_put_module;
206 212
207 read_unlock_irqrestore(&cpufreq_driver_lock, flags);
208 return policy; 213 return policy;
209
210err_out_put_module:
211 module_put(cpufreq_driver->owner);
212err_out_unlock:
213 read_unlock_irqrestore(&cpufreq_driver_lock, flags);
214err_out:
215 return NULL;
216}
217
218struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
219{
220 if (cpufreq_disabled())
221 return NULL;
222
223 return __cpufreq_cpu_get(cpu, false);
224} 214}
225EXPORT_SYMBOL_GPL(cpufreq_cpu_get); 215EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
226 216
227static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
228{
229 return __cpufreq_cpu_get(cpu, true);
230}
231
232static void __cpufreq_cpu_put(struct cpufreq_policy *policy, bool sysfs)
233{
234 if (!sysfs)
235 kobject_put(&policy->kobj);
236 module_put(cpufreq_driver->owner);
237}
238
239void cpufreq_cpu_put(struct cpufreq_policy *policy) 217void cpufreq_cpu_put(struct cpufreq_policy *policy)
240{ 218{
241 if (cpufreq_disabled()) 219 if (cpufreq_disabled())
242 return; 220 return;
243 221
244 __cpufreq_cpu_put(policy, false); 222 kobject_put(&policy->kobj);
223 up_read(&cpufreq_rwsem);
245} 224}
246EXPORT_SYMBOL_GPL(cpufreq_cpu_put); 225EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
247 226
248static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *policy)
249{
250 __cpufreq_cpu_put(policy, true);
251}
252
253/********************************************************************* 227/*********************************************************************
254 * EXTERNALLY AFFECTING FREQUENCY CHANGES * 228 * EXTERNALLY AFFECTING FREQUENCY CHANGES *
255 *********************************************************************/ 229 *********************************************************************/
@@ -694,12 +668,12 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
694 struct cpufreq_policy *policy = to_policy(kobj); 668 struct cpufreq_policy *policy = to_policy(kobj);
695 struct freq_attr *fattr = to_attr(attr); 669 struct freq_attr *fattr = to_attr(attr);
696 ssize_t ret = -EINVAL; 670 ssize_t ret = -EINVAL;
697 policy = cpufreq_cpu_get_sysfs(policy->cpu); 671
698 if (!policy) 672 if (!down_read_trylock(&cpufreq_rwsem))
699 goto no_policy; 673 goto exit;
700 674
701 if (lock_policy_rwsem_read(policy->cpu) < 0) 675 if (lock_policy_rwsem_read(policy->cpu) < 0)
702 goto fail; 676 goto up_read;
703 677
704 if (fattr->show) 678 if (fattr->show)
705 ret = fattr->show(policy, buf); 679 ret = fattr->show(policy, buf);
@@ -707,9 +681,10 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
707 ret = -EIO; 681 ret = -EIO;
708 682
709 unlock_policy_rwsem_read(policy->cpu); 683 unlock_policy_rwsem_read(policy->cpu);
710fail: 684
711 cpufreq_cpu_put_sysfs(policy); 685up_read:
712no_policy: 686 up_read(&cpufreq_rwsem);
687exit:
713 return ret; 688 return ret;
714} 689}
715 690
@@ -719,12 +694,12 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
719 struct cpufreq_policy *policy = to_policy(kobj); 694 struct cpufreq_policy *policy = to_policy(kobj);
720 struct freq_attr *fattr = to_attr(attr); 695 struct freq_attr *fattr = to_attr(attr);
721 ssize_t ret = -EINVAL; 696 ssize_t ret = -EINVAL;
722 policy = cpufreq_cpu_get_sysfs(policy->cpu); 697
723 if (!policy) 698 if (!down_read_trylock(&cpufreq_rwsem))
724 goto no_policy; 699 goto exit;
725 700
726 if (lock_policy_rwsem_write(policy->cpu) < 0) 701 if (lock_policy_rwsem_write(policy->cpu) < 0)
727 goto fail; 702 goto up_read;
728 703
729 if (fattr->store) 704 if (fattr->store)
730 ret = fattr->store(policy, buf, count); 705 ret = fattr->store(policy, buf, count);
@@ -732,9 +707,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
732 ret = -EIO; 707 ret = -EIO;
733 708
734 unlock_policy_rwsem_write(policy->cpu); 709 unlock_policy_rwsem_write(policy->cpu);
735fail: 710
736 cpufreq_cpu_put_sysfs(policy); 711up_read:
737no_policy: 712 up_read(&cpufreq_rwsem);
713exit:
738 return ret; 714 return ret;
739} 715}
740 716
@@ -1003,25 +979,24 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
1003 return 0; 979 return 0;
1004 } 980 }
1005 981
982 if (!down_read_trylock(&cpufreq_rwsem))
983 return 0;
984
1006#ifdef CONFIG_HOTPLUG_CPU 985#ifdef CONFIG_HOTPLUG_CPU
1007 /* Check if this cpu was hot-unplugged earlier and has siblings */ 986 /* Check if this cpu was hot-unplugged earlier and has siblings */
1008 read_lock_irqsave(&cpufreq_driver_lock, flags); 987 read_lock_irqsave(&cpufreq_driver_lock, flags);
1009 list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { 988 list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
1010 if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { 989 if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
1011 read_unlock_irqrestore(&cpufreq_driver_lock, flags); 990 read_unlock_irqrestore(&cpufreq_driver_lock, flags);
1012 return cpufreq_add_policy_cpu(tpolicy, cpu, dev, 991 ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen);
1013 frozen); 992 up_read(&cpufreq_rwsem);
993 return ret;
1014 } 994 }
1015 } 995 }
1016 read_unlock_irqrestore(&cpufreq_driver_lock, flags); 996 read_unlock_irqrestore(&cpufreq_driver_lock, flags);
1017#endif 997#endif
1018#endif 998#endif
1019 999
1020 if (!try_module_get(cpufreq_driver->owner)) {
1021 ret = -EINVAL;
1022 goto module_out;
1023 }
1024
1025 if (frozen) 1000 if (frozen)
1026 /* Restore the saved policy when doing light-weight init */ 1001 /* Restore the saved policy when doing light-weight init */
1027 policy = cpufreq_policy_restore(cpu); 1002 policy = cpufreq_policy_restore(cpu);
@@ -1094,7 +1069,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
1094 cpufreq_init_policy(policy); 1069 cpufreq_init_policy(policy);
1095 1070
1096 kobject_uevent(&policy->kobj, KOBJ_ADD); 1071 kobject_uevent(&policy->kobj, KOBJ_ADD);
1097 module_put(cpufreq_driver->owner); 1072 up_read(&cpufreq_rwsem);
1073
1098 pr_debug("initialization complete\n"); 1074 pr_debug("initialization complete\n");
1099 1075
1100 return 0; 1076 return 0;
@@ -1112,8 +1088,8 @@ err_set_policy_cpu:
1112 per_cpu(cpufreq_policy_cpu, cpu) = -1; 1088 per_cpu(cpufreq_policy_cpu, cpu) = -1;
1113 cpufreq_policy_free(policy); 1089 cpufreq_policy_free(policy);
1114nomem_out: 1090nomem_out:
1115 module_put(cpufreq_driver->owner); 1091 up_read(&cpufreq_rwsem);
1116module_out: 1092
1117 return ret; 1093 return ret;
1118} 1094}
1119 1095
@@ -1425,10 +1401,9 @@ static unsigned int __cpufreq_get(unsigned int cpu)
1425unsigned int cpufreq_get(unsigned int cpu) 1401unsigned int cpufreq_get(unsigned int cpu)
1426{ 1402{
1427 unsigned int ret_freq = 0; 1403 unsigned int ret_freq = 0;
1428 struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
1429 1404
1430 if (!policy) 1405 if (!down_read_trylock(&cpufreq_rwsem))
1431 goto out; 1406 return 0;
1432 1407
1433 if (unlikely(lock_policy_rwsem_read(cpu))) 1408 if (unlikely(lock_policy_rwsem_read(cpu)))
1434 goto out_policy; 1409 goto out_policy;
@@ -1438,8 +1413,8 @@ unsigned int cpufreq_get(unsigned int cpu)
1438 unlock_policy_rwsem_read(cpu); 1413 unlock_policy_rwsem_read(cpu);
1439 1414
1440out_policy: 1415out_policy:
1441 cpufreq_cpu_put(policy); 1416 up_read(&cpufreq_rwsem);
1442out: 1417
1443 return ret_freq; 1418 return ret_freq;
1444} 1419}
1445EXPORT_SYMBOL(cpufreq_get); 1420EXPORT_SYMBOL(cpufreq_get);
@@ -2132,9 +2107,13 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
2132 subsys_interface_unregister(&cpufreq_interface); 2107 subsys_interface_unregister(&cpufreq_interface);
2133 unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 2108 unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
2134 2109
2110 down_write(&cpufreq_rwsem);
2135 write_lock_irqsave(&cpufreq_driver_lock, flags); 2111 write_lock_irqsave(&cpufreq_driver_lock, flags);
2112
2136 cpufreq_driver = NULL; 2113 cpufreq_driver = NULL;
2114
2137 write_unlock_irqrestore(&cpufreq_driver_lock, flags); 2115 write_unlock_irqrestore(&cpufreq_driver_lock, flags);
2116 up_write(&cpufreq_rwsem);
2138 2117
2139 return 0; 2118 return 0;
2140} 2119}