cpufreq: Split __cpufreq_remove_dev() into two parts

During CPU offline, the cpufreq core invokes __cpufreq_remove_dev()
to perform work such as stopping the cpufreq governor, clearing the
CPU from the policy structure etc, and finally cleaning up the
kobject.

There are certain subtle issues related to the kobject cleanup, and
it would be much easier to deal with them if we separate that part
from the rest of the cleanup-work in the CPU offline phase. So split
the __cpufreq_remove_dev() function into 2 parts: one that handles
the kobject cleanup, and the other that handles the rest of the work.

Reported-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Srivatsa S. Bhat 2013-09-07 01:23:09 +05:30 коммит произвёл Rafael J. Wysocki
Родитель a857c0b9e2
Коммит cedb70afd0
1 изменённых файлов: 53 добавлений и 12 удалений

Просмотреть файл

@ -1141,22 +1141,14 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
return cpu_dev->id; return cpu_dev->id;
} }
/** static int __cpufreq_remove_dev_prepare(struct device *dev,
* __cpufreq_remove_dev - remove a CPU device struct subsys_interface *sif,
* bool frozen)
* Removes the cpufreq interface for a CPU device.
* Caller should already have policy_rwsem in write mode for this CPU.
* This routine frees the rwsem before returning.
*/
static int __cpufreq_remove_dev(struct device *dev,
struct subsys_interface *sif, bool frozen)
{ {
unsigned int cpu = dev->id, cpus; unsigned int cpu = dev->id, cpus;
int new_cpu, ret; int new_cpu, ret;
unsigned long flags; unsigned long flags;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
struct kobject *kobj;
struct completion *cmp;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu); pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
@ -1213,6 +1205,33 @@ static int __cpufreq_remove_dev(struct device *dev,
} }
} }
return 0;
}
static int __cpufreq_remove_dev_finish(struct device *dev,
struct subsys_interface *sif,
bool frozen)
{
unsigned int cpu = dev->id, cpus;
int ret;
unsigned long flags;
struct cpufreq_policy *policy;
struct kobject *kobj;
struct completion *cmp;
read_lock_irqsave(&cpufreq_driver_lock, flags);
policy = per_cpu(cpufreq_cpu_data, cpu);
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!policy) {
pr_debug("%s: No cpu_data found\n", __func__);
return -EINVAL;
}
lock_policy_rwsem_read(cpu);
cpus = cpumask_weight(policy->cpus);
unlock_policy_rwsem_read(cpu);
/* If cpu is last user of policy, free policy */ /* If cpu is last user of policy, free policy */
if (cpus == 1) { if (cpus == 1) {
if (cpufreq_driver->target) { if (cpufreq_driver->target) {
@ -1272,6 +1291,27 @@ static int __cpufreq_remove_dev(struct device *dev,
return 0; return 0;
} }
/**
* __cpufreq_remove_dev - remove a CPU device
*
* Removes the cpufreq interface for a CPU device.
* Caller should already have policy_rwsem in write mode for this CPU.
* This routine frees the rwsem before returning.
*/
static inline int __cpufreq_remove_dev(struct device *dev,
struct subsys_interface *sif,
bool frozen)
{
int ret;
ret = __cpufreq_remove_dev_prepare(dev, sif, frozen);
if (!ret)
ret = __cpufreq_remove_dev_finish(dev, sif, frozen);
return ret;
}
static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
{ {
unsigned int cpu = dev->id; unsigned int cpu = dev->id;
@ -2000,7 +2040,8 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
break; break;
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
__cpufreq_remove_dev(dev, NULL, frozen); __cpufreq_remove_dev_prepare(dev, NULL, frozen);
__cpufreq_remove_dev_finish(dev, NULL, frozen);
break; break;
case CPU_DOWN_FAILED: case CPU_DOWN_FAILED: