diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 130 | 
1 files changed, 74 insertions, 56 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0128de3603df..02ab56b2a0d8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -50,7 +50,9 @@ static LIST_HEAD(cpufreq_governor_list);  #define for_each_governor(__governor)				\  	list_for_each_entry(__governor, &cpufreq_governor_list, governor_list) -/** +static char default_governor[CPUFREQ_NAME_LEN]; + +/*   * The "cpufreq driver" - the arch- or hardware-dependent low   * level driver of CPUFreq support, and its spinlock. This lock   * also protects the cpufreq_cpu_data array. @@ -71,14 +73,12 @@ static inline bool has_target(void)  static unsigned int __cpufreq_get(struct cpufreq_policy *policy);  static int cpufreq_init_governor(struct cpufreq_policy *policy);  static void cpufreq_exit_governor(struct cpufreq_policy *policy); -static int cpufreq_start_governor(struct cpufreq_policy *policy); -static void cpufreq_stop_governor(struct cpufreq_policy *policy);  static void cpufreq_governor_limits(struct cpufreq_policy *policy);  static int cpufreq_set_policy(struct cpufreq_policy *policy,  			      struct cpufreq_governor *new_gov,  			      unsigned int new_pol); -/** +/*   * Two notifier lists: the "policy" list is involved in the   * validation process for a new CPU frequency policy; the   * "transition" list for kernel code that needs to handle @@ -298,7 +298,7 @@ struct cpufreq_policy *cpufreq_cpu_acquire(unsigned int cpu)   *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *   *********************************************************************/ -/** +/*   * adjust_jiffies - adjust the system "loops_per_jiffy"   *   * This function alters the system "loops_per_jiffy" for the clock @@ -524,6 +524,7 @@ EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch);  /**   * cpufreq_driver_resolve_freq - Map a target frequency to a driver-supported   * one. + * @policy: associated policy to interrogate   * @target_freq: target frequency to resolve.   *   * The target to driver frequency mapping is cached in the policy. @@ -538,7 +539,7 @@ unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,  	policy->cached_target_freq = target_freq;  	if (cpufreq_driver->target_index) { -		int idx; +		unsigned int idx;  		idx = cpufreq_frequency_table_target(policy, target_freq,  						     CPUFREQ_RELATION_L); @@ -621,6 +622,24 @@ static struct cpufreq_governor *find_governor(const char *str_governor)  	return NULL;  } +static struct cpufreq_governor *get_governor(const char *str_governor) +{ +	struct cpufreq_governor *t; + +	mutex_lock(&cpufreq_governor_mutex); +	t = find_governor(str_governor); +	if (!t) +		goto unlock; + +	if (!try_module_get(t->owner)) +		t = NULL; + +unlock: +	mutex_unlock(&cpufreq_governor_mutex); + +	return t; +} +  static unsigned int cpufreq_parse_policy(char *str_governor)  {  	if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) @@ -640,31 +659,17 @@ static struct cpufreq_governor *cpufreq_parse_governor(char *str_governor)  {  	struct cpufreq_governor *t; -	mutex_lock(&cpufreq_governor_mutex); - -	t = find_governor(str_governor); -	if (!t) { -		int ret; - -		mutex_unlock(&cpufreq_governor_mutex); - -		ret = request_module("cpufreq_%s", str_governor); -		if (ret) -			return NULL; +	t = get_governor(str_governor); +	if (t) +		return t; -		mutex_lock(&cpufreq_governor_mutex); - -		t = find_governor(str_governor); -	} -	if (t && !try_module_get(t->owner)) -		t = NULL; - -	mutex_unlock(&cpufreq_governor_mutex); +	if (request_module("cpufreq_%s", str_governor)) +		return NULL; -	return t; +	return get_governor(str_governor);  } -/** +/*   * cpufreq_per_cpu_attr_read() / show_##file_name() -   * print out cpufreq information   * @@ -706,7 +711,7 @@ static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)  	return ret;  } -/** +/*   * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access   */  #define store_one(file_name, object)			\ @@ -727,7 +732,7 @@ static ssize_t store_##file_name					\  store_one(scaling_min_freq, min);  store_one(scaling_max_freq, max); -/** +/*   * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware   */  static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, @@ -741,7 +746,7 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,  	return sprintf(buf, "<unknown>\n");  } -/** +/*   * show_scaling_governor - show the current policy for the specified CPU   */  static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) @@ -756,7 +761,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)  	return -EINVAL;  } -/** +/*   * store_scaling_governor - store policy for the specified CPU   */  static ssize_t store_scaling_governor(struct cpufreq_policy *policy, @@ -793,7 +798,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,  	return ret ? ret : count;  } -/** +/*   * show_scaling_driver - show the cpufreq driver currently loaded   */  static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) @@ -801,7 +806,7 @@ static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)  	return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name);  } -/** +/*   * show_scaling_available_governors - show the available CPUfreq governors   */  static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, @@ -815,12 +820,14 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,  		goto out;  	} +	mutex_lock(&cpufreq_governor_mutex);  	for_each_governor(t) {  		if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))  		    - (CPUFREQ_NAME_LEN + 2))) -			goto out; +			break;  		i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name);  	} +	mutex_unlock(&cpufreq_governor_mutex);  out:  	i += sprintf(&buf[i], "\n");  	return i; @@ -843,7 +850,7 @@ ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf)  }  EXPORT_SYMBOL_GPL(cpufreq_show_cpus); -/** +/*   * show_related_cpus - show the CPUs affected by each transition even if   * hw coordination is in use   */ @@ -852,7 +859,7 @@ static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)  	return cpufreq_show_cpus(policy->related_cpus, buf);  } -/** +/*   * show_affected_cpus - show the CPUs affected by each transition   */  static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) @@ -886,7 +893,7 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)  	return policy->governor->show_setspeed(policy, buf);  } -/** +/*   * show_bios_limit - show the current cpufreq HW/BIOS limitation   */  static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) @@ -1048,36 +1055,36 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy)  	return 0;  } -__weak struct cpufreq_governor *cpufreq_default_governor(void) -{ -	return NULL; -} -  static int cpufreq_init_policy(struct cpufreq_policy *policy)  { -	struct cpufreq_governor *def_gov = cpufreq_default_governor();  	struct cpufreq_governor *gov = NULL;  	unsigned int pol = CPUFREQ_POLICY_UNKNOWN; +	int ret;  	if (has_target()) {  		/* Update policy governor to the one used before hotplug. */ -		gov = find_governor(policy->last_governor); +		gov = get_governor(policy->last_governor);  		if (gov) {  			pr_debug("Restoring governor %s for cpu %d\n", -				 policy->governor->name, policy->cpu); -		} else if (def_gov) { -			gov = def_gov; +				 gov->name, policy->cpu);  		} else { -			return -ENODATA; +			gov = get_governor(default_governor); +		} + +		if (!gov) { +			gov = cpufreq_default_governor(); +			__module_get(gov->owner);  		} +  	} else { +  		/* Use the default policy if there is no last_policy. */  		if (policy->last_policy) {  			pol = policy->last_policy; -		} else if (def_gov) { -			pol = cpufreq_parse_policy(def_gov->name); +		} else { +			pol = cpufreq_parse_policy(default_governor);  			/* -			 * In case the default governor is neiter "performance" +			 * In case the default governor is neither "performance"  			 * nor "powersave", fall back to the initial policy  			 * value set by the driver.  			 */ @@ -1089,7 +1096,11 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)  			return -ENODATA;  	} -	return cpufreq_set_policy(policy, gov, pol); +	ret = cpufreq_set_policy(policy, gov, pol); +	if (gov) +		module_put(gov->owner); + +	return ret;  }  static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) @@ -1604,7 +1615,7 @@ unlock:  	return 0;  } -/** +/*   * cpufreq_remove_dev - remove a CPU device   *   * Removes the cpufreq interface for a CPU device. @@ -2253,7 +2264,7 @@ static void cpufreq_exit_governor(struct cpufreq_policy *policy)  	module_put(policy->governor->owner);  } -static int cpufreq_start_governor(struct cpufreq_policy *policy) +int cpufreq_start_governor(struct cpufreq_policy *policy)  {  	int ret; @@ -2280,7 +2291,7 @@ static int cpufreq_start_governor(struct cpufreq_policy *policy)  	return 0;  } -static void cpufreq_stop_governor(struct cpufreq_policy *policy) +void cpufreq_stop_governor(struct cpufreq_policy *policy)  {  	if (cpufreq_suspended || !policy->governor)  		return; @@ -2361,6 +2372,7 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);   * cpufreq_get_policy - get the current cpufreq_policy   * @policy: struct cpufreq_policy into which the current cpufreq_policy   *	is written + * @cpu: CPU to find the policy for   *   * Reads the current cpufreq policy.   */ @@ -2747,7 +2759,7 @@ out:  }  EXPORT_SYMBOL_GPL(cpufreq_register_driver); -/** +/*   * cpufreq_unregister_driver - unregister the current CPUFreq driver   *   * Unregister the current CPUFreq driver. Only call this if you have @@ -2783,13 +2795,19 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);  static int __init cpufreq_core_init(void)  { +	struct cpufreq_governor *gov = cpufreq_default_governor(); +  	if (cpufreq_disabled())  		return -ENODEV;  	cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);  	BUG_ON(!cpufreq_global_kobject); +	if (!strlen(default_governor)) +		strncpy(default_governor, gov->name, CPUFREQ_NAME_LEN); +  	return 0;  }  module_param(off, int, 0444); +module_param_string(default_governor, default_governor, CPUFREQ_NAME_LEN, 0444);  core_initcall(cpufreq_core_init);  |