mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	cpufreq: make sure frequency transitions are serialized
Whenever we are changing frequency of a cpu, we are calling PRECHANGE and POSTCHANGE notifiers. They must be serialized. i.e. PRECHANGE or POSTCHANGE shouldn't be called twice contiguously. This can happen due to bugs in users of __cpufreq_driver_target() or actual cpufreq drivers who are sending these notifiers. This patch adds some protection against this. Now, we keep track of the last transaction and see if something went wrong. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
		
							parent
							
								
									e11158c0c9
								
							
						
					
					
						commit
						7c30ed532c
					
				
					 2 changed files with 15 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -312,6 +312,12 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
 | 
			
		|||
	switch (state) {
 | 
			
		||||
 | 
			
		||||
	case CPUFREQ_PRECHANGE:
 | 
			
		||||
		if (WARN(policy->transition_ongoing,
 | 
			
		||||
				"In middle of another frequency transition\n"))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		policy->transition_ongoing = true;
 | 
			
		||||
 | 
			
		||||
		/* detect if the driver reported a value as "old frequency"
 | 
			
		||||
		 * which is not equal to what the cpufreq core thinks is
 | 
			
		||||
		 * "old frequency".
 | 
			
		||||
| 
						 | 
				
			
			@ -331,6 +337,12 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
 | 
			
		|||
		break;
 | 
			
		||||
 | 
			
		||||
	case CPUFREQ_POSTCHANGE:
 | 
			
		||||
		if (WARN(!policy->transition_ongoing,
 | 
			
		||||
				"No frequency transition in progress\n"))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		policy->transition_ongoing = false;
 | 
			
		||||
 | 
			
		||||
		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
 | 
			
		||||
		pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
 | 
			
		||||
			(unsigned long)freqs->cpu);
 | 
			
		||||
| 
						 | 
				
			
			@ -1539,6 +1551,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 | 
			
		|||
 | 
			
		||||
	if (cpufreq_disabled())
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	if (policy->transition_ongoing)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	/* Make sure that target_freq is within supported range */
 | 
			
		||||
	if (target_freq > policy->max)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,6 +119,7 @@ struct cpufreq_policy {
 | 
			
		|||
 | 
			
		||||
	struct kobject		kobj;
 | 
			
		||||
	struct completion	kobj_unregister;
 | 
			
		||||
	bool			transition_ongoing; /* Tracks transition status */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CPUFREQ_ADJUST			(0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue