diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 72 |
1 files changed, 38 insertions, 34 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7cbf1d53804f..e000f3691661 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -59,8 +59,6 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock); | |||
59 | * mode before doing so. | 59 | * mode before doing so. |
60 | * | 60 | * |
61 | * Additional rules: | 61 | * Additional rules: |
62 | * - All holders of the lock should check to make sure that the CPU they | ||
63 | * are concerned with are online after they get the lock. | ||
64 | * - Governor routines that can be called in cpufreq hotplug path should not | 62 | * - Governor routines that can be called in cpufreq hotplug path should not |
65 | * take this sem as top level hotplug notifier handler takes this. | 63 | * take this sem as top level hotplug notifier handler takes this. |
66 | * - Lock should not be held across | 64 | * - Lock should not be held across |
@@ -257,6 +255,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) | |||
257 | void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) | 255 | void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) |
258 | { | 256 | { |
259 | struct cpufreq_policy *policy; | 257 | struct cpufreq_policy *policy; |
258 | unsigned long flags; | ||
260 | 259 | ||
261 | BUG_ON(irqs_disabled()); | 260 | BUG_ON(irqs_disabled()); |
262 | 261 | ||
@@ -267,7 +266,10 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) | |||
267 | pr_debug("notification %u of frequency transition to %u kHz\n", | 266 | pr_debug("notification %u of frequency transition to %u kHz\n", |
268 | state, freqs->new); | 267 | state, freqs->new); |
269 | 268 | ||
269 | spin_lock_irqsave(&cpufreq_driver_lock, flags); | ||
270 | policy = per_cpu(cpufreq_cpu_data, freqs->cpu); | 270 | policy = per_cpu(cpufreq_cpu_data, freqs->cpu); |
271 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
272 | |||
271 | switch (state) { | 273 | switch (state) { |
272 | 274 | ||
273 | case CPUFREQ_PRECHANGE: | 275 | case CPUFREQ_PRECHANGE: |
@@ -808,22 +810,22 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, | |||
808 | policy = cpufreq_cpu_get(sibling); | 810 | policy = cpufreq_cpu_get(sibling); |
809 | WARN_ON(!policy); | 811 | WARN_ON(!policy); |
810 | 812 | ||
811 | per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; | ||
812 | |||
813 | lock_policy_rwsem_write(cpu); | ||
814 | |||
815 | __cpufreq_governor(policy, CPUFREQ_GOV_STOP); | 813 | __cpufreq_governor(policy, CPUFREQ_GOV_STOP); |
816 | 814 | ||
815 | lock_policy_rwsem_write(sibling); | ||
816 | |||
817 | spin_lock_irqsave(&cpufreq_driver_lock, flags); | 817 | spin_lock_irqsave(&cpufreq_driver_lock, flags); |
818 | |||
818 | cpumask_set_cpu(cpu, policy->cpus); | 819 | cpumask_set_cpu(cpu, policy->cpus); |
820 | per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; | ||
819 | per_cpu(cpufreq_cpu_data, cpu) = policy; | 821 | per_cpu(cpufreq_cpu_data, cpu) = policy; |
820 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | 822 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); |
821 | 823 | ||
824 | unlock_policy_rwsem_write(sibling); | ||
825 | |||
822 | __cpufreq_governor(policy, CPUFREQ_GOV_START); | 826 | __cpufreq_governor(policy, CPUFREQ_GOV_START); |
823 | __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); | 827 | __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); |
824 | 828 | ||
825 | unlock_policy_rwsem_write(cpu); | ||
826 | |||
827 | ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); | 829 | ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); |
828 | if (ret) { | 830 | if (ret) { |
829 | cpufreq_cpu_put(policy); | 831 | cpufreq_cpu_put(policy); |
@@ -870,11 +872,15 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
870 | 872 | ||
871 | #ifdef CONFIG_HOTPLUG_CPU | 873 | #ifdef CONFIG_HOTPLUG_CPU |
872 | /* Check if this cpu was hot-unplugged earlier and has siblings */ | 874 | /* Check if this cpu was hot-unplugged earlier and has siblings */ |
875 | spin_lock_irqsave(&cpufreq_driver_lock, flags); | ||
873 | for_each_online_cpu(sibling) { | 876 | for_each_online_cpu(sibling) { |
874 | struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); | 877 | struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); |
875 | if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) | 878 | if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { |
879 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
876 | return cpufreq_add_policy_cpu(cpu, sibling, dev); | 880 | return cpufreq_add_policy_cpu(cpu, sibling, dev); |
881 | } | ||
877 | } | 882 | } |
883 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
878 | #endif | 884 | #endif |
879 | #endif | 885 | #endif |
880 | 886 | ||
@@ -899,8 +905,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
899 | 905 | ||
900 | /* Initially set CPU itself as the policy_cpu */ | 906 | /* Initially set CPU itself as the policy_cpu */ |
901 | per_cpu(cpufreq_policy_cpu, cpu) = cpu; | 907 | per_cpu(cpufreq_policy_cpu, cpu) = cpu; |
902 | ret = (lock_policy_rwsem_write(cpu) < 0); | ||
903 | WARN_ON(ret); | ||
904 | 908 | ||
905 | init_completion(&policy->kobj_unregister); | 909 | init_completion(&policy->kobj_unregister); |
906 | INIT_WORK(&policy->update, handle_update); | 910 | INIT_WORK(&policy->update, handle_update); |
@@ -911,7 +915,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
911 | ret = cpufreq_driver->init(policy); | 915 | ret = cpufreq_driver->init(policy); |
912 | if (ret) { | 916 | if (ret) { |
913 | pr_debug("initialization failed\n"); | 917 | pr_debug("initialization failed\n"); |
914 | goto err_unlock_policy; | 918 | goto err_set_policy_cpu; |
915 | } | 919 | } |
916 | 920 | ||
917 | /* related cpus should atleast have policy->cpus */ | 921 | /* related cpus should atleast have policy->cpus */ |
@@ -942,8 +946,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
942 | if (ret) | 946 | if (ret) |
943 | goto err_out_unregister; | 947 | goto err_out_unregister; |
944 | 948 | ||
945 | unlock_policy_rwsem_write(cpu); | ||
946 | |||
947 | kobject_uevent(&policy->kobj, KOBJ_ADD); | 949 | kobject_uevent(&policy->kobj, KOBJ_ADD); |
948 | module_put(cpufreq_driver->owner); | 950 | module_put(cpufreq_driver->owner); |
949 | pr_debug("initialization complete\n"); | 951 | pr_debug("initialization complete\n"); |
@@ -959,8 +961,8 @@ err_out_unregister: | |||
959 | kobject_put(&policy->kobj); | 961 | kobject_put(&policy->kobj); |
960 | wait_for_completion(&policy->kobj_unregister); | 962 | wait_for_completion(&policy->kobj_unregister); |
961 | 963 | ||
962 | err_unlock_policy: | 964 | err_set_policy_cpu: |
963 | unlock_policy_rwsem_write(cpu); | 965 | per_cpu(cpufreq_policy_cpu, cpu) = -1; |
964 | free_cpumask_var(policy->related_cpus); | 966 | free_cpumask_var(policy->related_cpus); |
965 | err_free_cpumask: | 967 | err_free_cpumask: |
966 | free_cpumask_var(policy->cpus); | 968 | free_cpumask_var(policy->cpus); |
@@ -1008,12 +1010,14 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1008 | pr_debug("%s: unregistering CPU %u\n", __func__, cpu); | 1010 | pr_debug("%s: unregistering CPU %u\n", __func__, cpu); |
1009 | 1011 | ||
1010 | spin_lock_irqsave(&cpufreq_driver_lock, flags); | 1012 | spin_lock_irqsave(&cpufreq_driver_lock, flags); |
1013 | |||
1011 | data = per_cpu(cpufreq_cpu_data, cpu); | 1014 | data = per_cpu(cpufreq_cpu_data, cpu); |
1015 | per_cpu(cpufreq_cpu_data, cpu) = NULL; | ||
1016 | |||
1017 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
1012 | 1018 | ||
1013 | if (!data) { | 1019 | if (!data) { |
1014 | pr_debug("%s: No cpu_data found\n", __func__); | 1020 | pr_debug("%s: No cpu_data found\n", __func__); |
1015 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
1016 | unlock_policy_rwsem_write(cpu); | ||
1017 | return -EINVAL; | 1021 | return -EINVAL; |
1018 | } | 1022 | } |
1019 | 1023 | ||
@@ -1025,9 +1029,10 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1025 | CPUFREQ_NAME_LEN); | 1029 | CPUFREQ_NAME_LEN); |
1026 | #endif | 1030 | #endif |
1027 | 1031 | ||
1028 | per_cpu(cpufreq_cpu_data, cpu) = NULL; | 1032 | WARN_ON(lock_policy_rwsem_write(cpu)); |
1029 | cpus = cpumask_weight(data->cpus); | 1033 | cpus = cpumask_weight(data->cpus); |
1030 | cpumask_clear_cpu(cpu, data->cpus); | 1034 | cpumask_clear_cpu(cpu, data->cpus); |
1035 | unlock_policy_rwsem_write(cpu); | ||
1031 | 1036 | ||
1032 | if (cpu != data->cpu) { | 1037 | if (cpu != data->cpu) { |
1033 | sysfs_remove_link(&dev->kobj, "cpufreq"); | 1038 | sysfs_remove_link(&dev->kobj, "cpufreq"); |
@@ -1038,31 +1043,37 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1038 | ret = kobject_move(&data->kobj, &cpu_dev->kobj); | 1043 | ret = kobject_move(&data->kobj, &cpu_dev->kobj); |
1039 | if (ret) { | 1044 | if (ret) { |
1040 | pr_err("%s: Failed to move kobj: %d", __func__, ret); | 1045 | pr_err("%s: Failed to move kobj: %d", __func__, ret); |
1046 | |||
1047 | WARN_ON(lock_policy_rwsem_write(cpu)); | ||
1041 | cpumask_set_cpu(cpu, data->cpus); | 1048 | cpumask_set_cpu(cpu, data->cpus); |
1042 | ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, | 1049 | |
1043 | "cpufreq"); | 1050 | spin_lock_irqsave(&cpufreq_driver_lock, flags); |
1051 | per_cpu(cpufreq_cpu_data, cpu) = data; | ||
1044 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | 1052 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); |
1053 | |||
1045 | unlock_policy_rwsem_write(cpu); | 1054 | unlock_policy_rwsem_write(cpu); |
1055 | |||
1056 | ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, | ||
1057 | "cpufreq"); | ||
1046 | return -EINVAL; | 1058 | return -EINVAL; |
1047 | } | 1059 | } |
1048 | 1060 | ||
1061 | WARN_ON(lock_policy_rwsem_write(cpu)); | ||
1049 | update_policy_cpu(data, cpu_dev->id); | 1062 | update_policy_cpu(data, cpu_dev->id); |
1063 | unlock_policy_rwsem_write(cpu); | ||
1050 | pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", | 1064 | pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", |
1051 | __func__, cpu_dev->id, cpu); | 1065 | __func__, cpu_dev->id, cpu); |
1052 | } | 1066 | } |
1053 | 1067 | ||
1054 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
1055 | |||
1056 | pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); | 1068 | pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); |
1057 | cpufreq_cpu_put(data); | 1069 | cpufreq_cpu_put(data); |
1058 | unlock_policy_rwsem_write(cpu); | ||
1059 | 1070 | ||
1060 | /* If cpu is last user of policy, free policy */ | 1071 | /* If cpu is last user of policy, free policy */ |
1061 | if (cpus == 1) { | 1072 | if (cpus == 1) { |
1062 | lock_policy_rwsem_write(cpu); | 1073 | lock_policy_rwsem_read(cpu); |
1063 | kobj = &data->kobj; | 1074 | kobj = &data->kobj; |
1064 | cmp = &data->kobj_unregister; | 1075 | cmp = &data->kobj_unregister; |
1065 | unlock_policy_rwsem_write(cpu); | 1076 | unlock_policy_rwsem_read(cpu); |
1066 | kobject_put(kobj); | 1077 | kobject_put(kobj); |
1067 | 1078 | ||
1068 | /* we need to make sure that the underlying kobj is actually | 1079 | /* we need to make sure that the underlying kobj is actually |
@@ -1073,10 +1084,8 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1073 | wait_for_completion(cmp); | 1084 | wait_for_completion(cmp); |
1074 | pr_debug("wait complete\n"); | 1085 | pr_debug("wait complete\n"); |
1075 | 1086 | ||
1076 | lock_policy_rwsem_write(cpu); | ||
1077 | if (cpufreq_driver->exit) | 1087 | if (cpufreq_driver->exit) |
1078 | cpufreq_driver->exit(data); | 1088 | cpufreq_driver->exit(data); |
1079 | unlock_policy_rwsem_write(cpu); | ||
1080 | 1089 | ||
1081 | free_cpumask_var(data->related_cpus); | 1090 | free_cpumask_var(data->related_cpus); |
1082 | free_cpumask_var(data->cpus); | 1091 | free_cpumask_var(data->cpus); |
@@ -1086,6 +1095,7 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif | |||
1086 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); | 1095 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); |
1087 | } | 1096 | } |
1088 | 1097 | ||
1098 | per_cpu(cpufreq_policy_cpu, cpu) = -1; | ||
1089 | return 0; | 1099 | return 0; |
1090 | } | 1100 | } |
1091 | 1101 | ||
@@ -1098,9 +1108,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) | |||
1098 | if (cpu_is_offline(cpu)) | 1108 | if (cpu_is_offline(cpu)) |
1099 | return 0; | 1109 | return 0; |
1100 | 1110 | ||
1101 | if (unlikely(lock_policy_rwsem_write(cpu))) | ||
1102 | BUG(); | ||
1103 | |||
1104 | retval = __cpufreq_remove_dev(dev, sif); | 1111 | retval = __cpufreq_remove_dev(dev, sif); |
1105 | return retval; | 1112 | return retval; |
1106 | } | 1113 | } |
@@ -1791,9 +1798,6 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, | |||
1791 | break; | 1798 | break; |
1792 | case CPU_DOWN_PREPARE: | 1799 | case CPU_DOWN_PREPARE: |
1793 | case CPU_DOWN_PREPARE_FROZEN: | 1800 | case CPU_DOWN_PREPARE_FROZEN: |
1794 | if (unlikely(lock_policy_rwsem_write(cpu))) | ||
1795 | BUG(); | ||
1796 | |||
1797 | __cpufreq_remove_dev(dev, NULL); | 1801 | __cpufreq_remove_dev(dev, NULL); |
1798 | break; | 1802 | break; |
1799 | case CPU_DOWN_FAILED: | 1803 | case CPU_DOWN_FAILED: |