diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-09-12 13:04:11 +0200 | 
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-09-12 13:04:11 +0200 | 
| commit | f1728fd1599112239ed5cebc7be9810264db6792 (patch) | |
| tree | de36bb207a71db98c7170b57c557017e340831b7 | |
| parent | 0df03a30c333d67ee9b4c37f32d423624f48fe05 (diff) | |
| parent | 44871c9c7f7963f8869dd8bc9620221c9e9db153 (diff) | |
| download | linux-f1728fd1599112239ed5cebc7be9810264db6792.tar.bz2 | |
Merge branch 'pm-cpufreq'
* pm-cpufreq:
  cpufreq: Acquire the lock in cpufreq_policy_restore() for reading
  cpufreq: Prevent problems in update_policy_cpu() if last_cpu == new_cpu
  cpufreq: Restructure if/else block to avoid unintended behavior
  cpufreq: Fix crash in cpufreq-stats during suspend/resume
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 49 | 
1 files changed, 32 insertions, 17 deletions
| diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5a64f66d36e0..43c24aa756f6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -906,11 +906,11 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)  	struct cpufreq_policy *policy;  	unsigned long flags; -	write_lock_irqsave(&cpufreq_driver_lock, flags); +	read_lock_irqsave(&cpufreq_driver_lock, flags);  	policy = per_cpu(cpufreq_cpu_data_fallback, cpu); -	write_unlock_irqrestore(&cpufreq_driver_lock, flags); +	read_unlock_irqrestore(&cpufreq_driver_lock, flags);  	return policy;  } @@ -947,6 +947,21 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)  	kfree(policy);  } +static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) +{ +	if (cpu == policy->cpu) +		return; + +	policy->last_cpu = policy->cpu; +	policy->cpu = cpu; + +#ifdef CONFIG_CPU_FREQ_TABLE +	cpufreq_frequency_table_update_policy_cpu(policy); +#endif +	blocking_notifier_call_chain(&cpufreq_policy_notifier_list, +			CPUFREQ_UPDATE_POLICY_CPU, policy); +} +  static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,  			     bool frozen)  { @@ -1000,7 +1015,18 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,  	if (!policy)  		goto nomem_out; -	policy->cpu = cpu; + +	/* +	 * In the resume path, since we restore a saved policy, the assignment +	 * to policy->cpu is like an update of the existing policy, rather than +	 * the creation of a brand new one. So we need to perform this update +	 * by invoking update_policy_cpu(). +	 */ +	if (frozen && cpu != policy->cpu) +		update_policy_cpu(policy, cpu); +	else +		policy->cpu = cpu; +  	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;  	cpumask_copy(policy->cpus, cpumask_of(cpu)); @@ -1092,18 +1118,6 @@ 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) -{ -	policy->last_cpu = policy->cpu; -	policy->cpu = cpu; - -#ifdef CONFIG_CPU_FREQ_TABLE -	cpufreq_frequency_table_update_policy_cpu(policy); -#endif -	blocking_notifier_call_chain(&cpufreq_policy_notifier_list, -			CPUFREQ_UPDATE_POLICY_CPU, policy); -} -  static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,  					   unsigned int old_cpu, bool frozen)  { @@ -1182,8 +1196,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,  		cpumask_clear_cpu(cpu, policy->cpus);  	unlock_policy_rwsem_write(cpu); -	if (cpu != policy->cpu && !frozen) { -		sysfs_remove_link(&dev->kobj, "cpufreq"); +	if (cpu != policy->cpu) { +		if (!frozen) +			sysfs_remove_link(&dev->kobj, "cpufreq");  	} else if (cpus > 1) {  		new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); |