diff options
author | Nathan Zimmer <nzimmer@sgi.com> | 2013-04-04 10:53:25 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-10 07:19:26 -0400 |
commit | 5800043b2488a1c4c6e859af860644d37419d58b (patch) | |
tree | 87e64e06920fa4483c01363d5b8d59928b0082e5 | |
parent | 6eb1c377423572374518f5be93214d139d113090 (diff) |
cpufreq: convert cpufreq_driver to using RCU
We eventually would like to remove the rwlock cpufreq_driver_lock or
convert it back to a spinlock and protect the read sections with RCU.
The first step in that direction is to make cpufreq_driver use RCU.
I don't see an easy wasy to protect the cpufreq_cpu_data structure
with RCU, so I am leaving it with the rwlock for now since under
certain configs __cpufreq_cpu_get is a hot spot with 256+ cores.
[rjw: Subject, changelog, white space]
Signed-off-by: Nathan Zimmer <nzimmer@sgi.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 275 |
1 files changed, 208 insertions, 67 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0198cd0a60ce..fd97a620518d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -39,7 +39,7 @@ | |||
39 | * level driver of CPUFreq support, and its spinlock. This lock | 39 | * level driver of CPUFreq support, and its spinlock. This lock |
40 | * also protects the cpufreq_cpu_data array. | 40 | * also protects the cpufreq_cpu_data array. |
41 | */ | 41 | */ |
42 | static struct cpufreq_driver *cpufreq_driver; | 42 | static struct cpufreq_driver __rcu *cpufreq_driver; |
43 | static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); | 43 | static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); |
44 | #ifdef CONFIG_HOTPLUG_CPU | 44 | #ifdef CONFIG_HOTPLUG_CPU |
45 | /* This one keeps track of the previously set governor of a removed CPU */ | 45 | /* This one keeps track of the previously set governor of a removed CPU */ |
@@ -130,26 +130,34 @@ static DEFINE_MUTEX(cpufreq_governor_mutex); | |||
130 | 130 | ||
131 | bool have_governor_per_policy(void) | 131 | bool have_governor_per_policy(void) |
132 | { | 132 | { |
133 | return cpufreq_driver->have_governor_per_policy; | 133 | bool have_governor_per_policy; |
134 | rcu_read_lock(); | ||
135 | have_governor_per_policy = | ||
136 | rcu_dereference(cpufreq_driver)->have_governor_per_policy; | ||
137 | rcu_read_unlock(); | ||
138 | return have_governor_per_policy; | ||
134 | } | 139 | } |
135 | 140 | ||
136 | static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) | 141 | static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) |
137 | { | 142 | { |
138 | struct cpufreq_policy *data; | 143 | struct cpufreq_policy *data; |
144 | struct cpufreq_driver *driver; | ||
139 | unsigned long flags; | 145 | unsigned long flags; |
140 | 146 | ||
141 | if (cpu >= nr_cpu_ids) | 147 | if (cpu >= nr_cpu_ids) |
142 | goto err_out; | 148 | goto err_out; |
143 | 149 | ||
144 | /* get the cpufreq driver */ | 150 | /* get the cpufreq driver */ |
145 | read_lock_irqsave(&cpufreq_driver_lock, flags); | 151 | rcu_read_lock(); |
152 | driver = rcu_dereference(cpufreq_driver); | ||
146 | 153 | ||
147 | if (!cpufreq_driver) | 154 | if (!driver) |
148 | goto err_out_unlock; | 155 | goto err_out_unlock; |
149 | 156 | ||
150 | if (!try_module_get(cpufreq_driver->owner)) | 157 | if (!try_module_get(driver->owner)) |
151 | goto err_out_unlock; | 158 | goto err_out_unlock; |
152 | 159 | ||
160 | read_lock_irqsave(&cpufreq_driver_lock, flags); | ||
153 | 161 | ||
154 | /* get the CPU */ | 162 | /* get the CPU */ |
155 | data = per_cpu(cpufreq_cpu_data, cpu); | 163 | data = per_cpu(cpufreq_cpu_data, cpu); |
@@ -161,12 +169,14 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) | |||
161 | goto err_out_put_module; | 169 | goto err_out_put_module; |
162 | 170 | ||
163 | read_unlock_irqrestore(&cpufreq_driver_lock, flags); | 171 | read_unlock_irqrestore(&cpufreq_driver_lock, flags); |
172 | rcu_read_unlock(); | ||
164 | return data; | 173 | return data; |
165 | 174 | ||
166 | err_out_put_module: | 175 | err_out_put_module: |
167 | module_put(cpufreq_driver->owner); | 176 | module_put(driver->owner); |
168 | err_out_unlock: | ||
169 | read_unlock_irqrestore(&cpufreq_driver_lock, flags); | 177 | read_unlock_irqrestore(&cpufreq_driver_lock, flags); |
178 | err_out_unlock: | ||
179 | rcu_read_unlock(); | ||
170 | err_out: | 180 | err_out: |
171 | return NULL; | 181 | return NULL; |
172 | } | 182 | } |
@@ -189,7 +199,9 @@ static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs) | |||
189 | { | 199 | { |
190 | if (!sysfs) | 200 | if (!sysfs) |
191 | kobject_put(&data->kobj); | 201 | kobject_put(&data->kobj); |
192 | module_put(cpufreq_driver->owner); | 202 | rcu_read_lock(); |
203 | module_put(rcu_dereference(cpufreq_driver)->owner); | ||
204 | rcu_read_unlock(); | ||
193 | } | 205 | } |
194 | 206 | ||
195 | void cpufreq_cpu_put(struct cpufreq_policy *data) | 207 | void cpufreq_cpu_put(struct cpufreq_policy *data) |
@@ -257,7 +269,9 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy, | |||
257 | if (cpufreq_disabled()) | 269 | if (cpufreq_disabled()) |
258 | return; | 270 | return; |
259 | 271 | ||
260 | freqs->flags = cpufreq_driver->flags; | 272 | rcu_read_lock(); |
273 | freqs->flags = rcu_dereference(cpufreq_driver)->flags; | ||
274 | rcu_read_unlock(); | ||
261 | pr_debug("notification %u of frequency transition to %u kHz\n", | 275 | pr_debug("notification %u of frequency transition to %u kHz\n", |
262 | state, freqs->new); | 276 | state, freqs->new); |
263 | 277 | ||
@@ -268,7 +282,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy, | |||
268 | * which is not equal to what the cpufreq core thinks is | 282 | * which is not equal to what the cpufreq core thinks is |
269 | * "old frequency". | 283 | * "old frequency". |
270 | */ | 284 | */ |
271 | if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { | 285 | if (!(freqs->flags & CPUFREQ_CONST_LOOPS)) { |
272 | if ((policy) && (policy->cpu == freqs->cpu) && | 286 | if ((policy) && (policy->cpu == freqs->cpu) && |
273 | (policy->cur) && (policy->cur != freqs->old)) { | 287 | (policy->cur) && (policy->cur != freqs->old)) { |
274 | pr_debug("Warning: CPU frequency is" | 288 | pr_debug("Warning: CPU frequency is" |
@@ -334,11 +348,21 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, | |||
334 | struct cpufreq_governor **governor) | 348 | struct cpufreq_governor **governor) |
335 | { | 349 | { |
336 | int err = -EINVAL; | 350 | int err = -EINVAL; |
337 | 351 | struct cpufreq_driver *driver; | |
338 | if (!cpufreq_driver) | 352 | bool has_setpolicy; |
353 | bool has_target; | ||
354 | |||
355 | rcu_read_lock(); | ||
356 | driver = rcu_dereference(cpufreq_driver); | ||
357 | if (!driver) { | ||
358 | rcu_read_unlock(); | ||
339 | goto out; | 359 | goto out; |
360 | } | ||
361 | has_setpolicy = driver->setpolicy ? true : false; | ||
362 | has_target = driver->target ? true : false; | ||
363 | rcu_read_unlock(); | ||
340 | 364 | ||
341 | if (cpufreq_driver->setpolicy) { | 365 | if (has_setpolicy) { |
342 | if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { | 366 | if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { |
343 | *policy = CPUFREQ_POLICY_PERFORMANCE; | 367 | *policy = CPUFREQ_POLICY_PERFORMANCE; |
344 | err = 0; | 368 | err = 0; |
@@ -347,7 +371,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, | |||
347 | *policy = CPUFREQ_POLICY_POWERSAVE; | 371 | *policy = CPUFREQ_POLICY_POWERSAVE; |
348 | err = 0; | 372 | err = 0; |
349 | } | 373 | } |
350 | } else if (cpufreq_driver->target) { | 374 | } else if (has_target) { |
351 | struct cpufreq_governor *t; | 375 | struct cpufreq_governor *t; |
352 | 376 | ||
353 | mutex_lock(&cpufreq_governor_mutex); | 377 | mutex_lock(&cpufreq_governor_mutex); |
@@ -498,7 +522,12 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, | |||
498 | */ | 522 | */ |
499 | static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) | 523 | static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) |
500 | { | 524 | { |
501 | return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name); | 525 | ssize_t size; |
526 | rcu_read_lock(); | ||
527 | size = scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", | ||
528 | rcu_dereference(cpufreq_driver)->name); | ||
529 | rcu_read_unlock(); | ||
530 | return size; | ||
502 | } | 531 | } |
503 | 532 | ||
504 | /** | 533 | /** |
@@ -510,10 +539,13 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, | |||
510 | ssize_t i = 0; | 539 | ssize_t i = 0; |
511 | struct cpufreq_governor *t; | 540 | struct cpufreq_governor *t; |
512 | 541 | ||
513 | if (!cpufreq_driver->target) { | 542 | rcu_read_lock(); |
543 | if (!rcu_dereference(cpufreq_driver)->target) { | ||
544 | rcu_read_unlock(); | ||
514 | i += sprintf(buf, "performance powersave"); | 545 | i += sprintf(buf, "performance powersave"); |
515 | goto out; | 546 | goto out; |
516 | } | 547 | } |
548 | rcu_read_unlock(); | ||
517 | 549 | ||
518 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) { | 550 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) { |
519 | if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) | 551 | if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) |
@@ -591,9 +623,15 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) | |||
591 | static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) | 623 | static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) |
592 | { | 624 | { |
593 | unsigned int limit; | 625 | unsigned int limit; |
626 | int (*bios_limit)(int cpu, unsigned int *limit); | ||
594 | int ret; | 627 | int ret; |
595 | if (cpufreq_driver->bios_limit) { | 628 | |
596 | ret = cpufreq_driver->bios_limit(policy->cpu, &limit); | 629 | rcu_read_lock(); |
630 | bios_limit = rcu_dereference(cpufreq_driver)->bios_limit; | ||
631 | rcu_read_unlock(); | ||
632 | |||
633 | if (bios_limit) { | ||
634 | ret = bios_limit(policy->cpu, &limit); | ||
597 | if (!ret) | 635 | if (!ret) |
598 | return sprintf(buf, "%u\n", limit); | 636 | return sprintf(buf, "%u\n", limit); |
599 | } | 637 | } |
@@ -736,6 +774,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu, | |||
736 | { | 774 | { |
737 | struct cpufreq_policy new_policy; | 775 | struct cpufreq_policy new_policy; |
738 | struct freq_attr **drv_attr; | 776 | struct freq_attr **drv_attr; |
777 | struct cpufreq_driver *driver; | ||
739 | unsigned long flags; | 778 | unsigned long flags; |
740 | int ret = 0; | 779 | int ret = 0; |
741 | unsigned int j; | 780 | unsigned int j; |
@@ -747,28 +786,31 @@ static int cpufreq_add_dev_interface(unsigned int cpu, | |||
747 | return ret; | 786 | return ret; |
748 | 787 | ||
749 | /* set up files for this cpu device */ | 788 | /* set up files for this cpu device */ |
750 | drv_attr = cpufreq_driver->attr; | 789 | rcu_read_lock(); |
790 | driver = rcu_dereference(cpufreq_driver); | ||
791 | drv_attr = driver->attr; | ||
751 | while ((drv_attr) && (*drv_attr)) { | 792 | while ((drv_attr) && (*drv_attr)) { |
752 | ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); | 793 | ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); |
753 | if (ret) | 794 | if (ret) |
754 | goto err_out_kobj_put; | 795 | goto err_out_unlock; |
755 | drv_attr++; | 796 | drv_attr++; |
756 | } | 797 | } |
757 | if (cpufreq_driver->get) { | 798 | if (driver->get) { |
758 | ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); | 799 | ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); |
759 | if (ret) | 800 | if (ret) |
760 | goto err_out_kobj_put; | 801 | goto err_out_unlock; |
761 | } | 802 | } |
762 | if (cpufreq_driver->target) { | 803 | if (driver->target) { |
763 | ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); | 804 | ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); |
764 | if (ret) | 805 | if (ret) |
765 | goto err_out_kobj_put; | 806 | goto err_out_unlock; |
766 | } | 807 | } |
767 | if (cpufreq_driver->bios_limit) { | 808 | if (driver->bios_limit) { |
768 | ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); | 809 | ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); |
769 | if (ret) | 810 | if (ret) |
770 | goto err_out_kobj_put; | 811 | goto err_out_unlock; |
771 | } | 812 | } |
813 | rcu_read_unlock(); | ||
772 | 814 | ||
773 | write_lock_irqsave(&cpufreq_driver_lock, flags); | 815 | write_lock_irqsave(&cpufreq_driver_lock, flags); |
774 | for_each_cpu(j, policy->cpus) { | 816 | for_each_cpu(j, policy->cpus) { |
@@ -791,12 +833,20 @@ static int cpufreq_add_dev_interface(unsigned int cpu, | |||
791 | policy->user_policy.governor = policy->governor; | 833 | policy->user_policy.governor = policy->governor; |
792 | 834 | ||
793 | if (ret) { | 835 | if (ret) { |
836 | int (*exit)(struct cpufreq_policy *policy); | ||
837 | |||
794 | pr_debug("setting policy failed\n"); | 838 | pr_debug("setting policy failed\n"); |
795 | if (cpufreq_driver->exit) | 839 | rcu_read_lock(); |
796 | cpufreq_driver->exit(policy); | 840 | exit = rcu_dereference(cpufreq_driver)->exit; |
841 | rcu_read_unlock(); | ||
842 | if (exit) | ||
843 | exit(policy); | ||
844 | |||
797 | } | 845 | } |
798 | return ret; | 846 | return ret; |
799 | 847 | ||
848 | err_out_unlock: | ||
849 | rcu_read_unlock(); | ||
800 | err_out_kobj_put: | 850 | err_out_kobj_put: |
801 | kobject_put(&policy->kobj); | 851 | kobject_put(&policy->kobj); |
802 | wait_for_completion(&policy->kobj_unregister); | 852 | wait_for_completion(&policy->kobj_unregister); |
@@ -854,6 +904,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
854 | unsigned int j, cpu = dev->id; | 904 | unsigned int j, cpu = dev->id; |
855 | int ret = -ENOMEM; | 905 | int ret = -ENOMEM; |
856 | struct cpufreq_policy *policy; | 906 | struct cpufreq_policy *policy; |
907 | struct cpufreq_driver *driver; | ||
908 | int (*init)(struct cpufreq_policy *policy); | ||
857 | unsigned long flags; | 909 | unsigned long flags; |
858 | #ifdef CONFIG_HOTPLUG_CPU | 910 | #ifdef CONFIG_HOTPLUG_CPU |
859 | struct cpufreq_governor *gov; | 911 | struct cpufreq_governor *gov; |
@@ -888,10 +940,15 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
888 | #endif | 940 | #endif |
889 | #endif | 941 | #endif |
890 | 942 | ||
891 | if (!try_module_get(cpufreq_driver->owner)) { | 943 | rcu_read_lock(); |
944 | driver = rcu_dereference(cpufreq_driver); | ||
945 | if (!try_module_get(driver->owner)) { | ||
946 | rcu_read_unlock(); | ||
892 | ret = -EINVAL; | 947 | ret = -EINVAL; |
893 | goto module_out; | 948 | goto module_out; |
894 | } | 949 | } |
950 | init = driver->init; | ||
951 | rcu_read_unlock(); | ||
895 | 952 | ||
896 | policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); | 953 | policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); |
897 | if (!policy) | 954 | if (!policy) |
@@ -916,7 +973,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
916 | /* call driver. From then on the cpufreq must be able | 973 | /* call driver. From then on the cpufreq must be able |
917 | * to accept all calls to ->verify and ->setpolicy for this CPU | 974 | * to accept all calls to ->verify and ->setpolicy for this CPU |
918 | */ | 975 | */ |
919 | ret = cpufreq_driver->init(policy); | 976 | ret = init(policy); |
920 | if (ret) { | 977 | if (ret) { |
921 | pr_debug("initialization failed\n"); | 978 | pr_debug("initialization failed\n"); |
922 | goto err_set_policy_cpu; | 979 | goto err_set_policy_cpu; |
@@ -951,7 +1008,9 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
951 | goto err_out_unregister; | 1008 | goto err_out_unregister; |
952 | 1009 | ||
953 | kobject_uevent(&policy->kobj, KOBJ_ADD); | 1010 | kobject_uevent(&policy->kobj, KOBJ_ADD); |
954 | module_put(cpufreq_driver->owner); | 1011 | rcu_read_lock(); |
1012 | module_put(rcu_dereference(cpufreq_driver)->owner); | ||
1013 | rcu_read_unlock(); | ||
955 | pr_debug("initialization complete\n"); | 1014 | pr_debug("initialization complete\n"); |
956 | 1015 | ||
957 | return 0; | 1016 | return 0; |
@@ -973,7 +1032,9 @@ err_free_cpumask: | |||
973 | err_free_policy: | 1032 | err_free_policy: |
974 | kfree(policy); | 1033 | kfree(policy); |
975 | nomem_out: | 1034 | nomem_out: |
976 | module_put(cpufreq_driver->owner); | 1035 | rcu_read_lock(); |
1036 | module_put(rcu_dereference(cpufreq_driver)->owner); | ||
1037 | rcu_read_unlock(); | ||
977 | module_out: | 1038 | module_out: |
978 | return ret; | 1039 | return ret; |
979 | } | 1040 | } |
@@ -1007,9 +1068,12 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1007 | unsigned int cpu = dev->id, ret, cpus; | 1068 | unsigned int cpu = dev->id, ret, cpus; |
1008 | unsigned long flags; | 1069 | unsigned long flags; |
1009 | struct cpufreq_policy *data; | 1070 | struct cpufreq_policy *data; |
1071 | struct cpufreq_driver *driver; | ||
1010 | struct kobject *kobj; | 1072 | struct kobject *kobj; |
1011 | struct completion *cmp; | 1073 | struct completion *cmp; |
1012 | struct device *cpu_dev; | 1074 | struct device *cpu_dev; |
1075 | bool has_target; | ||
1076 | int (*exit)(struct cpufreq_policy *policy); | ||
1013 | 1077 | ||
1014 | pr_debug("%s: unregistering CPU %u\n", __func__, cpu); | 1078 | pr_debug("%s: unregistering CPU %u\n", __func__, cpu); |
1015 | 1079 | ||
@@ -1025,14 +1089,19 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1025 | return -EINVAL; | 1089 | return -EINVAL; |
1026 | } | 1090 | } |
1027 | 1091 | ||
1028 | if (cpufreq_driver->target) | 1092 | rcu_read_lock(); |
1093 | driver = rcu_dereference(cpufreq_driver); | ||
1094 | has_target = driver->target ? true : false; | ||
1095 | exit = driver->exit; | ||
1096 | if (has_target) | ||
1029 | __cpufreq_governor(data, CPUFREQ_GOV_STOP); | 1097 | __cpufreq_governor(data, CPUFREQ_GOV_STOP); |
1030 | 1098 | ||
1031 | #ifdef CONFIG_HOTPLUG_CPU | 1099 | #ifdef CONFIG_HOTPLUG_CPU |
1032 | if (!cpufreq_driver->setpolicy) | 1100 | if (!driver->setpolicy) |
1033 | strncpy(per_cpu(cpufreq_cpu_governor, cpu), | 1101 | strncpy(per_cpu(cpufreq_cpu_governor, cpu), |
1034 | data->governor->name, CPUFREQ_NAME_LEN); | 1102 | data->governor->name, CPUFREQ_NAME_LEN); |
1035 | #endif | 1103 | #endif |
1104 | rcu_read_unlock(); | ||
1036 | 1105 | ||
1037 | WARN_ON(lock_policy_rwsem_write(cpu)); | 1106 | WARN_ON(lock_policy_rwsem_write(cpu)); |
1038 | cpus = cpumask_weight(data->cpus); | 1107 | cpus = cpumask_weight(data->cpus); |
@@ -1091,13 +1160,13 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1091 | wait_for_completion(cmp); | 1160 | wait_for_completion(cmp); |
1092 | pr_debug("wait complete\n"); | 1161 | pr_debug("wait complete\n"); |
1093 | 1162 | ||
1094 | if (cpufreq_driver->exit) | 1163 | if (exit) |
1095 | cpufreq_driver->exit(data); | 1164 | exit(data); |
1096 | 1165 | ||
1097 | free_cpumask_var(data->related_cpus); | 1166 | free_cpumask_var(data->related_cpus); |
1098 | free_cpumask_var(data->cpus); | 1167 | free_cpumask_var(data->cpus); |
1099 | kfree(data); | 1168 | kfree(data); |
1100 | } else if (cpufreq_driver->target) { | 1169 | } else if (has_target) { |
1101 | __cpufreq_governor(data, CPUFREQ_GOV_START); | 1170 | __cpufreq_governor(data, CPUFREQ_GOV_START); |
1102 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); | 1171 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); |
1103 | } | 1172 | } |
@@ -1171,10 +1240,18 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, | |||
1171 | unsigned int cpufreq_quick_get(unsigned int cpu) | 1240 | unsigned int cpufreq_quick_get(unsigned int cpu) |
1172 | { | 1241 | { |
1173 | struct cpufreq_policy *policy; | 1242 | struct cpufreq_policy *policy; |
1243 | struct cpufreq_driver *driver; | ||
1244 | unsigned int (*get)(unsigned int cpu); | ||
1174 | unsigned int ret_freq = 0; | 1245 | unsigned int ret_freq = 0; |
1175 | 1246 | ||
1176 | if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) | 1247 | rcu_read_lock(); |
1177 | return cpufreq_driver->get(cpu); | 1248 | driver = rcu_dereference(cpufreq_driver); |
1249 | if (driver && driver->setpolicy && driver->get) { | ||
1250 | get = driver->get; | ||
1251 | rcu_read_unlock(); | ||
1252 | return get(cpu); | ||
1253 | } | ||
1254 | rcu_read_unlock(); | ||
1178 | 1255 | ||
1179 | policy = cpufreq_cpu_get(cpu); | 1256 | policy = cpufreq_cpu_get(cpu); |
1180 | if (policy) { | 1257 | if (policy) { |
@@ -1210,15 +1287,26 @@ EXPORT_SYMBOL(cpufreq_quick_get_max); | |||
1210 | static unsigned int __cpufreq_get(unsigned int cpu) | 1287 | static unsigned int __cpufreq_get(unsigned int cpu) |
1211 | { | 1288 | { |
1212 | struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); | 1289 | struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); |
1290 | struct cpufreq_driver *driver; | ||
1291 | unsigned int (*get)(unsigned int cpu); | ||
1213 | unsigned int ret_freq = 0; | 1292 | unsigned int ret_freq = 0; |
1293 | u8 flags; | ||
1294 | |||
1214 | 1295 | ||
1215 | if (!cpufreq_driver->get) | 1296 | rcu_read_lock(); |
1297 | driver = rcu_dereference(cpufreq_driver); | ||
1298 | if (!driver->get) { | ||
1299 | rcu_read_unlock(); | ||
1216 | return ret_freq; | 1300 | return ret_freq; |
1301 | } | ||
1302 | flags = driver->flags; | ||
1303 | get = driver->get; | ||
1304 | rcu_read_unlock(); | ||
1217 | 1305 | ||
1218 | ret_freq = cpufreq_driver->get(cpu); | 1306 | ret_freq = get(cpu); |
1219 | 1307 | ||
1220 | if (ret_freq && policy->cur && | 1308 | if (ret_freq && policy->cur && |
1221 | !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { | 1309 | !(flags & CPUFREQ_CONST_LOOPS)) { |
1222 | /* verify no discrepancy between actual and | 1310 | /* verify no discrepancy between actual and |
1223 | saved value exists */ | 1311 | saved value exists */ |
1224 | if (unlikely(ret_freq != policy->cur)) { | 1312 | if (unlikely(ret_freq != policy->cur)) { |
@@ -1274,6 +1362,7 @@ static struct subsys_interface cpufreq_interface = { | |||
1274 | */ | 1362 | */ |
1275 | static int cpufreq_bp_suspend(void) | 1363 | static int cpufreq_bp_suspend(void) |
1276 | { | 1364 | { |
1365 | int (*suspend)(struct cpufreq_policy *policy); | ||
1277 | int ret = 0; | 1366 | int ret = 0; |
1278 | 1367 | ||
1279 | int cpu = smp_processor_id(); | 1368 | int cpu = smp_processor_id(); |
@@ -1286,8 +1375,11 @@ static int cpufreq_bp_suspend(void) | |||
1286 | if (!cpu_policy) | 1375 | if (!cpu_policy) |
1287 | return 0; | 1376 | return 0; |
1288 | 1377 | ||
1289 | if (cpufreq_driver->suspend) { | 1378 | rcu_read_lock(); |
1290 | ret = cpufreq_driver->suspend(cpu_policy); | 1379 | suspend = rcu_dereference(cpufreq_driver)->suspend; |
1380 | rcu_read_unlock(); | ||
1381 | if (suspend) { | ||
1382 | ret = suspend(cpu_policy); | ||
1291 | if (ret) | 1383 | if (ret) |
1292 | printk(KERN_ERR "cpufreq: suspend failed in ->suspend " | 1384 | printk(KERN_ERR "cpufreq: suspend failed in ->suspend " |
1293 | "step on CPU %u\n", cpu_policy->cpu); | 1385 | "step on CPU %u\n", cpu_policy->cpu); |
@@ -1313,6 +1405,7 @@ static int cpufreq_bp_suspend(void) | |||
1313 | static void cpufreq_bp_resume(void) | 1405 | static void cpufreq_bp_resume(void) |
1314 | { | 1406 | { |
1315 | int ret = 0; | 1407 | int ret = 0; |
1408 | int (*resume)(struct cpufreq_policy *policy); | ||
1316 | 1409 | ||
1317 | int cpu = smp_processor_id(); | 1410 | int cpu = smp_processor_id(); |
1318 | struct cpufreq_policy *cpu_policy; | 1411 | struct cpufreq_policy *cpu_policy; |
@@ -1324,8 +1417,12 @@ static void cpufreq_bp_resume(void) | |||
1324 | if (!cpu_policy) | 1417 | if (!cpu_policy) |
1325 | return; | 1418 | return; |
1326 | 1419 | ||
1327 | if (cpufreq_driver->resume) { | 1420 | rcu_read_lock(); |
1328 | ret = cpufreq_driver->resume(cpu_policy); | 1421 | resume = rcu_dereference(cpufreq_driver)->resume; |
1422 | rcu_read_unlock(); | ||
1423 | |||
1424 | if (resume) { | ||
1425 | ret = resume(cpu_policy); | ||
1329 | if (ret) { | 1426 | if (ret) { |
1330 | printk(KERN_ERR "cpufreq: resume failed in ->resume " | 1427 | printk(KERN_ERR "cpufreq: resume failed in ->resume " |
1331 | "step on CPU %u\n", cpu_policy->cpu); | 1428 | "step on CPU %u\n", cpu_policy->cpu); |
@@ -1352,10 +1449,14 @@ static struct syscore_ops cpufreq_syscore_ops = { | |||
1352 | */ | 1449 | */ |
1353 | const char *cpufreq_get_current_driver(void) | 1450 | const char *cpufreq_get_current_driver(void) |
1354 | { | 1451 | { |
1355 | if (cpufreq_driver) | 1452 | struct cpufreq_driver *driver; |
1356 | return cpufreq_driver->name; | 1453 | const char *name = NULL; |
1357 | 1454 | rcu_read_lock(); | |
1358 | return NULL; | 1455 | driver = rcu_dereference(cpufreq_driver); |
1456 | if (driver) | ||
1457 | name = driver->name; | ||
1458 | rcu_read_unlock(); | ||
1459 | return name; | ||
1359 | } | 1460 | } |
1360 | EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); | 1461 | EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); |
1361 | 1462 | ||
@@ -1449,6 +1550,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, | |||
1449 | { | 1550 | { |
1450 | int retval = -EINVAL; | 1551 | int retval = -EINVAL; |
1451 | unsigned int old_target_freq = target_freq; | 1552 | unsigned int old_target_freq = target_freq; |
1553 | int (*target)(struct cpufreq_policy *policy, | ||
1554 | unsigned int target_freq, | ||
1555 | unsigned int relation); | ||
1452 | 1556 | ||
1453 | if (cpufreq_disabled()) | 1557 | if (cpufreq_disabled()) |
1454 | return -ENODEV; | 1558 | return -ENODEV; |
@@ -1465,8 +1569,11 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, | |||
1465 | if (target_freq == policy->cur) | 1569 | if (target_freq == policy->cur) |
1466 | return 0; | 1570 | return 0; |
1467 | 1571 | ||
1468 | if (cpufreq_driver->target) | 1572 | rcu_read_lock(); |
1469 | retval = cpufreq_driver->target(policy, target_freq, relation); | 1573 | target = rcu_dereference(cpufreq_driver)->target; |
1574 | rcu_read_unlock(); | ||
1575 | if (target) | ||
1576 | retval = target(policy, target_freq, relation); | ||
1470 | 1577 | ||
1471 | return retval; | 1578 | return retval; |
1472 | } | 1579 | } |
@@ -1499,18 +1606,24 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_target); | |||
1499 | int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) | 1606 | int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) |
1500 | { | 1607 | { |
1501 | int ret = 0; | 1608 | int ret = 0; |
1609 | unsigned int (*getavg)(struct cpufreq_policy *policy, | ||
1610 | unsigned int cpu); | ||
1502 | 1611 | ||
1503 | if (cpufreq_disabled()) | 1612 | if (cpufreq_disabled()) |
1504 | return ret; | 1613 | return ret; |
1505 | 1614 | ||
1506 | if (!cpufreq_driver->getavg) | 1615 | rcu_read_lock(); |
1616 | getavg = rcu_dereference(cpufreq_driver)->getavg; | ||
1617 | rcu_read_unlock(); | ||
1618 | |||
1619 | if (!getavg) | ||
1507 | return 0; | 1620 | return 0; |
1508 | 1621 | ||
1509 | policy = cpufreq_cpu_get(policy->cpu); | 1622 | policy = cpufreq_cpu_get(policy->cpu); |
1510 | if (!policy) | 1623 | if (!policy) |
1511 | return -EINVAL; | 1624 | return -EINVAL; |
1512 | 1625 | ||
1513 | ret = cpufreq_driver->getavg(policy, cpu); | 1626 | ret = getavg(policy, cpu); |
1514 | 1627 | ||
1515 | cpufreq_cpu_put(policy); | 1628 | cpufreq_cpu_put(policy); |
1516 | return ret; | 1629 | return ret; |
@@ -1668,6 +1781,9 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, | |||
1668 | struct cpufreq_policy *policy) | 1781 | struct cpufreq_policy *policy) |
1669 | { | 1782 | { |
1670 | int ret = 0, failed = 1; | 1783 | int ret = 0, failed = 1; |
1784 | struct cpufreq_driver *driver; | ||
1785 | int (*verify)(struct cpufreq_policy *policy); | ||
1786 | int (*setpolicy)(struct cpufreq_policy *policy); | ||
1671 | 1787 | ||
1672 | pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, | 1788 | pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, |
1673 | policy->min, policy->max); | 1789 | policy->min, policy->max); |
@@ -1681,7 +1797,13 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, | |||
1681 | } | 1797 | } |
1682 | 1798 | ||
1683 | /* verify the cpu speed can be set within this limit */ | 1799 | /* verify the cpu speed can be set within this limit */ |
1684 | ret = cpufreq_driver->verify(policy); | 1800 | rcu_read_lock(); |
1801 | driver = rcu_dereference(cpufreq_driver); | ||
1802 | verify = driver->verify; | ||
1803 | setpolicy = driver->setpolicy; | ||
1804 | rcu_read_unlock(); | ||
1805 | |||
1806 | ret = verify(policy); | ||
1685 | if (ret) | 1807 | if (ret) |
1686 | goto error_out; | 1808 | goto error_out; |
1687 | 1809 | ||
@@ -1695,7 +1817,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, | |||
1695 | 1817 | ||
1696 | /* verify the cpu speed can be set within this limit, | 1818 | /* verify the cpu speed can be set within this limit, |
1697 | which might be different to the first one */ | 1819 | which might be different to the first one */ |
1698 | ret = cpufreq_driver->verify(policy); | 1820 | ret = verify(policy); |
1699 | if (ret) | 1821 | if (ret) |
1700 | goto error_out; | 1822 | goto error_out; |
1701 | 1823 | ||
@@ -1709,10 +1831,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, | |||
1709 | pr_debug("new min and max freqs are %u - %u kHz\n", | 1831 | pr_debug("new min and max freqs are %u - %u kHz\n", |
1710 | data->min, data->max); | 1832 | data->min, data->max); |
1711 | 1833 | ||
1712 | if (cpufreq_driver->setpolicy) { | 1834 | if (setpolicy) { |
1713 | data->policy = policy->policy; | 1835 | data->policy = policy->policy; |
1714 | pr_debug("setting range\n"); | 1836 | pr_debug("setting range\n"); |
1715 | ret = cpufreq_driver->setpolicy(policy); | 1837 | ret = setpolicy(policy); |
1716 | } else { | 1838 | } else { |
1717 | if (policy->governor != data->governor) { | 1839 | if (policy->governor != data->governor) { |
1718 | /* save old, working values */ | 1840 | /* save old, working values */ |
@@ -1772,6 +1894,11 @@ int cpufreq_update_policy(unsigned int cpu) | |||
1772 | { | 1894 | { |
1773 | struct cpufreq_policy *data = cpufreq_cpu_get(cpu); | 1895 | struct cpufreq_policy *data = cpufreq_cpu_get(cpu); |
1774 | struct cpufreq_policy policy; | 1896 | struct cpufreq_policy policy; |
1897 | struct cpufreq_driver *driver; | ||
1898 | unsigned int (*get)(unsigned int cpu); | ||
1899 | int (*target)(struct cpufreq_policy *policy, | ||
1900 | unsigned int target_freq, | ||
1901 | unsigned int relation); | ||
1775 | int ret; | 1902 | int ret; |
1776 | 1903 | ||
1777 | if (!data) { | 1904 | if (!data) { |
@@ -1793,13 +1920,18 @@ int cpufreq_update_policy(unsigned int cpu) | |||
1793 | 1920 | ||
1794 | /* BIOS might change freq behind our back | 1921 | /* BIOS might change freq behind our back |
1795 | -> ask driver for current freq and notify governors about a change */ | 1922 | -> ask driver for current freq and notify governors about a change */ |
1796 | if (cpufreq_driver->get) { | 1923 | rcu_read_lock(); |
1797 | policy.cur = cpufreq_driver->get(cpu); | 1924 | driver = rcu_access_pointer(cpufreq_driver); |
1925 | get = driver->get; | ||
1926 | target = driver->target; | ||
1927 | rcu_read_unlock(); | ||
1928 | if (get) { | ||
1929 | policy.cur = get(cpu); | ||
1798 | if (!data->cur) { | 1930 | if (!data->cur) { |
1799 | pr_debug("Driver did not initialize current freq"); | 1931 | pr_debug("Driver did not initialize current freq"); |
1800 | data->cur = policy.cur; | 1932 | data->cur = policy.cur; |
1801 | } else { | 1933 | } else { |
1802 | if (data->cur != policy.cur && cpufreq_driver->target) | 1934 | if (data->cur != policy.cur && target) |
1803 | cpufreq_out_of_sync(cpu, data->cur, | 1935 | cpufreq_out_of_sync(cpu, data->cur, |
1804 | policy.cur); | 1936 | policy.cur); |
1805 | } | 1937 | } |
@@ -1878,18 +2010,19 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) | |||
1878 | driver_data->flags |= CPUFREQ_CONST_LOOPS; | 2010 | driver_data->flags |= CPUFREQ_CONST_LOOPS; |
1879 | 2011 | ||
1880 | write_lock_irqsave(&cpufreq_driver_lock, flags); | 2012 | write_lock_irqsave(&cpufreq_driver_lock, flags); |
1881 | if (cpufreq_driver) { | 2013 | if (rcu_access_pointer(cpufreq_driver)) { |
1882 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 2014 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
1883 | return -EBUSY; | 2015 | return -EBUSY; |
1884 | } | 2016 | } |
1885 | cpufreq_driver = driver_data; | 2017 | rcu_assign_pointer(cpufreq_driver, driver_data); |
1886 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 2018 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
2019 | synchronize_rcu(); | ||
1887 | 2020 | ||
1888 | ret = subsys_interface_register(&cpufreq_interface); | 2021 | ret = subsys_interface_register(&cpufreq_interface); |
1889 | if (ret) | 2022 | if (ret) |
1890 | goto err_null_driver; | 2023 | goto err_null_driver; |
1891 | 2024 | ||
1892 | if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { | 2025 | if (!(driver_data->flags & CPUFREQ_STICKY)) { |
1893 | int i; | 2026 | int i; |
1894 | ret = -ENODEV; | 2027 | ret = -ENODEV; |
1895 | 2028 | ||
@@ -1916,8 +2049,9 @@ err_if_unreg: | |||
1916 | subsys_interface_unregister(&cpufreq_interface); | 2049 | subsys_interface_unregister(&cpufreq_interface); |
1917 | err_null_driver: | 2050 | err_null_driver: |
1918 | write_lock_irqsave(&cpufreq_driver_lock, flags); | 2051 | write_lock_irqsave(&cpufreq_driver_lock, flags); |
1919 | cpufreq_driver = NULL; | 2052 | rcu_assign_pointer(cpufreq_driver, NULL); |
1920 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 2053 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
2054 | synchronize_rcu(); | ||
1921 | return ret; | 2055 | return ret; |
1922 | } | 2056 | } |
1923 | EXPORT_SYMBOL_GPL(cpufreq_register_driver); | 2057 | EXPORT_SYMBOL_GPL(cpufreq_register_driver); |
@@ -1934,9 +2068,15 @@ EXPORT_SYMBOL_GPL(cpufreq_register_driver); | |||
1934 | int cpufreq_unregister_driver(struct cpufreq_driver *driver) | 2068 | int cpufreq_unregister_driver(struct cpufreq_driver *driver) |
1935 | { | 2069 | { |
1936 | unsigned long flags; | 2070 | unsigned long flags; |
2071 | struct cpufreq_driver *old_driver; | ||
1937 | 2072 | ||
1938 | if (!cpufreq_driver || (driver != cpufreq_driver)) | 2073 | rcu_read_lock(); |
2074 | old_driver = rcu_access_pointer(cpufreq_driver); | ||
2075 | if (!old_driver || (driver != old_driver)) { | ||
2076 | rcu_read_unlock(); | ||
1939 | return -EINVAL; | 2077 | return -EINVAL; |
2078 | } | ||
2079 | rcu_read_unlock(); | ||
1940 | 2080 | ||
1941 | pr_debug("unregistering driver %s\n", driver->name); | 2081 | pr_debug("unregistering driver %s\n", driver->name); |
1942 | 2082 | ||
@@ -1944,8 +2084,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) | |||
1944 | unregister_hotcpu_notifier(&cpufreq_cpu_notifier); | 2084 | unregister_hotcpu_notifier(&cpufreq_cpu_notifier); |
1945 | 2085 | ||
1946 | write_lock_irqsave(&cpufreq_driver_lock, flags); | 2086 | write_lock_irqsave(&cpufreq_driver_lock, flags); |
1947 | cpufreq_driver = NULL; | 2087 | rcu_assign_pointer(cpufreq_driver, NULL); |
1948 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 2088 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
2089 | synchronize_rcu(); | ||
1949 | 2090 | ||
1950 | return 0; | 2091 | return 0; |
1951 | } | 2092 | } |