* [PATCH v2 1/7] cpufreq: Fix misplaced call to cpufreq_update_policy()
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
@ 2013-07-29 22:53 ` Srivatsa S. Bhat
2013-07-29 22:54 ` [PATCH v2 2/7] cpufreq: Add helper to perform alloc/free of policy structure Srivatsa S. Bhat
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:53 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
The call to cpufreq_update_policy() is placed in the CPU hotplug callback
of cpufreq_stats, which has a higher priority than the CPU hotplug callback
of cpufreq-core. As a result, during CPU_ONLINE/CPU_ONLINE_FROZEN, we end up
calling cpufreq_update_policy() *before* calling cpufreq_add_dev() !
And for uninitialized CPUs, it just returns silently, not doing anything.
To add to it, cpufreq_stats is not even the right place to call
cpufreq_update_policy() to begin with. The cpufreq core ought to handle
this in its own callback, from an elegance/relevance perspective.
So move the invocation of cpufreq_update_policy() to cpufreq_cpu_callback,
and place it *after* cpufreq_add_dev().
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq.c | 1 +
drivers/cpufreq/cpufreq_stats.c | 6 ------
2 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index c1a917a..347aef3 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1933,6 +1933,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
cpufreq_add_dev(dev, NULL);
+ cpufreq_update_policy(cpu);
break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d37568c..bc73be2 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -348,10 +348,6 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
unsigned int cpu = (unsigned long)hcpu;
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- cpufreq_update_policy(cpu);
- break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
@@ -390,8 +386,6 @@ static int __init cpufreq_stats_init(void)
return ret;
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
- for_each_online_cpu(cpu)
- cpufreq_update_policy(cpu);
ret = cpufreq_register_notifier(¬ifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER);
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 2/7] cpufreq: Add helper to perform alloc/free of policy structure
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
2013-07-29 22:53 ` [PATCH v2 1/7] cpufreq: Fix misplaced call to cpufreq_update_policy() Srivatsa S. Bhat
@ 2013-07-29 22:54 ` Srivatsa S. Bhat
2013-07-29 22:54 ` [PATCH v2 3/7] cpufreq: Extract non-interface related stuff from cpufreq_add_dev_interface Srivatsa S. Bhat
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:54 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
Separate out the allocation of the cpufreq policy structure (along with
its error handling) to a helper function. This makes the code easier to
read and also helps with some upcoming code reorganization.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq.c | 49 +++++++++++++++++++++++++++++++--------------
1 file changed, 34 insertions(+), 15 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 347aef3..0ce9e9d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -944,6 +944,37 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
}
#endif
+static struct cpufreq_policy *cpufreq_policy_alloc(void)
+{
+ struct cpufreq_policy *policy;
+
+ policy = kzalloc(sizeof(*policy), GFP_KERNEL);
+ if (!policy)
+ return NULL;
+
+ if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+ goto err_free_policy;
+
+ if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+ goto err_free_cpumask;
+
+ return policy;
+
+err_free_cpumask:
+ free_cpumask_var(policy->cpus);
+err_free_policy:
+ kfree(policy);
+
+ return NULL;
+}
+
+static void cpufreq_policy_free(struct cpufreq_policy *policy)
+{
+ free_cpumask_var(policy->related_cpus);
+ free_cpumask_var(policy->cpus);
+ kfree(policy);
+}
+
/**
* cpufreq_add_dev - add a CPU device
*
@@ -997,16 +1028,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
goto module_out;
}
- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+ policy = cpufreq_policy_alloc();
if (!policy)
goto nomem_out;
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
- goto err_free_policy;
-
- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
- goto err_free_cpumask;
-
policy->cpu = cpu;
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
cpumask_copy(policy->cpus, cpumask_of(cpu));
@@ -1071,11 +1096,7 @@ err_out_unregister:
err_set_policy_cpu:
per_cpu(cpufreq_policy_cpu, cpu) = -1;
- free_cpumask_var(policy->related_cpus);
-err_free_cpumask:
- free_cpumask_var(policy->cpus);
-err_free_policy:
- kfree(policy);
+ cpufreq_policy_free(policy);
nomem_out:
module_put(cpufreq_driver->owner);
module_out:
@@ -1199,9 +1220,7 @@ static int __cpufreq_remove_dev(struct device *dev,
if (cpufreq_driver->exit)
cpufreq_driver->exit(data);
- free_cpumask_var(data->related_cpus);
- free_cpumask_var(data->cpus);
- kfree(data);
+ cpufreq_policy_free(data);
} else {
pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
cpufreq_cpu_put(data);
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 3/7] cpufreq: Extract non-interface related stuff from cpufreq_add_dev_interface
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
2013-07-29 22:53 ` [PATCH v2 1/7] cpufreq: Fix misplaced call to cpufreq_update_policy() Srivatsa S. Bhat
2013-07-29 22:54 ` [PATCH v2 2/7] cpufreq: Add helper to perform alloc/free of policy structure Srivatsa S. Bhat
@ 2013-07-29 22:54 ` Srivatsa S. Bhat
2013-07-29 22:54 ` [PATCH v2 4/7] cpufreq: Extract the handover of policy cpu to a helper function Srivatsa S. Bhat
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:54 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
cpufreq_add_dev_interface() includes the work of exposing the interface
to the device, as well as a lot of unrelated stuff. Move the latter to
cpufreq_add_dev(), where it is more appropriate.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq.c | 43 ++++++++++++++++++++++++++-----------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 0ce9e9d..39bda8f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -835,11 +835,8 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
struct cpufreq_policy *policy,
struct device *dev)
{
- struct cpufreq_policy new_policy;
struct freq_attr **drv_attr;
- unsigned long flags;
int ret = 0;
- unsigned int j;
/* prepare interface data */
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
@@ -871,17 +868,23 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
goto err_out_kobj_put;
}
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu(j, policy->cpus) {
- per_cpu(cpufreq_cpu_data, j) = policy;
- per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
- }
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
ret = cpufreq_add_dev_symlink(cpu, policy);
if (ret)
goto err_out_kobj_put;
+ return ret;
+
+err_out_kobj_put:
+ kobject_put(&policy->kobj);
+ wait_for_completion(&policy->kobj_unregister);
+ return ret;
+}
+
+static void cpufreq_init_policy(struct cpufreq_policy *policy)
+{
+ struct cpufreq_policy new_policy;
+ int ret = 0;
+
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
/* assure that the starting sequence is run in __cpufreq_set_policy */
policy->governor = NULL;
@@ -896,12 +899,6 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
}
- return ret;
-
-err_out_kobj_put:
- kobject_put(&policy->kobj);
- wait_for_completion(&policy->kobj_unregister);
- return ret;
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -1075,10 +1072,19 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
}
#endif
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ for_each_cpu(j, policy->cpus) {
+ per_cpu(cpufreq_cpu_data, j) = policy;
+ per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
+ }
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
ret = cpufreq_add_dev_interface(cpu, policy, dev);
if (ret)
goto err_out_unregister;
+ cpufreq_init_policy(policy);
+
kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
pr_debug("initialization complete\n");
@@ -1087,8 +1093,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
err_out_unregister:
write_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu(j, policy->cpus)
+ for_each_cpu(j, policy->cpus) {
per_cpu(cpufreq_cpu_data, j) = NULL;
+ if (j != cpu)
+ per_cpu(cpufreq_policy_cpu, j) = -1;
+ }
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_put(&policy->kobj);
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 4/7] cpufreq: Extract the handover of policy cpu to a helper function
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
` (2 preceding siblings ...)
2013-07-29 22:54 ` [PATCH v2 3/7] cpufreq: Extract non-interface related stuff from cpufreq_add_dev_interface Srivatsa S. Bhat
@ 2013-07-29 22:54 ` Srivatsa S. Bhat
2013-07-29 22:54 ` [PATCH v2 5/7] cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown Srivatsa S. Bhat
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:54 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
During cpu offline, when the policy->cpu is going down, some other CPU
present in the policy->cpus mask is nominated as the new policy->cpu.
Extract this functionality from __cpufreq_remove_dev() and implement
it in a helper function. This helps in upcoming code reorganization.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq.c | 63 ++++++++++++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 24 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 39bda8f..32b3ce7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1129,6 +1129,38 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
CPUFREQ_UPDATE_POLICY_CPU, policy);
}
+static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
+ unsigned int old_cpu)
+{
+ struct device *cpu_dev;
+ unsigned long flags;
+ int ret;
+
+ /* first sibling now owns the new sysfs dir */
+ cpu_dev = get_cpu_device(cpumask_first(data->cpus));
+ sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+ ret = kobject_move(&data->kobj, &cpu_dev->kobj);
+ if (ret) {
+ pr_err("%s: Failed to move kobj: %d", __func__, ret);
+
+ WARN_ON(lock_policy_rwsem_write(old_cpu));
+ cpumask_set_cpu(old_cpu, data->cpus);
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ per_cpu(cpufreq_cpu_data, old_cpu) = data;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ unlock_policy_rwsem_write(old_cpu);
+
+ ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
+ "cpufreq");
+
+ return -EINVAL;
+ }
+
+ return cpu_dev->id;
+}
+
/**
* __cpufreq_remove_dev - remove a CPU device
*
@@ -1139,12 +1171,12 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
static int __cpufreq_remove_dev(struct device *dev,
struct subsys_interface *sif)
{
- unsigned int cpu = dev->id, ret, cpus;
+ unsigned int cpu = dev->id, cpus;
+ int new_cpu;
unsigned long flags;
struct cpufreq_policy *data;
struct kobject *kobj;
struct completion *cmp;
- struct device *cpu_dev;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
@@ -1179,32 +1211,15 @@ static int __cpufreq_remove_dev(struct device *dev,
if (cpu != data->cpu) {
sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) {
- /* first sibling now owns the new sysfs dir */
- cpu_dev = get_cpu_device(cpumask_first(data->cpus));
- sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
- ret = kobject_move(&data->kobj, &cpu_dev->kobj);
- if (ret) {
- pr_err("%s: Failed to move kobj: %d", __func__, ret);
+ new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu);
+ if (new_cpu >= 0) {
WARN_ON(lock_policy_rwsem_write(cpu));
- cpumask_set_cpu(cpu, data->cpus);
-
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- per_cpu(cpufreq_cpu_data, cpu) = data;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
+ update_policy_cpu(data, new_cpu);
unlock_policy_rwsem_write(cpu);
-
- ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
- "cpufreq");
- return -EINVAL;
+ pr_debug("%s: policy Kobject moved to cpu: %d "
+ "from: %d\n",__func__, new_cpu, cpu);
}
-
- WARN_ON(lock_policy_rwsem_write(cpu));
- update_policy_cpu(data, cpu_dev->id);
- unlock_policy_rwsem_write(cpu);
- pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
- __func__, cpu_dev->id, cpu);
}
/* If cpu is last user of policy, free policy */
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 5/7] cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
` (3 preceding siblings ...)
2013-07-29 22:54 ` [PATCH v2 4/7] cpufreq: Extract the handover of policy cpu to a helper function Srivatsa S. Bhat
@ 2013-07-29 22:54 ` Srivatsa S. Bhat
2013-07-29 22:55 ` [PATCH v2 6/7] cpufreq: Preserve policy structure across suspend/resume Srivatsa S. Bhat
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:54 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
During suspend/resume we would like to do a light-weight init/teardown of
CPUs in the cpufreq subsystem and preserve certain things such as sysfs files
etc across suspend/resume transitions. Add a flag called 'frozen' to help
distinguish the full init/teardown sequence from the light-weight one.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq.c | 76 +++++++++++++++++++++++++++++----------------
1 file changed, 49 insertions(+), 27 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 32b3ce7..92b833f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -903,7 +903,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
#ifdef CONFIG_HOTPLUG_CPU
static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
- struct device *dev)
+ struct device *dev, bool frozen)
{
struct cpufreq_policy *policy;
int ret = 0, has_target = !!cpufreq_driver->target;
@@ -931,13 +931,18 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
}
- ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
- if (ret) {
+ /* Don't touch sysfs links during light-weight init */
+ if (frozen) {
+ /* Drop the extra refcount that we took above */
cpufreq_cpu_put(policy);
- return ret;
+ return 0;
}
- return 0;
+ ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
+ if (ret)
+ cpufreq_cpu_put(policy);
+
+ return ret;
}
#endif
@@ -972,16 +977,8 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
kfree(policy);
}
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
- */
-static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
+ bool frozen)
{
unsigned int j, cpu = dev->id;
int ret = -ENOMEM;
@@ -1013,7 +1010,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return cpufreq_add_policy_cpu(cpu, sibling, dev);
+ return cpufreq_add_policy_cpu(cpu, sibling, dev,
+ frozen);
}
}
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -1079,9 +1077,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
}
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- ret = cpufreq_add_dev_interface(cpu, policy, dev);
- if (ret)
- goto err_out_unregister;
+ if (!frozen) {
+ ret = cpufreq_add_dev_interface(cpu, policy, dev);
+ if (ret)
+ goto err_out_unregister;
+ }
cpufreq_init_policy(policy);
@@ -1112,6 +1112,20 @@ module_out:
return ret;
}
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+{
+ return __cpufreq_add_dev(dev, sif, false);
+}
+
static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
{
int j;
@@ -1130,7 +1144,7 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
}
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
- unsigned int old_cpu)
+ unsigned int old_cpu, bool frozen)
{
struct device *cpu_dev;
unsigned long flags;
@@ -1138,6 +1152,11 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
/* first sibling now owns the new sysfs dir */
cpu_dev = get_cpu_device(cpumask_first(data->cpus));
+
+ /* Don't touch sysfs files during light-weight tear-down */
+ if (frozen)
+ return cpu_dev->id;
+
sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
ret = kobject_move(&data->kobj, &cpu_dev->kobj);
if (ret) {
@@ -1169,7 +1188,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
* This routine frees the rwsem before returning.
*/
static int __cpufreq_remove_dev(struct device *dev,
- struct subsys_interface *sif)
+ struct subsys_interface *sif, bool frozen)
{
unsigned int cpu = dev->id, cpus;
int new_cpu;
@@ -1208,17 +1227,20 @@ static int __cpufreq_remove_dev(struct device *dev,
cpumask_clear_cpu(cpu, data->cpus);
unlock_policy_rwsem_write(cpu);
- if (cpu != data->cpu) {
+ if (cpu != data->cpu && !frozen) {
sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) {
- new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu);
+ new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen);
if (new_cpu >= 0) {
WARN_ON(lock_policy_rwsem_write(cpu));
update_policy_cpu(data, new_cpu);
unlock_policy_rwsem_write(cpu);
- pr_debug("%s: policy Kobject moved to cpu: %d "
- "from: %d\n",__func__, new_cpu, cpu);
+
+ if (!frozen) {
+ pr_debug("%s: policy Kobject moved to cpu: %d "
+ "from: %d\n",__func__, new_cpu, cpu);
+ }
}
}
@@ -1266,7 +1288,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu))
return 0;
- retval = __cpufreq_remove_dev(dev, sif);
+ retval = __cpufreq_remove_dev(dev, sif, false);
return retval;
}
@@ -1980,7 +2002,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
- __cpufreq_remove_dev(dev, NULL);
+ __cpufreq_remove_dev(dev, NULL, false);
break;
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 6/7] cpufreq: Preserve policy structure across suspend/resume
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
` (4 preceding siblings ...)
2013-07-29 22:54 ` [PATCH v2 5/7] cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown Srivatsa S. Bhat
@ 2013-07-29 22:55 ` Srivatsa S. Bhat
2013-07-30 9:09 ` Viresh Kumar
2013-07-29 22:55 ` [PATCH v2 7/7] cpufreq: Perform light-weight init/teardown during suspend/resume Srivatsa S. Bhat
2013-07-30 14:06 ` [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Rafael J. Wysocki
7 siblings, 1 reply; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:55 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
To perform light-weight cpu-init and teardown in the cpufreq subsystem
during suspend/resume, we need to separate out the 2 main functionalities
of the cpufreq CPU hotplug callbacks, as outlined below:
1. Init/tear-down of core cpufreq and CPU-specific components, which are
critical to the correct functioning of the cpufreq subsystem.
2. Init/tear-down of cpufreq sysfs files during suspend/resume.
The first part requires accurate updates to the policy structure such as
its ->cpus and ->related_cpus masks, whereas the second part requires that
the policy->kobj structure is not released or re-initialized during
suspend/resume.
To handle both these requirements, we need to allow updates to the policy
structure throughout suspend/resume, but prevent the structure from getting
freed up. Also, we must have a mechanism by which the cpu-up callbacks can
restore the policy structure, without allocating things afresh. (That also
helps avoid memory leaks).
To achieve this, we use 2 schemes:
a. Use a fallback per-cpu storage area for preserving the policy structures
during suspend, so that they can be restored during resume appropriately.
b. Use the 'frozen' flag to determine when to free or allocate the policy
structure vs when to restore the policy from the saved fallback storage.
Thus we can successfully preserve the structure across suspend/resume.
Effectively, this helps us complete the separation of the 'light-weight'
and the 'full' init/tear-down sequences in the cpufreq subsystem, so that
this can be made use of in the suspend/resume scenario.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---
drivers/cpufreq/cpufreq.c | 69 +++++++++++++++++++++++++++++++++++----------
1 file changed, 53 insertions(+), 16 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 92b833f..4c5ad4a 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -44,6 +44,7 @@
*/
static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_MUTEX(cpufreq_governor_lock);
@@ -946,6 +947,20 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
}
#endif
+static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
+{
+ struct cpufreq_policy *policy;
+ unsigned long flags;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+
+ policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
+
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ return policy;
+}
+
static struct cpufreq_policy *cpufreq_policy_alloc(void)
{
struct cpufreq_policy *policy;
@@ -1023,7 +1038,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
goto module_out;
}
- policy = cpufreq_policy_alloc();
+ if (frozen)
+ /* Restore the saved policy when doing light-weight init */
+ policy = cpufreq_policy_restore(cpu);
+ else
+ policy = cpufreq_policy_alloc();
+
if (!policy)
goto nomem_out;
@@ -1204,6 +1224,10 @@ static int __cpufreq_remove_dev(struct device *dev,
data = per_cpu(cpufreq_cpu_data, cpu);
per_cpu(cpufreq_cpu_data, cpu) = NULL;
+ /* Save the policy somewhere when doing a light-weight tear-down */
+ if (frozen)
+ per_cpu(cpufreq_cpu_data_fallback, cpu) = data;
+
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!data) {
@@ -1249,27 +1273,40 @@ static int __cpufreq_remove_dev(struct device *dev,
if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
- lock_policy_rwsem_read(cpu);
- kobj = &data->kobj;
- cmp = &data->kobj_unregister;
- unlock_policy_rwsem_read(cpu);
- kobject_put(kobj);
+ if (!frozen) {
+ lock_policy_rwsem_read(cpu);
+ kobj = &data->kobj;
+ cmp = &data->kobj_unregister;
+ unlock_policy_rwsem_read(cpu);
+ kobject_put(kobj);
+
+ /*
+ * We need to make sure that the underlying kobj is
+ * actually not referenced anymore by anybody before we
+ * proceed with unloading.
+ */
+ pr_debug("waiting for dropping of refcount\n");
+ wait_for_completion(cmp);
+ pr_debug("wait complete\n");
+ }
- /* we need to make sure that the underlying kobj is actually
- * not referenced anymore by anybody before we proceed with
- * unloading.
+ /*
+ * Perform the ->exit() even during light-weight tear-down,
+ * since this is a core component, and is essential for the
+ * subsequent light-weight ->init() to succeed.
*/
- pr_debug("waiting for dropping of refcount\n");
- wait_for_completion(cmp);
- pr_debug("wait complete\n");
-
if (cpufreq_driver->exit)
cpufreq_driver->exit(data);
- cpufreq_policy_free(data);
+ if (!frozen)
+ cpufreq_policy_free(data);
} else {
- pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
- cpufreq_cpu_put(data);
+
+ if (!frozen) {
+ pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+ cpufreq_cpu_put(data);
+ }
+
if (cpufreq_driver->target) {
__cpufreq_governor(data, CPUFREQ_GOV_START);
__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 6/7] cpufreq: Preserve policy structure across suspend/resume
2013-07-29 22:55 ` [PATCH v2 6/7] cpufreq: Preserve policy structure across suspend/resume Srivatsa S. Bhat
@ 2013-07-30 9:09 ` Viresh Kumar
0 siblings, 0 replies; 11+ messages in thread
From: Viresh Kumar @ 2013-07-30 9:09 UTC (permalink / raw)
To: Srivatsa S. Bhat
Cc: rjw, toralf.foerster, robert.jarzmik, durgadoss.r, tianyu.lan,
lantianyu1986, dirk.brandewie, stern, linux-pm, linux-kernel
On 30 July 2013 04:25, Srivatsa S. Bhat
<srivatsa.bhat@linux.vnet.ibm.com> wrote:
> To perform light-weight cpu-init and teardown in the cpufreq subsystem
> during suspend/resume, we need to separate out the 2 main functionalities
> of the cpufreq CPU hotplug callbacks, as outlined below:
>
> 1. Init/tear-down of core cpufreq and CPU-specific components, which are
> critical to the correct functioning of the cpufreq subsystem.
>
> 2. Init/tear-down of cpufreq sysfs files during suspend/resume.
>
> The first part requires accurate updates to the policy structure such as
> its ->cpus and ->related_cpus masks, whereas the second part requires that
> the policy->kobj structure is not released or re-initialized during
> suspend/resume.
>
> To handle both these requirements, we need to allow updates to the policy
> structure throughout suspend/resume, but prevent the structure from getting
> freed up. Also, we must have a mechanism by which the cpu-up callbacks can
> restore the policy structure, without allocating things afresh. (That also
> helps avoid memory leaks).
>
> To achieve this, we use 2 schemes:
> a. Use a fallback per-cpu storage area for preserving the policy structures
> during suspend, so that they can be restored during resume appropriately.
>
> b. Use the 'frozen' flag to determine when to free or allocate the policy
> structure vs when to restore the policy from the saved fallback storage.
> Thus we can successfully preserve the structure across suspend/resume.
>
> Effectively, this helps us complete the separation of the 'light-weight'
> and the 'full' init/tear-down sequences in the cpufreq subsystem, so that
> this can be made use of in the suspend/resume scenario.
>
> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> ---
>
> drivers/cpufreq/cpufreq.c | 69 +++++++++++++++++++++++++++++++++++----------
> 1 file changed, 53 insertions(+), 16 deletions(-)
>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 7/7] cpufreq: Perform light-weight init/teardown during suspend/resume
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
` (5 preceding siblings ...)
2013-07-29 22:55 ` [PATCH v2 6/7] cpufreq: Preserve policy structure across suspend/resume Srivatsa S. Bhat
@ 2013-07-29 22:55 ` Srivatsa S. Bhat
2013-07-30 9:09 ` Viresh Kumar
2013-07-30 14:06 ` [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Rafael J. Wysocki
7 siblings, 1 reply; 11+ messages in thread
From: Srivatsa S. Bhat @ 2013-07-29 22:55 UTC (permalink / raw)
To: rjw, viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie
Cc: stern, srivatsa.bhat, linux-pm, linux-kernel
Now that we have the infrastructure to perform a light-weight init/tear-down,
use that in the cpufreq CPU hotplug notifier when invoked from the
suspend/resume path.
This also ensures that the file permissions of the cpufreq sysfs files are
preserved across suspend/resume, something which commit a66b2e (cpufreq:
Preserve sysfs files across suspend/resume) originally intended to do, but
had to be reverted due to other problems.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---
drivers/cpufreq/cpufreq.c | 18 +++++++++++-------
drivers/cpufreq/cpufreq_stats.c | 2 --
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 4c5ad4a..170d344 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2028,22 +2028,26 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
{
unsigned int cpu = (unsigned long)hcpu;
struct device *dev;
+ bool frozen = false;
dev = get_cpu_device(cpu);
if (dev) {
- switch (action) {
+
+ if (action & CPU_TASKS_FROZEN)
+ frozen = true;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- cpufreq_add_dev(dev, NULL);
+ __cpufreq_add_dev(dev, NULL, frozen);
cpufreq_update_policy(cpu);
break;
+
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- __cpufreq_remove_dev(dev, NULL, false);
+ __cpufreq_remove_dev(dev, NULL, frozen);
break;
+
case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- cpufreq_add_dev(dev, NULL);
+ __cpufreq_add_dev(dev, NULL, frozen);
break;
}
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index bc73be2..cb38413 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -349,11 +349,9 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
- case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
break;
}
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 7/7] cpufreq: Perform light-weight init/teardown during suspend/resume
2013-07-29 22:55 ` [PATCH v2 7/7] cpufreq: Perform light-weight init/teardown during suspend/resume Srivatsa S. Bhat
@ 2013-07-30 9:09 ` Viresh Kumar
0 siblings, 0 replies; 11+ messages in thread
From: Viresh Kumar @ 2013-07-30 9:09 UTC (permalink / raw)
To: Srivatsa S. Bhat
Cc: rjw, toralf.foerster, robert.jarzmik, durgadoss.r, tianyu.lan,
lantianyu1986, dirk.brandewie, stern, linux-pm, linux-kernel
On 30 July 2013 04:25, Srivatsa S. Bhat
<srivatsa.bhat@linux.vnet.ibm.com> wrote:
> Now that we have the infrastructure to perform a light-weight init/tear-down,
> use that in the cpufreq CPU hotplug notifier when invoked from the
> suspend/resume path.
>
> This also ensures that the file permissions of the cpufreq sysfs files are
> preserved across suspend/resume, something which commit a66b2e (cpufreq:
> Preserve sysfs files across suspend/resume) originally intended to do, but
> had to be reverted due to other problems.
>
> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> ---
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes
2013-07-29 22:53 [PATCH v2 0/7] Cpufreq, cpu hotplug, suspend/resume related fixes Srivatsa S. Bhat
` (6 preceding siblings ...)
2013-07-29 22:55 ` [PATCH v2 7/7] cpufreq: Perform light-weight init/teardown during suspend/resume Srivatsa S. Bhat
@ 2013-07-30 14:06 ` Rafael J. Wysocki
7 siblings, 0 replies; 11+ messages in thread
From: Rafael J. Wysocki @ 2013-07-30 14:06 UTC (permalink / raw)
To: Srivatsa S. Bhat
Cc: viresh.kumar, toralf.foerster, robert.jarzmik, durgadoss.r,
tianyu.lan, lantianyu1986, dirk.brandewie, stern, linux-pm,
linux-kernel
On Tuesday, July 30, 2013 04:23:12 AM Srivatsa S. Bhat wrote:
>
> Hi,
>
> This patchset reorganizes the cpufreq code and preserves the file permissions
> of cpufreq-related per-cpu sysfs files across suspend/resume cycles, by
> performing a light-weight init/teardown in those paths.
>
> Patches 1 - 4 reorganize the code and have no functional impact, and can go
> in as general cleanups as well. This reorganization builds a base that the
> rest of the patches will make use of.
>
> Patch 5 and 6 add a mechanism to perform light-weight init/tear-down of CPUs
> in the cpufreq subsystem and finally patch 7 uses it to preserve sysfs files
> across suspend/resume.
>
> All the patches apply on Rafael's bleeding-edge branch on linux-pm git
> tree[1].
>
>
> Changes in v2:
> * Fixed a refcounting bug explained here:
> http://marc.info/?l=linux-kernel&m=137511192600806&w=2
>
> * Addressed some suggestions about code reorganization received in v1.
> * Rebased on top of the bleeding-edge branch.
>
>
> [1]. git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge
>
> Thank you very much!
>
>
> Srivatsa S. Bhat (7):
> cpufreq: Fix misplaced call to cpufreq_update_policy()
> cpufreq: Add helper to perform alloc/free of policy structure
> cpufreq: Extract non-interface related stuff from cpufreq_add_dev_interface
> cpufreq: Extract the handover of policy cpu to a helper function
> cpufreq: Introduce a flag ('frozen') to separate full vs temporary init/teardown
> cpufreq: Preserve policy structure across suspend/resume
> cpufreq: Perform light-weight init/teardown during suspend/resume
>
>
> drivers/cpufreq/cpufreq.c | 303 ++++++++++++++++++++++++++-------------
> drivers/cpufreq/cpufreq_stats.c | 8 -
> 2 files changed, 205 insertions(+), 106 deletions(-)
Thanks, queued up for 3.12.
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply [flat|nested] 11+ messages in thread