提交 0176005e 编写于 作者: J Joao Martins 提交者: Shile Zhang

cpuidle: allow governor switch on cpuidle_register_driver()

commit 11c59eae6633b8a7e77b8ee1cf908964d80c78cd upstream

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: NJoao Martins <joao.m.martins@oracle.com>
Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: NYihao Wu <wuyihao@linux.alibaba.com>
Acked-by: NMichael Wang <yun.wang@linux.alibaba.com>
上级 1e18beca
...@@ -9,6 +9,7 @@ ...@@ -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); ...@@ -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 */
......
...@@ -253,12 +253,25 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) ...@@ -253,12 +253,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);
...@@ -273,9 +286,21 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver); ...@@ -273,9 +286,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]; ...@@ -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) ...@@ -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;
if (!cpuidle_curr_governor || if (!cpuidle_curr_governor ||
!strncasecmp(param_governor, gov->name, CPUIDLE_NAME_LEN) || !strncasecmp(param_governor, gov->name, CPUIDLE_NAME_LEN) ||
......
...@@ -130,6 +130,9 @@ struct cpuidle_driver { ...@@ -130,6 +130,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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册