Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351048
b: refs/heads/master
c: 2eaa3e2
h: refs/heads/master
v: v3
  • Loading branch information
Viresh Kumar authored and Rafael J. Wysocki committed Feb 9, 2013
1 parent 8a1b0f8 commit fc10dfd
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 35 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fa1d8af47f42671fa82779582ca60948f876a73e
refs/heads/master: 2eaa3e2df185997e92596ab14a2a67dde3876d2e
72 changes: 38 additions & 34 deletions trunk/drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
* mode before doing so.
*
* Additional rules:
* - All holders of the lock should check to make sure that the CPU they
* are concerned with are online after they get the lock.
* - Governor routines that can be called in cpufreq hotplug path should not
* take this sem as top level hotplug notifier handler takes this.
* - Lock should not be held across
Expand Down Expand Up @@ -257,6 +255,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{
struct cpufreq_policy *policy;
unsigned long flags;

BUG_ON(irqs_disabled());

Expand All @@ -267,7 +266,10 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
pr_debug("notification %u of frequency transition to %u kHz\n",
state, freqs->new);

spin_lock_irqsave(&cpufreq_driver_lock, flags);
policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);

switch (state) {

case CPUFREQ_PRECHANGE:
Expand Down Expand Up @@ -808,22 +810,22 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
policy = cpufreq_cpu_get(sibling);
WARN_ON(!policy);

per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;

lock_policy_rwsem_write(cpu);

__cpufreq_governor(policy, CPUFREQ_GOV_STOP);

lock_policy_rwsem_write(sibling);

spin_lock_irqsave(&cpufreq_driver_lock, flags);

cpumask_set_cpu(cpu, policy->cpus);
per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
per_cpu(cpufreq_cpu_data, cpu) = policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);

unlock_policy_rwsem_write(sibling);

__cpufreq_governor(policy, CPUFREQ_GOV_START);
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);

unlock_policy_rwsem_write(cpu);

ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
if (ret) {
cpufreq_cpu_put(policy);
Expand Down Expand Up @@ -870,11 +872,15 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)

#ifdef CONFIG_HOTPLUG_CPU
/* Check if this cpu was hot-unplugged earlier and has siblings */
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_online_cpu(sibling) {
struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
if (cp && cpumask_test_cpu(cpu, cp->related_cpus))
if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return cpufreq_add_policy_cpu(cpu, sibling, dev);
}
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
#endif

Expand All @@ -899,8 +905,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)

/* Initially set CPU itself as the policy_cpu */
per_cpu(cpufreq_policy_cpu, cpu) = cpu;
ret = (lock_policy_rwsem_write(cpu) < 0);
WARN_ON(ret);

init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
Expand All @@ -911,7 +915,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
ret = cpufreq_driver->init(policy);
if (ret) {
pr_debug("initialization failed\n");
goto err_unlock_policy;
goto err_set_policy_cpu;
}

/* related cpus should atleast have policy->cpus */
Expand Down Expand Up @@ -942,8 +946,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
if (ret)
goto err_out_unregister;

unlock_policy_rwsem_write(cpu);

kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
pr_debug("initialization complete\n");
Expand All @@ -959,8 +961,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);

err_unlock_policy:
unlock_policy_rwsem_write(cpu);
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);
Expand Down Expand Up @@ -1008,12 +1010,14 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);

spin_lock_irqsave(&cpufreq_driver_lock, flags);

data = per_cpu(cpufreq_cpu_data, cpu);
per_cpu(cpufreq_cpu_data, cpu) = NULL;

spin_unlock_irqrestore(&cpufreq_driver_lock, flags);

if (!data) {
pr_debug("%s: No cpu_data found\n", __func__);
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
unlock_policy_rwsem_write(cpu);
return -EINVAL;
}

Expand All @@ -1025,9 +1029,10 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
CPUFREQ_NAME_LEN);
#endif

per_cpu(cpufreq_cpu_data, cpu) = NULL;
WARN_ON(lock_policy_rwsem_write(cpu));
cpus = cpumask_weight(data->cpus);
cpumask_clear_cpu(cpu, data->cpus);
unlock_policy_rwsem_write(cpu);

if (cpu != data->cpu) {
sysfs_remove_link(&dev->kobj, "cpufreq");
Expand All @@ -1038,31 +1043,37 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
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(cpu));
cpumask_set_cpu(cpu, data->cpus);
ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
"cpufreq");

spin_lock_irqsave(&cpufreq_driver_lock, flags);
per_cpu(cpufreq_cpu_data, cpu) = data;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);

unlock_policy_rwsem_write(cpu);

ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
"cpufreq");
return -EINVAL;
}

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

spin_unlock_irqrestore(&cpufreq_driver_lock, flags);

pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
cpufreq_cpu_put(data);
unlock_policy_rwsem_write(cpu);

/* If cpu is last user of policy, free policy */
if (cpus == 1) {
lock_policy_rwsem_write(cpu);
lock_policy_rwsem_read(cpu);
kobj = &data->kobj;
cmp = &data->kobj_unregister;
unlock_policy_rwsem_write(cpu);
unlock_policy_rwsem_read(cpu);
kobject_put(kobj);

/* we need to make sure that the underlying kobj is actually
Expand All @@ -1073,10 +1084,8 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
wait_for_completion(cmp);
pr_debug("wait complete\n");

lock_policy_rwsem_write(cpu);
if (cpufreq_driver->exit)
cpufreq_driver->exit(data);
unlock_policy_rwsem_write(cpu);

free_cpumask_var(data->related_cpus);
free_cpumask_var(data->cpus);
Expand All @@ -1086,6 +1095,7 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
}

per_cpu(cpufreq_policy_cpu, cpu) = -1;
return 0;
}

Expand All @@ -1098,9 +1108,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu))
return 0;

if (unlikely(lock_policy_rwsem_write(cpu)))
BUG();

retval = __cpufreq_remove_dev(dev, sif);
return retval;
}
Expand Down Expand Up @@ -1791,9 +1798,6 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
if (unlikely(lock_policy_rwsem_write(cpu)))
BUG();

__cpufreq_remove_dev(dev, NULL);
break;
case CPU_DOWN_FAILED:
Expand Down

0 comments on commit fc10dfd

Please sign in to comment.