mirror of
https://github.com/torvalds/linux.git
synced 2024-10-23 13:40:56 +00:00
PM / devfreq: provide hooks for governors to be registered
Add devfreq_add_governor and devfreq_remove_governor which can be invoked by governors to register with devfreq. This sets up the stage to dynamically switch governors and allow governors to be dynamically loaded as well. 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> Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
This commit is contained in:
parent
2df5021fa9
commit
3aa173b8db
|
@ -36,6 +36,8 @@ static struct class *devfreq_class;
|
||||||
*/
|
*/
|
||||||
static struct workqueue_struct *devfreq_wq;
|
static struct workqueue_struct *devfreq_wq;
|
||||||
|
|
||||||
|
/* The list of all device-devfreq governors */
|
||||||
|
static LIST_HEAD(devfreq_governor_list);
|
||||||
/* The list of all device-devfreq */
|
/* The list of all device-devfreq */
|
||||||
static LIST_HEAD(devfreq_list);
|
static LIST_HEAD(devfreq_list);
|
||||||
static DEFINE_MUTEX(devfreq_list_lock);
|
static DEFINE_MUTEX(devfreq_list_lock);
|
||||||
|
@ -111,6 +113,32 @@ static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_devfreq_governor() - find devfreq governor from name
|
||||||
|
* @name: name of the governor
|
||||||
|
*
|
||||||
|
* Search the list of devfreq governors and return the matched
|
||||||
|
* governor's pointer. devfreq_list_lock should be held by the caller.
|
||||||
|
*/
|
||||||
|
static struct devfreq_governor *find_devfreq_governor(const char *name)
|
||||||
|
{
|
||||||
|
struct devfreq_governor *tmp_governor;
|
||||||
|
|
||||||
|
if (unlikely(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.");
|
||||||
|
|
||||||
|
list_for_each_entry(tmp_governor, &devfreq_governor_list, node) {
|
||||||
|
if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN))
|
||||||
|
return tmp_governor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
/* Load monitoring helper functions for governors use */
|
/* Load monitoring helper functions for governors use */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -515,6 +543,69 @@ int devfreq_resume_device(struct devfreq *devfreq)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(devfreq_resume_device);
|
EXPORT_SYMBOL(devfreq_resume_device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devfreq_add_governor() - Add devfreq governor
|
||||||
|
* @governor: the devfreq governor to be added
|
||||||
|
*/
|
||||||
|
int devfreq_add_governor(struct devfreq_governor *governor)
|
||||||
|
{
|
||||||
|
struct devfreq_governor *g;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!governor) {
|
||||||
|
pr_err("%s: Invalid parameters.\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&devfreq_list_lock);
|
||||||
|
g = find_devfreq_governor(governor->name);
|
||||||
|
if (!IS_ERR(g)) {
|
||||||
|
pr_err("%s: governor %s already registered\n", __func__,
|
||||||
|
g->name);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add(&governor->node, &devfreq_governor_list);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
mutex_unlock(&devfreq_list_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(devfreq_add_governor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devfreq_remove_device() - Remove devfreq feature from a device.
|
||||||
|
* @governor: the devfreq governor to be removed
|
||||||
|
*/
|
||||||
|
int devfreq_remove_governor(struct devfreq_governor *governor)
|
||||||
|
{
|
||||||
|
struct devfreq_governor *g;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!governor) {
|
||||||
|
pr_err("%s: Invalid parameters.\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&devfreq_list_lock);
|
||||||
|
g = find_devfreq_governor(governor->name);
|
||||||
|
if (IS_ERR(g)) {
|
||||||
|
pr_err("%s: governor %s not registered\n", __func__,
|
||||||
|
g->name);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&governor->node);
|
||||||
|
err_out:
|
||||||
|
mutex_unlock(&devfreq_list_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(devfreq_remove_governor);
|
||||||
|
|
||||||
static ssize_t show_governor(struct device *dev,
|
static ssize_t show_governor(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,4 +34,8 @@ extern void devfreq_monitor_suspend(struct devfreq *devfreq);
|
||||||
extern void devfreq_monitor_resume(struct devfreq *devfreq);
|
extern void devfreq_monitor_resume(struct devfreq *devfreq);
|
||||||
extern void devfreq_interval_update(struct devfreq *devfreq,
|
extern void devfreq_interval_update(struct devfreq *devfreq,
|
||||||
unsigned int *delay);
|
unsigned int *delay);
|
||||||
|
|
||||||
|
extern int devfreq_add_governor(struct devfreq_governor *governor);
|
||||||
|
extern int devfreq_remove_governor(struct devfreq_governor *governor);
|
||||||
|
|
||||||
#endif /* _GOVERNOR_H */
|
#endif /* _GOVERNOR_H */
|
||||||
|
|
|
@ -92,6 +92,7 @@ struct devfreq_dev_profile {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq_governor - Devfreq policy governor
|
* struct devfreq_governor - Devfreq policy governor
|
||||||
|
* @node: list node - contains registered devfreq governors
|
||||||
* @name: Governor's name
|
* @name: Governor's name
|
||||||
* @get_target_freq: Returns desired operating frequency for the device.
|
* @get_target_freq: Returns desired operating frequency for the device.
|
||||||
* Basically, get_target_freq will run
|
* Basically, get_target_freq will run
|
||||||
|
@ -107,6 +108,8 @@ struct devfreq_dev_profile {
|
||||||
* Note that the callbacks are called with devfreq->lock locked by devfreq.
|
* Note that the callbacks are called with devfreq->lock locked by devfreq.
|
||||||
*/
|
*/
|
||||||
struct devfreq_governor {
|
struct devfreq_governor {
|
||||||
|
struct list_head node;
|
||||||
|
|
||||||
const char name[DEVFREQ_NAME_LEN];
|
const char name[DEVFREQ_NAME_LEN];
|
||||||
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
|
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
|
||||||
int (*event_handler)(struct devfreq *devfreq,
|
int (*event_handler)(struct devfreq *devfreq,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user