diff options
Diffstat (limited to 'drivers/devfreq/devfreq.c')
| -rw-r--r-- | drivers/devfreq/devfreq.c | 118 | 
1 files changed, 88 insertions, 30 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 4c49bb1330b5..141413067b5c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -11,6 +11,7 @@   */  #include <linux/kernel.h> +#include <linux/kmod.h>  #include <linux/sched.h>  #include <linux/errno.h>  #include <linux/err.h> @@ -28,9 +29,6 @@  #include <linux/of.h>  #include "governor.h" -#define MAX(a,b)	((a > b) ? a : b) -#define MIN(a,b)	((a < b) ? a : b) -  static struct class *devfreq_class;  /* @@ -221,6 +219,49 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)  	return ERR_PTR(-ENODEV);  } +/** + * try_then_request_governor() - Try to find the governor and request the + *                               module if is not found. + * @name:	name of the governor + * + * Search the list of devfreq governors and request the module and try again + * if is not found. This can happen when both drivers (the governor driver + * and the driver that call devfreq_add_device) are built as modules. + * devfreq_list_lock should be held by the caller. Returns the matched + * governor's pointer. + */ +static struct devfreq_governor *try_then_request_governor(const char *name) +{ +	struct devfreq_governor *governor; +	int err = 0; + +	if (IS_ERR_OR_NULL(name)) { +		pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); +		return ERR_PTR(-EINVAL); +	} +	WARN(!mutex_is_locked(&devfreq_list_lock), +	     "devfreq_list_lock must be locked."); + +	governor = find_devfreq_governor(name); +	if (IS_ERR(governor)) { +		mutex_unlock(&devfreq_list_lock); + +		if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND, +			     DEVFREQ_NAME_LEN)) +			err = request_module("governor_%s", "simpleondemand"); +		else +			err = request_module("governor_%s", name); +		/* Restore previous state before return */ +		mutex_lock(&devfreq_list_lock); +		if (err) +			return NULL; + +		governor = find_devfreq_governor(name); +	} + +	return governor; +} +  static int devfreq_notify_transition(struct devfreq *devfreq,  		struct devfreq_freqs *freqs, unsigned int state)  { @@ -280,14 +321,14 @@ int update_devfreq(struct devfreq *devfreq)  	 * max_freq  	 * min_freq  	 */ -	max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq); -	min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq); +	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq); +	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq); -	if (min_freq && freq < min_freq) { +	if (freq < min_freq) {  		freq = min_freq;  		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */  	} -	if (max_freq && freq > max_freq) { +	if (freq > max_freq) {  		freq = max_freq;  		flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */  	} @@ -534,10 +575,6 @@ static void devfreq_dev_release(struct device *dev)  	list_del(&devfreq->node);  	mutex_unlock(&devfreq_list_lock); -	if (devfreq->governor) -		devfreq->governor->event_handler(devfreq, -						 DEVFREQ_GOV_STOP, NULL); -  	if (devfreq->profile->exit)  		devfreq->profile->exit(devfreq->dev.parent); @@ -646,9 +683,8 @@ struct devfreq *devfreq_add_device(struct device *dev,  	mutex_unlock(&devfreq->lock);  	mutex_lock(&devfreq_list_lock); -	list_add(&devfreq->node, &devfreq_list); -	governor = find_devfreq_governor(devfreq->governor_name); +	governor = try_then_request_governor(devfreq->governor_name);  	if (IS_ERR(governor)) {  		dev_err(dev, "%s: Unable to find governor for the device\n",  			__func__); @@ -664,19 +700,20 @@ struct devfreq *devfreq_add_device(struct device *dev,  			__func__);  		goto err_init;  	} + +	list_add(&devfreq->node, &devfreq_list); +  	mutex_unlock(&devfreq_list_lock);  	return devfreq;  err_init: -	list_del(&devfreq->node);  	mutex_unlock(&devfreq_list_lock); -	device_unregister(&devfreq->dev); +	devfreq_remove_device(devfreq);  	devfreq = NULL;  err_dev: -	if (devfreq) -		kfree(devfreq); +	kfree(devfreq);  err_out:  	return ERR_PTR(err);  } @@ -693,6 +730,9 @@ int devfreq_remove_device(struct devfreq *devfreq)  	if (!devfreq)  		return -EINVAL; +	if (devfreq->governor) +		devfreq->governor->event_handler(devfreq, +						 DEVFREQ_GOV_STOP, NULL);  	device_unregister(&devfreq->dev);  	return 0; @@ -991,7 +1031,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,  		return -EINVAL;  	mutex_lock(&devfreq_list_lock); -	governor = find_devfreq_governor(str_governor); +	governor = try_then_request_governor(str_governor);  	if (IS_ERR(governor)) {  		ret = PTR_ERR(governor);  		goto out; @@ -1126,17 +1166,26 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,  	struct devfreq *df = to_devfreq(dev);  	unsigned long value;  	int ret; -	unsigned long max;  	ret = sscanf(buf, "%lu", &value);  	if (ret != 1)  		return -EINVAL;  	mutex_lock(&df->lock); -	max = df->max_freq; -	if (value && max && value > max) { -		ret = -EINVAL; -		goto unlock; + +	if (value) { +		if (value > df->max_freq) { +			ret = -EINVAL; +			goto unlock; +		} +	} else { +		unsigned long *freq_table = df->profile->freq_table; + +		/* Get minimum frequency according to sorting order */ +		if (freq_table[0] < freq_table[df->profile->max_state - 1]) +			value = freq_table[0]; +		else +			value = freq_table[df->profile->max_state - 1];  	}  	df->min_freq = value; @@ -1152,7 +1201,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,  {  	struct devfreq *df = to_devfreq(dev); -	return sprintf(buf, "%lu\n", MAX(df->scaling_min_freq, df->min_freq)); +	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));  }  static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, @@ -1161,17 +1210,26 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,  	struct devfreq *df = to_devfreq(dev);  	unsigned long value;  	int ret; -	unsigned long min;  	ret = sscanf(buf, "%lu", &value);  	if (ret != 1)  		return -EINVAL;  	mutex_lock(&df->lock); -	min = df->min_freq; -	if (value && min && value < min) { -		ret = -EINVAL; -		goto unlock; + +	if (value) { +		if (value < df->min_freq) { +			ret = -EINVAL; +			goto unlock; +		} +	} else { +		unsigned long *freq_table = df->profile->freq_table; + +		/* Get maximum frequency according to sorting order */ +		if (freq_table[0] < freq_table[df->profile->max_state - 1]) +			value = freq_table[df->profile->max_state - 1]; +		else +			value = freq_table[0];  	}  	df->max_freq = value; @@ -1188,7 +1246,7 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,  {  	struct devfreq *df = to_devfreq(dev); -	return sprintf(buf, "%lu\n", MIN(df->scaling_max_freq, df->max_freq)); +	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));  }  static DEVICE_ATTR_RW(max_freq);  | 
