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); |
