diff --git a/drivers/cpuidle/cpuidle-haltpoll.c b/drivers/cpuidle/cpuidle-haltpoll.c index fc351f093ce1afef947a4b164fdb0e0b91d28448..ae4f06f0507987c5db02a454b7886e764ef82806 100644 --- a/drivers/cpuidle/cpuidle-haltpoll.c +++ b/drivers/cpuidle/cpuidle-haltpoll.c @@ -117,7 +117,9 @@ static int __init haltpoll_init(void) return -ENODEV; ret = cpuidle_register_driver(drv); - if (ret < 0) + if (ret == 0) + haltpoll_switch_governor(drv); + else if (ret < 0) return ret; haltpoll_cpuidle_dev_wrap = alloc_percpu(struct cpuidle_device_wrapper); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index b7a7125f1cded5113d2ae5ece55d2897a8985f26..42fc9477375335ff1d24f9874ed9344e5f0d22e5 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -330,15 +330,9 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index) u64 cpuidle_poll_time(struct cpuidle_driver *drv, struct cpuidle_device *dev) { - struct cpuidle_device_wrapper *devw = - container_of(dev, struct cpuidle_device_wrapper, dev); + u64 limit_ns = TICK_NSEC; int i; - u64 limit_ns; - if (devw->poll_limit_ns) - return devw->poll_limit_ns; - - limit_ns = TICK_NSEC; for (i = 1; i < drv->state_count; i++) { if (drv->states[i].disabled || dev->states_usage[i].disable) continue; @@ -348,7 +342,19 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv, break; } - devw->poll_limit_ns = limit_ns; + return limit_ns; +} + +u64 cpuidle_haltpoll_time(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + struct cpuidle_device_wrapper *devw = + container_of(dev, struct cpuidle_device_wrapper, dev); + + if (devw->poll_limit_ns) + return devw->poll_limit_ns; + + devw->poll_limit_ns = cpuidle_poll_time(drv, dev); return devw->poll_limit_ns; } diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 47930a0ecb0f14cbbf8bbbc983ea1a49e66e9257..484d0e9655fcbfbf9027533078ea5a149ef02005 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -241,6 +241,25 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) __cpuidle_unset_driver(drv); } +void haltpoll_switch_governor(struct cpuidle_driver *drv) +{ + struct cpuidle_governor *gov; + struct cpuidle_driver_wrapper *drvw; + + drvw = container_of(drv, struct cpuidle_driver_wrapper, drv); + if (!strlen(param_governor) && drvw->governor && + (cpuidle_get_driver() == drv)) { + mutex_lock(&cpuidle_lock); + gov = cpuidle_find_governor(drvw->governor); + if (gov) { + cpuidle_prev_governor = cpuidle_curr_governor; + if (cpuidle_switch_governor(gov) < 0) + cpuidle_prev_governor = NULL; + } + mutex_unlock(&cpuidle_lock); + } +} + /** * cpuidle_register_driver - registers a driver * @drv: a pointer to a valid struct cpuidle_driver @@ -253,29 +272,15 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) */ int cpuidle_register_driver(struct cpuidle_driver *drv) { - struct cpuidle_governor *gov; - struct cpuidle_driver_wrapper *drvw; int ret; spin_lock(&cpuidle_driver_lock); ret = __cpuidle_register_driver(drv); spin_unlock(&cpuidle_driver_lock); - drvw = container_of(drv, struct cpuidle_driver_wrapper, drv); - - if (!ret && !strlen(param_governor) && drvw->governor && - (cpuidle_get_driver() == drv)) { - mutex_lock(&cpuidle_lock); - gov = cpuidle_find_governor(drvw->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); /** diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c index aa9842b1f1cc2317ee8eace94193d2bb2bbf0c60..a73c09464429f4c3a574c6813de26ae03c8f3aa3 100644 --- a/drivers/cpuidle/poll_state.c +++ b/drivers/cpuidle/poll_state.c @@ -26,7 +26,10 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev, unsigned int loop_count = 0; u64 limit; - limit = cpuidle_poll_time(drv, dev); + if (drv->name && !strcmp(drv->name, "haltpoll")) + limit = cpuidle_haltpoll_time(drv, dev); + else + limit = cpuidle_poll_time(drv, dev); while (!need_resched()) { cpu_relax(); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index f966a343daa71433b0e54c883dadd9a4f9e3d22e..4c8042f19a9601e38bbb8985d6c19adf946eca62 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -410,16 +410,10 @@ static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr, struct cpuidle_state *state = kobj_to_state(kobj); struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); struct cpuidle_state_attr *cattr = attr_to_stateattr(attr); - struct cpuidle_device *dev = kobj_to_device(kobj); - struct cpuidle_device_wrapper *devw = - container_of(dev, struct cpuidle_device_wrapper, dev); if (cattr->store) ret = cattr->store(state, state_usage, buf, size); - /* reset poll time cache */ - devw->poll_limit_ns = 0; - return ret; } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 364e28be3155f5f9f9d9f1de15af373abac9b459..e365f5dfe6e7dbdffb7b4f05d995e5daff7a5934 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -155,7 +155,10 @@ extern int cpuidle_enter(struct cpuidle_driver *drv, extern void cpuidle_reflect(struct cpuidle_device *dev, int index); extern u64 cpuidle_poll_time(struct cpuidle_driver *drv, struct cpuidle_device *dev); +extern u64 cpuidle_haltpoll_time(struct cpuidle_driver *drv, + struct cpuidle_device *dev); +extern void haltpoll_switch_governor(struct cpuidle_driver *drv); extern int cpuidle_register_driver(struct cpuidle_driver *drv); extern struct cpuidle_driver *cpuidle_get_driver(void); extern struct cpuidle_driver *cpuidle_driver_ref(void); @@ -192,8 +195,13 @@ static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { } static inline u64 cpuidle_poll_time(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return 0; } +static inline u64 cpuidle_haltpoll_time(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{return 0; } static inline int cpuidle_register_driver(struct cpuidle_driver *drv) {return -ENODEV; } +static inline void haltpoll_switch_governor(struct cpuidle_driver *drv) +{return -ENODEV; } static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; } static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; } static inline void cpuidle_driver_unref(void) {}