diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 93 |
1 files changed, 28 insertions, 65 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3dd4884c6f9e..3a64136bf21b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -916,58 +916,18 @@ static struct kobj_type ktype_cpufreq = { | |||
916 | .release = cpufreq_sysfs_release, | 916 | .release = cpufreq_sysfs_release, |
917 | }; | 917 | }; |
918 | 918 | ||
919 | static int add_cpu_dev_symlink(struct cpufreq_policy *policy, int cpu) | 919 | static int add_cpu_dev_symlink(struct cpufreq_policy *policy, |
920 | struct device *dev) | ||
920 | { | 921 | { |
921 | struct device *cpu_dev; | 922 | dev_dbg(dev, "%s: Adding symlink\n", __func__); |
922 | 923 | return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); | |
923 | pr_debug("%s: Adding symlink for CPU: %u\n", __func__, cpu); | ||
924 | |||
925 | if (!policy) | ||
926 | return 0; | ||
927 | |||
928 | cpu_dev = get_cpu_device(cpu); | ||
929 | if (WARN_ON(!cpu_dev)) | ||
930 | return 0; | ||
931 | |||
932 | return sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq"); | ||
933 | } | ||
934 | |||
935 | static void remove_cpu_dev_symlink(struct cpufreq_policy *policy, int cpu) | ||
936 | { | ||
937 | struct device *cpu_dev; | ||
938 | |||
939 | pr_debug("%s: Removing symlink for CPU: %u\n", __func__, cpu); | ||
940 | |||
941 | cpu_dev = get_cpu_device(cpu); | ||
942 | if (WARN_ON(!cpu_dev)) | ||
943 | return; | ||
944 | |||
945 | sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); | ||
946 | } | 924 | } |
947 | 925 | ||
948 | /* Add/remove symlinks for all related CPUs */ | 926 | static void remove_cpu_dev_symlink(struct cpufreq_policy *policy, |
949 | static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy) | 927 | struct device *dev) |
950 | { | 928 | { |
951 | unsigned int j; | 929 | dev_dbg(dev, "%s: Removing symlink\n", __func__); |
952 | int ret = 0; | 930 | sysfs_remove_link(&dev->kobj, "cpufreq"); |
953 | |||
954 | /* Some related CPUs might not be present (physically hotplugged) */ | ||
955 | for_each_cpu(j, policy->real_cpus) { | ||
956 | ret = add_cpu_dev_symlink(policy, j); | ||
957 | if (ret) | ||
958 | break; | ||
959 | } | ||
960 | |||
961 | return ret; | ||
962 | } | ||
963 | |||
964 | static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy) | ||
965 | { | ||
966 | unsigned int j; | ||
967 | |||
968 | /* Some related CPUs might not be present (physically hotplugged) */ | ||
969 | for_each_cpu(j, policy->real_cpus) | ||
970 | remove_cpu_dev_symlink(policy, j); | ||
971 | } | 931 | } |
972 | 932 | ||
973 | static int cpufreq_add_dev_interface(struct cpufreq_policy *policy) | 933 | static int cpufreq_add_dev_interface(struct cpufreq_policy *policy) |
@@ -999,7 +959,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy) | |||
999 | return ret; | 959 | return ret; |
1000 | } | 960 | } |
1001 | 961 | ||
1002 | return cpufreq_add_dev_symlink(policy); | 962 | return 0; |
1003 | } | 963 | } |
1004 | 964 | ||
1005 | __weak struct cpufreq_governor *cpufreq_default_governor(void) | 965 | __weak struct cpufreq_governor *cpufreq_default_governor(void) |
@@ -1073,13 +1033,9 @@ static void handle_update(struct work_struct *work) | |||
1073 | 1033 | ||
1074 | static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) | 1034 | static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) |
1075 | { | 1035 | { |
1076 | struct device *dev = get_cpu_device(cpu); | ||
1077 | struct cpufreq_policy *policy; | 1036 | struct cpufreq_policy *policy; |
1078 | int ret; | 1037 | int ret; |
1079 | 1038 | ||
1080 | if (WARN_ON(!dev)) | ||
1081 | return NULL; | ||
1082 | |||
1083 | policy = kzalloc(sizeof(*policy), GFP_KERNEL); | 1039 | policy = kzalloc(sizeof(*policy), GFP_KERNEL); |
1084 | if (!policy) | 1040 | if (!policy) |
1085 | return NULL; | 1041 | return NULL; |
@@ -1133,7 +1089,6 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify) | |||
1133 | 1089 | ||
1134 | down_write(&policy->rwsem); | 1090 | down_write(&policy->rwsem); |
1135 | cpufreq_stats_free_table(policy); | 1091 | cpufreq_stats_free_table(policy); |
1136 | cpufreq_remove_dev_symlink(policy); | ||
1137 | kobj = &policy->kobj; | 1092 | kobj = &policy->kobj; |
1138 | cmp = &policy->kobj_unregister; | 1093 | cmp = &policy->kobj_unregister; |
1139 | up_write(&policy->rwsem); | 1094 | up_write(&policy->rwsem); |
@@ -1215,8 +1170,8 @@ static int cpufreq_online(unsigned int cpu) | |||
1215 | if (new_policy) { | 1170 | if (new_policy) { |
1216 | /* related_cpus should at least include policy->cpus. */ | 1171 | /* related_cpus should at least include policy->cpus. */ |
1217 | cpumask_copy(policy->related_cpus, policy->cpus); | 1172 | cpumask_copy(policy->related_cpus, policy->cpus); |
1218 | /* Remember CPUs present at the policy creation time. */ | 1173 | /* Clear mask of registered CPUs */ |
1219 | cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask); | 1174 | cpumask_clear(policy->real_cpus); |
1220 | } | 1175 | } |
1221 | 1176 | ||
1222 | /* | 1177 | /* |
@@ -1331,6 +1286,8 @@ out_free_policy: | |||
1331 | return ret; | 1286 | return ret; |
1332 | } | 1287 | } |
1333 | 1288 | ||
1289 | static void cpufreq_offline(unsigned int cpu); | ||
1290 | |||
1334 | /** | 1291 | /** |
1335 | * cpufreq_add_dev - the cpufreq interface for a CPU device. | 1292 | * cpufreq_add_dev - the cpufreq interface for a CPU device. |
1336 | * @dev: CPU device. | 1293 | * @dev: CPU device. |
@@ -1340,22 +1297,28 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
1340 | { | 1297 | { |
1341 | struct cpufreq_policy *policy; | 1298 | struct cpufreq_policy *policy; |
1342 | unsigned cpu = dev->id; | 1299 | unsigned cpu = dev->id; |
1300 | int ret; | ||
1343 | 1301 | ||
1344 | dev_dbg(dev, "%s: adding CPU%u\n", __func__, cpu); | 1302 | dev_dbg(dev, "%s: adding CPU%u\n", __func__, cpu); |
1345 | 1303 | ||
1346 | if (cpu_online(cpu)) | 1304 | if (cpu_online(cpu)) { |
1347 | return cpufreq_online(cpu); | 1305 | ret = cpufreq_online(cpu); |
1306 | if (ret) | ||
1307 | return ret; | ||
1308 | } | ||
1348 | 1309 | ||
1349 | /* | 1310 | /* Create sysfs link on CPU registration */ |
1350 | * A hotplug notifier will follow and we will handle it as CPU online | ||
1351 | * then. For now, just create the sysfs link, unless there is no policy | ||
1352 | * or the link is already present. | ||
1353 | */ | ||
1354 | policy = per_cpu(cpufreq_cpu_data, cpu); | 1311 | policy = per_cpu(cpufreq_cpu_data, cpu); |
1355 | if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus)) | 1312 | if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus)) |
1356 | return 0; | 1313 | return 0; |
1357 | 1314 | ||
1358 | return add_cpu_dev_symlink(policy, cpu); | 1315 | ret = add_cpu_dev_symlink(policy, dev); |
1316 | if (ret) { | ||
1317 | cpumask_clear_cpu(cpu, policy->real_cpus); | ||
1318 | cpufreq_offline(cpu); | ||
1319 | } | ||
1320 | |||
1321 | return ret; | ||
1359 | } | 1322 | } |
1360 | 1323 | ||
1361 | static void cpufreq_offline(unsigned int cpu) | 1324 | static void cpufreq_offline(unsigned int cpu) |
@@ -1436,7 +1399,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) | |||
1436 | cpufreq_offline(cpu); | 1399 | cpufreq_offline(cpu); |
1437 | 1400 | ||
1438 | cpumask_clear_cpu(cpu, policy->real_cpus); | 1401 | cpumask_clear_cpu(cpu, policy->real_cpus); |
1439 | remove_cpu_dev_symlink(policy, cpu); | 1402 | remove_cpu_dev_symlink(policy, dev); |
1440 | 1403 | ||
1441 | if (cpumask_empty(policy->real_cpus)) | 1404 | if (cpumask_empty(policy->real_cpus)) |
1442 | cpufreq_policy_free(policy, true); | 1405 | cpufreq_policy_free(policy, true); |