diff options
| -rw-r--r-- | drivers/devfreq/devfreq.c | 95 | ||||
| -rw-r--r-- | drivers/devfreq/exynos4_bus.c | 2 | ||||
| -rw-r--r-- | drivers/devfreq/governor_performance.c | 2 | ||||
| -rw-r--r-- | drivers/devfreq/governor_powersave.c | 2 | ||||
| -rw-r--r-- | drivers/devfreq/governor_simpleondemand.c | 2 | ||||
| -rw-r--r-- | drivers/devfreq/governor_userspace.c | 2 | ||||
| -rw-r--r-- | include/linux/devfreq.h | 21 | 
7 files changed, 96 insertions, 30 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 679ac424472..0d7be03d561 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -159,6 +159,9 @@ int update_devfreq(struct devfreq *devfreq)  		return -EINVAL;  	} +	if (!devfreq->governor) +		return -EINVAL; +  	/* Reevaluate the proper frequency */  	err = devfreq->governor->get_target_freq(devfreq, &freq);  	if (err) @@ -379,7 +382,9 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)  	list_del(&devfreq->node);  	mutex_unlock(&devfreq_list_lock); -	devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL); +	if (devfreq->governor) +		devfreq->governor->event_handler(devfreq, +						 DEVFREQ_GOV_STOP, NULL);  	if (devfreq->profile->exit)  		devfreq->profile->exit(devfreq->dev.parent); @@ -412,19 +417,20 @@ static void devfreq_dev_release(struct device *dev)   * devfreq_add_device() - Add devfreq feature to the device   * @dev:	the device to add devfreq feature.   * @profile:	device-specific profile to run devfreq. - * @governor:	the policy to choose frequency. + * @governor_name:	name of the policy to choose frequency.   * @data:	private data for the governor. The devfreq framework does not   *		touch this value.   */  struct devfreq *devfreq_add_device(struct device *dev,  				   struct devfreq_dev_profile *profile, -				   const struct devfreq_governor *governor, +				   const char *governor_name,  				   void *data)  {  	struct devfreq *devfreq; +	struct devfreq_governor *governor;  	int err = 0; -	if (!dev || !profile || !governor) { +	if (!dev || !profile || !governor_name) {  		dev_err(dev, "%s: Invalid parameters.\n", __func__);  		return ERR_PTR(-EINVAL);  	} @@ -452,7 +458,7 @@ struct devfreq *devfreq_add_device(struct device *dev,  	devfreq->dev.class = devfreq_class;  	devfreq->dev.release = devfreq_dev_release;  	devfreq->profile = profile; -	devfreq->governor = governor; +	strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);  	devfreq->previous_freq = profile->initial_freq;  	devfreq->data = data;  	devfreq->nb.notifier_call = devfreq_notifier_call; @@ -478,10 +484,14 @@ struct devfreq *devfreq_add_device(struct device *dev,  	mutex_lock(&devfreq_list_lock);  	list_add(&devfreq->node, &devfreq_list); -	mutex_unlock(&devfreq_list_lock); -	err = devfreq->governor->event_handler(devfreq, -				DEVFREQ_GOV_START, NULL); +	governor = find_devfreq_governor(devfreq->governor_name); +	if (!IS_ERR(governor)) +		devfreq->governor = governor; +	if (devfreq->governor) +		err = devfreq->governor->event_handler(devfreq, +					DEVFREQ_GOV_START, NULL); +	mutex_unlock(&devfreq_list_lock);  	if (err) {  		dev_err(dev, "%s: Unable to start governor for the device\n",  			__func__); @@ -524,6 +534,9 @@ int devfreq_suspend_device(struct devfreq *devfreq)  	if (!devfreq)  		return -EINVAL; +	if (!devfreq->governor) +		return 0; +  	return devfreq->governor->event_handler(devfreq,  				DEVFREQ_GOV_SUSPEND, NULL);  } @@ -538,6 +551,9 @@ int devfreq_resume_device(struct devfreq *devfreq)  	if (!devfreq)  		return -EINVAL; +	if (!devfreq->governor) +		return 0; +  	return devfreq->governor->event_handler(devfreq,  				DEVFREQ_GOV_RESUME, NULL);  } @@ -550,6 +566,7 @@ EXPORT_SYMBOL(devfreq_resume_device);  int devfreq_add_governor(struct devfreq_governor *governor)  {  	struct devfreq_governor *g; +	struct devfreq *devfreq;  	int err = 0;  	if (!governor) { @@ -568,6 +585,38 @@ int devfreq_add_governor(struct devfreq_governor *governor)  	list_add(&governor->node, &devfreq_governor_list); +	list_for_each_entry(devfreq, &devfreq_list, node) { +		int ret = 0; +		struct device *dev = devfreq->dev.parent; + +		if (!strncmp(devfreq->governor_name, governor->name, +			     DEVFREQ_NAME_LEN)) { +			/* The following should never occur */ +			if (devfreq->governor) { +				dev_warn(dev, +					 "%s: Governor %s already present\n", +					 __func__, devfreq->governor->name); +				ret = devfreq->governor->event_handler(devfreq, +							DEVFREQ_GOV_STOP, NULL); +				if (ret) { +					dev_warn(dev, +						 "%s: Governor %s stop = %d\n", +						 __func__, +						 devfreq->governor->name, ret); +				} +				/* Fall through */ +			} +			devfreq->governor = governor; +			ret = devfreq->governor->event_handler(devfreq, +						DEVFREQ_GOV_START, NULL); +			if (ret) { +				dev_warn(dev, "%s: Governor %s start=%d\n", +					 __func__, devfreq->governor->name, +					 ret); +			} +		} +	} +  err_out:  	mutex_unlock(&devfreq_list_lock); @@ -582,6 +631,7 @@ EXPORT_SYMBOL(devfreq_add_governor);  int devfreq_remove_governor(struct devfreq_governor *governor)  {  	struct devfreq_governor *g; +	struct devfreq *devfreq;  	int err = 0;  	if (!governor) { @@ -597,6 +647,29 @@ int devfreq_remove_governor(struct devfreq_governor *governor)  		err = -EINVAL;  		goto err_out;  	} +	list_for_each_entry(devfreq, &devfreq_list, node) { +		int ret; +		struct device *dev = devfreq->dev.parent; + +		if (!strncmp(devfreq->governor_name, governor->name, +			     DEVFREQ_NAME_LEN)) { +			/* we should have a devfreq governor! */ +			if (!devfreq->governor) { +				dev_warn(dev, "%s: Governor %s NOT present\n", +					 __func__, governor->name); +				continue; +				/* Fall through */ +			} +			ret = devfreq->governor->event_handler(devfreq, +						DEVFREQ_GOV_STOP, NULL); +			if (ret) { +				dev_warn(dev, "%s: Governor %s stop=%d\n", +					 __func__, devfreq->governor->name, +					 ret); +			} +			devfreq->governor = NULL; +		} +	}  	list_del(&governor->node);  err_out: @@ -609,6 +682,9 @@ EXPORT_SYMBOL(devfreq_remove_governor);  static ssize_t show_governor(struct device *dev,  			     struct device_attribute *attr, char *buf)  { +	if (!to_devfreq(dev)->governor) +		return -EINVAL; +  	return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);  } @@ -645,6 +721,9 @@ static ssize_t store_polling_interval(struct device *dev,  	unsigned int value;  	int ret; +	if (!df->governor) +		return -EINVAL; +  	ret = sscanf(buf, "%u", &value);  	if (ret != 1)  		return -EINVAL; diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index 68145316c49..b8ac28497b3 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c @@ -1040,7 +1040,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)  	busfreq_mon_reset(data);  	data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile, -					   &devfreq_simple_ondemand, NULL); +					   "simple_ondemand", NULL);  	if (IS_ERR(data->devfreq))  		return PTR_ERR(data->devfreq); diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index db8ff77dbed..865a3695691 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -40,7 +40,7 @@ static int devfreq_performance_handler(struct devfreq *devfreq,  	return ret;  } -const struct devfreq_governor devfreq_performance = { +static struct devfreq_governor devfreq_performance = {  	.name = "performance",  	.get_target_freq = devfreq_performance_func,  	.event_handler = devfreq_performance_handler, diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 30f0fca8d63..8612c0f96b7 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -37,7 +37,7 @@ static int devfreq_powersave_handler(struct devfreq *devfreq,  	return ret;  } -const struct devfreq_governor devfreq_powersave = { +static struct devfreq_governor devfreq_powersave = {  	.name = "powersave",  	.get_target_freq = devfreq_powersave_func,  	.event_handler = devfreq_powersave_handler, diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 85f9ed531b1..a870a24bb56 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -120,7 +120,7 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,  	return 0;  } -const struct devfreq_governor devfreq_simple_ondemand = { +static struct devfreq_governor devfreq_simple_ondemand = {  	.name = "simple_ondemand",  	.get_target_freq = devfreq_simple_ondemand_func,  	.event_handler = devfreq_simple_ondemand_handler, diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 110f178fec0..34fb80f50cf 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -135,7 +135,7 @@ static int devfreq_userspace_handler(struct devfreq *devfreq,  	return ret;  } -const struct devfreq_governor devfreq_userspace = { +static struct devfreq_governor devfreq_userspace = {  	.name = "userspace",  	.get_target_freq = devfreq_userspace_func,  	.event_handler = devfreq_userspace_handler, diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 6484a3f8dda..235248cb2c9 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -125,6 +125,7 @@ struct devfreq_governor {   *		using devfreq.   * @profile:	device-specific devfreq profile   * @governor:	method how to choose frequency based on the usage. + * @governor_name:	devfreq governor name for use with this devfreq   * @nb:		notifier block used to notify devfreq object that it should   *		reevaluate operable frequencies. Devfreq users may use   *		devfreq.nb to the corresponding register notifier call chain. @@ -155,6 +156,7 @@ struct devfreq {  	struct device dev;  	struct devfreq_dev_profile *profile;  	const struct devfreq_governor *governor; +	char governor_name[DEVFREQ_NAME_LEN];  	struct notifier_block nb;  	struct delayed_work work; @@ -176,7 +178,7 @@ struct devfreq {  #if defined(CONFIG_PM_DEVFREQ)  extern struct devfreq *devfreq_add_device(struct device *dev,  				  struct devfreq_dev_profile *profile, -				  const struct devfreq_governor *governor, +				  const char *governor_name,  				  void *data);  extern int devfreq_remove_device(struct devfreq *devfreq);  extern int devfreq_suspend_device(struct devfreq *devfreq); @@ -190,17 +192,7 @@ extern int devfreq_register_opp_notifier(struct device *dev,  extern int devfreq_unregister_opp_notifier(struct device *dev,  					   struct devfreq *devfreq); -#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE -extern const struct devfreq_governor devfreq_powersave; -#endif -#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE -extern const struct devfreq_governor devfreq_performance; -#endif -#ifdef CONFIG_DEVFREQ_GOV_USERSPACE -extern const struct devfreq_governor devfreq_userspace; -#endif  #ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND -extern const struct devfreq_governor devfreq_simple_ondemand;  /**   * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq   *	and devfreq_add_device @@ -223,7 +215,7 @@ struct devfreq_simple_ondemand_data {  #else /* !CONFIG_PM_DEVFREQ */  static struct devfreq *devfreq_add_device(struct device *dev,  					  struct devfreq_dev_profile *profile, -					  struct devfreq_governor *governor, +					  const char *governor_name,  					  void *data)  {  	return NULL; @@ -262,11 +254,6 @@ static int devfreq_unregister_opp_notifier(struct device *dev,  	return -EINVAL;  } -#define devfreq_powersave	NULL -#define devfreq_performance	NULL -#define devfreq_userspace	NULL -#define devfreq_simple_ondemand	NULL -  #endif /* CONFIG_PM_DEVFREQ */  #endif /* __LINUX_DEVFREQ_H__ */  |