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 */
|
||||
extern char param_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_detected_devices;
|
||||
extern struct mutex cpuidle_lock;
|
||||
|
@ -22,6 +23,7 @@ extern void cpuidle_install_idle_handler(void);
|
|||
extern void cpuidle_uninstall_idle_handler(void);
|
||||
|
||||
/* governors */
|
||||
extern struct cpuidle_governor *cpuidle_find_governor(const char *str);
|
||||
extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
|
||||
|
||||
/* sysfs */
|
||||
|
|
|
@ -254,12 +254,25 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
|
|||
*/
|
||||
int cpuidle_register_driver(struct cpuidle_driver *drv)
|
||||
{
|
||||
struct cpuidle_governor *gov;
|
||||
int ret;
|
||||
|
||||
spin_lock(&cpuidle_driver_lock);
|
||||
ret = __cpuidle_register_driver(drv);
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpuidle_register_driver);
|
||||
|
@ -274,9 +287,21 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver);
|
|||
*/
|
||||
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
|
||||
{
|
||||
bool enabled = (cpuidle_get_driver() == drv);
|
||||
|
||||
spin_lock(&cpuidle_driver_lock);
|
||||
__cpuidle_unregister_driver(drv);
|
||||
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);
|
||||
|
||||
|
|
|
@ -20,14 +20,15 @@ char param_governor[CPUIDLE_NAME_LEN];
|
|||
|
||||
LIST_HEAD(cpuidle_governors);
|
||||
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
|
||||
*
|
||||
* 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;
|
||||
|
||||
|
@ -87,7 +88,7 @@ int cpuidle_register_governor(struct cpuidle_governor *gov)
|
|||
return -ENODEV;
|
||||
|
||||
mutex_lock(&cpuidle_lock);
|
||||
if (__cpuidle_find_governor(gov->name) == NULL) {
|
||||
if (cpuidle_find_governor(gov->name) == NULL) {
|
||||
ret = 0;
|
||||
list_add_tail(&gov->governor_list, &cpuidle_governors);
|
||||
if (!cpuidle_curr_governor ||
|
||||
|
|
|
@ -121,6 +121,9 @@ struct cpuidle_driver {
|
|||
|
||||
/* the driver handles the cpus in cpumask */
|
||||
struct cpumask *cpumask;
|
||||
|
||||
/* preferred governor to switch at register time */
|
||||
const char *governor;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CPU_IDLE
|
||||
|
|
Loading…
Reference in a new issue