forked from Minki/linux
cpuidle: allow governor switch on cpuidle_register_driver()
The recently introduced haltpoll driver is largely only useful with haltpoll governor. To allow drivers to associate with a particular idle behaviour, add a @governor property to 'struct cpuidle_driver' and thus allow a cpuidle driver to switch to a *preferred* governor on idle driver registration. We save the previous governor, and when an idle driver is unregistered we switch back to that. The @governor can be overridden by cpuidle.governor= boot param or alternatively be ignored if the governor doesn't exist. Signed-off-by: Joao Martins <joao.m.martins@oracle.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
cd4c076306
commit
cb5d8c45ab
@ -9,6 +9,7 @@
|
|||||||
/* For internal use only */
|
/* For internal use only */
|
||||||
extern char param_governor[];
|
extern char param_governor[];
|
||||||
extern struct cpuidle_governor *cpuidle_curr_governor;
|
extern struct cpuidle_governor *cpuidle_curr_governor;
|
||||||
|
extern struct cpuidle_governor *cpuidle_prev_governor;
|
||||||
extern struct list_head cpuidle_governors;
|
extern struct list_head cpuidle_governors;
|
||||||
extern struct list_head cpuidle_detected_devices;
|
extern struct list_head cpuidle_detected_devices;
|
||||||
extern struct mutex cpuidle_lock;
|
extern struct mutex cpuidle_lock;
|
||||||
@ -22,6 +23,7 @@ extern void cpuidle_install_idle_handler(void);
|
|||||||
extern void cpuidle_uninstall_idle_handler(void);
|
extern void cpuidle_uninstall_idle_handler(void);
|
||||||
|
|
||||||
/* governors */
|
/* governors */
|
||||||
|
extern struct cpuidle_governor *cpuidle_find_governor(const char *str);
|
||||||
extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
|
extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
|
||||||
|
|
||||||
/* sysfs */
|
/* sysfs */
|
||||||
|
@ -254,12 +254,25 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
|
|||||||
*/
|
*/
|
||||||
int cpuidle_register_driver(struct cpuidle_driver *drv)
|
int cpuidle_register_driver(struct cpuidle_driver *drv)
|
||||||
{
|
{
|
||||||
|
struct cpuidle_governor *gov;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
spin_lock(&cpuidle_driver_lock);
|
spin_lock(&cpuidle_driver_lock);
|
||||||
ret = __cpuidle_register_driver(drv);
|
ret = __cpuidle_register_driver(drv);
|
||||||
spin_unlock(&cpuidle_driver_lock);
|
spin_unlock(&cpuidle_driver_lock);
|
||||||
|
|
||||||
|
if (!ret && !strlen(param_governor) && drv->governor &&
|
||||||
|
(cpuidle_get_driver() == drv)) {
|
||||||
|
mutex_lock(&cpuidle_lock);
|
||||||
|
gov = cpuidle_find_governor(drv->governor);
|
||||||
|
if (gov) {
|
||||||
|
cpuidle_prev_governor = cpuidle_curr_governor;
|
||||||
|
if (cpuidle_switch_governor(gov) < 0)
|
||||||
|
cpuidle_prev_governor = NULL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&cpuidle_lock);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpuidle_register_driver);
|
EXPORT_SYMBOL_GPL(cpuidle_register_driver);
|
||||||
@ -274,9 +287,21 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver);
|
|||||||
*/
|
*/
|
||||||
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
|
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
|
||||||
{
|
{
|
||||||
|
bool enabled = (cpuidle_get_driver() == drv);
|
||||||
|
|
||||||
spin_lock(&cpuidle_driver_lock);
|
spin_lock(&cpuidle_driver_lock);
|
||||||
__cpuidle_unregister_driver(drv);
|
__cpuidle_unregister_driver(drv);
|
||||||
spin_unlock(&cpuidle_driver_lock);
|
spin_unlock(&cpuidle_driver_lock);
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&cpuidle_lock);
|
||||||
|
if (cpuidle_prev_governor) {
|
||||||
|
if (!cpuidle_switch_governor(cpuidle_prev_governor))
|
||||||
|
cpuidle_prev_governor = NULL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&cpuidle_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
|
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
|
||||||
|
|
||||||
|
@ -20,14 +20,15 @@ char param_governor[CPUIDLE_NAME_LEN];
|
|||||||
|
|
||||||
LIST_HEAD(cpuidle_governors);
|
LIST_HEAD(cpuidle_governors);
|
||||||
struct cpuidle_governor *cpuidle_curr_governor;
|
struct cpuidle_governor *cpuidle_curr_governor;
|
||||||
|
struct cpuidle_governor *cpuidle_prev_governor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __cpuidle_find_governor - finds a governor of the specified name
|
* cpuidle_find_governor - finds a governor of the specified name
|
||||||
* @str: the name
|
* @str: the name
|
||||||
*
|
*
|
||||||
* Must be called with cpuidle_lock acquired.
|
* Must be called with cpuidle_lock acquired.
|
||||||
*/
|
*/
|
||||||
static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
|
struct cpuidle_governor *cpuidle_find_governor(const char *str)
|
||||||
{
|
{
|
||||||
struct cpuidle_governor *gov;
|
struct cpuidle_governor *gov;
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ int cpuidle_register_governor(struct cpuidle_governor *gov)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
mutex_lock(&cpuidle_lock);
|
mutex_lock(&cpuidle_lock);
|
||||||
if (__cpuidle_find_governor(gov->name) == NULL) {
|
if (cpuidle_find_governor(gov->name) == NULL) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
list_add_tail(&gov->governor_list, &cpuidle_governors);
|
list_add_tail(&gov->governor_list, &cpuidle_governors);
|
||||||
if (!cpuidle_curr_governor ||
|
if (!cpuidle_curr_governor ||
|
||||||
|
@ -121,6 +121,9 @@ struct cpuidle_driver {
|
|||||||
|
|
||||||
/* the driver handles the cpus in cpumask */
|
/* the driver handles the cpus in cpumask */
|
||||||
struct cpumask *cpumask;
|
struct cpumask *cpumask;
|
||||||
|
|
||||||
|
/* preferred governor to switch at register time */
|
||||||
|
const char *governor;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_IDLE
|
#ifdef CONFIG_CPU_IDLE
|
||||||
|
Loading…
Reference in New Issue
Block a user