Skip to content

Commit

Permalink
PM / devfreq: map devfreq drivers to governor using name
Browse files Browse the repository at this point in the history
Allow devfreq drivers to register a preferred governor name
and when the devfreq governor loads itself at a later point
required drivers are managed appropriately, at the time of
unload of a devfreq governor, stop managing those drivers
as well.

Since the governor structures do not need to be exposed
anymore, remove the definitions and make them static

NOTE: devfreq_list_lock is now used to protect governor
start and stop - as this allows us to protect governors and
devfreq with the proper dependencies as needed.

As part of this change, change the registration of exynos
bus driver to request for ondemand using the governor name.

Cc: Rajagopal Venkat <rajagopal.venkat@linaro.org>
Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Kevin Hilman <khilman@ti.com>
Cc: linux-pm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Signed-off-by: Nishanth Menon <nm@ti.com>
[Merge conflict resolved by MyungJoo Ham]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
  • Loading branch information
Nishanth Menon authored and MyungJoo Ham committed Nov 20, 2012
1 parent 83116e6 commit 1b5c1be
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 30 deletions.
95 changes: 87 additions & 8 deletions drivers/devfreq/devfreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand All @@ -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__);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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) {
Expand All @@ -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);

Expand All @@ -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) {
Expand All @@ -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:
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/devfreq/exynos4_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion drivers/devfreq/governor_performance.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion drivers/devfreq/governor_powersave.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion drivers/devfreq/governor_simpleondemand.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion drivers/devfreq/governor_userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
21 changes: 4 additions & 17 deletions include/linux/devfreq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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__ */

0 comments on commit 1b5c1be

Please sign in to comment.