From: Prashanth Prakash <pprakash@codeaurora.org>
To: linux-pm@vger.kernel.org
Cc: rjw@rjwysocki.net, viresh.kumar@linaro.org, pprakash@codeaurora.org
Subject: [PATCH] cpufreq: create sysfs symlink for cpus onlined after boot
Date: Thu, 23 Mar 2017 15:24:46 -0600 [thread overview]
Message-ID: <1490304286-18311-1-git-send-email-pprakash@codeaurora.org> (raw)
Adds an additional code path within cpufreq_online to create sysfs
symlinks for cpus that are bought onilne for the first time after
completion of boot.
With maxcpus=N kernel parameter, it is possible to bring additional
cpus online after boot. In these cases per-cpu "cpufreq" symlinks
are not being created during registration as policy may not exist
for the cpus that were offline during boot.
Signed-off-by: Prashanth Prakash <pprakash@codeaurora.org>
---
drivers/cpufreq/cpufreq.c | 63 +++++++++++++++++++++++++++++++++++------------
include/linux/cpufreq.h | 1 -
2 files changed, 47 insertions(+), 17 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 5dbdd26..e7d8ad5 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -62,6 +62,7 @@ static inline bool policy_is_inactive(struct cpufreq_policy *policy)
* also protects the cpufreq_cpu_data array.
*/
static struct cpufreq_driver *cpufreq_driver;
+static cpumask_var_t cpufreq_real_cpus; /* mask of real/registered CPUs */
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_RWLOCK(cpufreq_driver_lock);
@@ -1048,14 +1049,11 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
goto err_free_cpumask;
- if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
- goto err_free_rcpumask;
-
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
cpufreq_global_kobject, "policy%u", cpu);
if (ret) {
pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
- goto err_free_real_cpus;
+ goto err_free_rcpumask;
}
INIT_LIST_HEAD(&policy->policy_list);
@@ -1068,8 +1066,6 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
policy->cpu = cpu;
return policy;
-err_free_real_cpus:
- free_cpumask_var(policy->real_cpus);
err_free_rcpumask:
free_cpumask_var(policy->related_cpus);
err_free_cpumask:
@@ -1116,7 +1112,6 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
cpufreq_policy_put_kobj(policy);
- free_cpumask_var(policy->real_cpus);
free_cpumask_var(policy->related_cpus);
free_cpumask_var(policy->cpus);
kfree(policy);
@@ -1181,8 +1176,16 @@ static int cpufreq_online(unsigned int cpu)
policy->user_policy.max = policy->max;
write_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu(j, policy->related_cpus)
+ for_each_cpu(j, policy->related_cpus) {
+ /* Setup sysfs links only for real CPUs */
+ if (cpumask_test_cpu(j, cpufreq_real_cpus)) {
+ ret = add_cpu_dev_symlink(policy,
+ get_cpu_device(j));
+ if (ret)
+ goto out_delete_symlinks;
+ }
per_cpu(cpufreq_cpu_data, j) = policy;
+ }
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
} else {
policy->min = policy->user_policy.min;
@@ -1270,6 +1273,13 @@ static int cpufreq_online(unsigned int cpu)
return 0;
+out_delete_symlinks:
+ for_each_cpu(j, policy->related_cpus) {
+ if (per_cpu(cpufreq_cpu_data, j) &&
+ cpumask_test_cpu(j, cpufreq_real_cpus))
+ remove_cpu_dev_symlink(policy, get_cpu_device(j));
+ per_cpu(cpufreq_cpu_data, j) = NULL;
+ }
out_exit_policy:
up_write(&policy->rwsem);
@@ -1301,14 +1311,22 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
return ret;
}
- /* Create sysfs link on CPU registration */
+ if (cpumask_test_and_set_cpu(cpu, cpufreq_real_cpus))
+ return 0;
+
+ /*
+ * sysfs links will be created on CPU registration <OR>
+ * if a CPU was offline during registration (when maxcpus=N is used)
+ * then sysfs links will be created when a new policy is created in
+ * cpufreq_online
+ */
policy = per_cpu(cpufreq_cpu_data, cpu);
- if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus))
+ if (!policy)
return 0;
ret = add_cpu_dev_symlink(policy, dev);
if (ret) {
- cpumask_clear_cpu(cpu, policy->real_cpus);
+ cpumask_clear_cpu(cpu, cpufreq_real_cpus);
cpufreq_offline(cpu);
}
@@ -1384,7 +1402,7 @@ static int cpufreq_offline(unsigned int cpu)
*/
static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
{
- unsigned int cpu = dev->id;
+ unsigned int cpu = dev->id, i;
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy)
@@ -1393,11 +1411,14 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_online(cpu))
cpufreq_offline(cpu);
- cpumask_clear_cpu(cpu, policy->real_cpus);
- remove_cpu_dev_symlink(policy, dev);
+ if (cpumask_test_and_clear_cpu(cpu, cpufreq_real_cpus))
+ remove_cpu_dev_symlink(policy, dev);
- if (cpumask_empty(policy->real_cpus))
- cpufreq_policy_free(policy);
+ for_each_cpu(i, policy->related_cpus) {
+ if (cpumask_test_cpu(i, cpufreq_real_cpus))
+ return;
+ }
+ cpufreq_policy_free(policy);
}
/**
@@ -2530,6 +2551,9 @@ static int __init cpufreq_core_init(void)
if (cpufreq_disabled())
return -ENODEV;
+ if (!zalloc_cpumask_var(&cpufreq_real_cpus, GFP_KERNEL))
+ return -ENOMEM;
+
cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
BUG_ON(!cpufreq_global_kobject);
@@ -2537,5 +2561,12 @@ static int __init cpufreq_core_init(void)
return 0;
}
+
+static void __exit cpufreq_core_exit(void)
+{
+ free_cpumask_var(cpufreq_real_cpus);
+}
+
module_param(off, int, 0444);
core_initcall(cpufreq_core_init);
+module_exit(cpufreq_core_exit);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 87165f0..86e0bd5 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -66,7 +66,6 @@ struct cpufreq_policy {
/* CPUs sharing clock, require sw coordination */
cpumask_var_t cpus; /* Online CPUs only */
cpumask_var_t related_cpus; /* Online + Offline CPUs */
- cpumask_var_t real_cpus; /* Related and present */
unsigned int shared_type; /* ACPI: ANY or ALL affected CPUs
should set cpufreq */
--
Qualcomm Datacenter Technologies on behalf of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
next reply other threads:[~2017-03-23 21:24 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-23 21:24 Prashanth Prakash [this message]
2017-03-23 23:30 ` [PATCH] cpufreq: create sysfs symlink for cpus onlined after boot Rafael J. Wysocki
2017-03-24 16:31 ` Prakash, Prashanth
2017-03-25 13:30 ` Rafael J. Wysocki
2017-03-25 17:15 ` Rafael J. Wysocki
2017-03-26 1:05 ` Rafael J. Wysocki
2017-03-26 1:19 ` Rafael J. Wysocki
2017-03-27 16:55 ` Prakash, Prashanth
2017-03-27 17:29 ` Rafael J. Wysocki
2017-04-10 10:11 ` Viresh Kumar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1490304286-18311-1-git-send-email-pprakash@codeaurora.org \
--to=pprakash@codeaurora.org \
--cc=linux-pm@vger.kernel.org \
--cc=rjw@rjwysocki.net \
--cc=viresh.kumar@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).