On Mon, Jul 1, 2019 at 8:57 PM Marcelo Tosatti <mtosatti@xxxxxxxxxx> wrote: > > Add a "get_poll_time" callback to the cpuidle_governor structure, > and change poll state to poll for that amount of time. > > Provide a default method for it, while allowing individual governors > to override it. > > Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> I had ACKed this before, but then it occurred to me that it would be less intrusive to use a new field, say poll_limit_ns (equal to 0 by default), in struct cpuidle_device. > > --- > drivers/cpuidle/cpuidle.c | 40 ++++++++++++++++++++++++++++++++++++++++ > drivers/cpuidle/poll_state.c | 11 ++--------- > include/linux/cpuidle.h | 8 ++++++++ > 3 files changed, 50 insertions(+), 9 deletions(-) > > Index: linux-2.6-newcpuidle.git/drivers/cpuidle/cpuidle.c > =================================================================== > --- linux-2.6-newcpuidle.git.orig/drivers/cpuidle/cpuidle.c > +++ linux-2.6-newcpuidle.git/drivers/cpuidle/cpuidle.c > @@ -362,6 +362,46 @@ void cpuidle_reflect(struct cpuidle_devi > } > > /** > + * cpuidle_default_poll_time - default routine used to return poll time > + * governors can override it if necessary > + * > + * @drv: the cpuidle driver tied with the cpu > + * @dev: the cpuidle device > + * > + */ > +static u64 cpuidle_default_poll_time(struct cpuidle_driver *drv, > + struct cpuidle_device *dev) With this new field in place this could be called cpuidle_poll_time() and -> > +{ > + int i; -> do something like this here: if (dev->poll_limit_ns) return dev->poll_limit_ns; and the governor changes below wouldn't be necessary any more. Then, the governor could update poll_limit_ns if it wanted to override the default. It also would be possible to use poll_limit_ns as a sort of poll limit cache to store the last value in it and clear it on state disable/enable to avoid the search through the states every time even without haltpoll. > + > + for (i = 1; i < drv->state_count; i++) { > + if (drv->states[i].disabled || dev->states_usage[i].disable) > + continue; > + > + return (u64)drv->states[i].target_residency * NSEC_PER_USEC; > + } > + > + return TICK_NSEC; > +} > + > +/** > + * cpuidle_get_poll_time - tell the polling driver how much time to poll, > + * in nanoseconds. > + * > + * @drv: the cpuidle driver tied with the cpu > + * @dev: the cpuidle device > + * > + */ > +u64 cpuidle_get_poll_time(struct cpuidle_driver *drv, > + struct cpuidle_device *dev) > +{ > + if (cpuidle_curr_governor->get_poll_time) > + return cpuidle_curr_governor->get_poll_time(drv, dev); > + > + return cpuidle_default_poll_time(drv, dev); > +} > + > +/** > * cpuidle_install_idle_handler - installs the cpuidle idle loop handler > */ > void cpuidle_install_idle_handler(void) > Index: linux-2.6-newcpuidle.git/drivers/cpuidle/poll_state.c > =================================================================== > --- linux-2.6-newcpuidle.git.orig/drivers/cpuidle/poll_state.c > +++ linux-2.6-newcpuidle.git/drivers/cpuidle/poll_state.c > @@ -20,16 +20,9 @@ static int __cpuidle poll_idle(struct cp > local_irq_enable(); > if (!current_set_polling_and_test()) { > unsigned int loop_count = 0; > - u64 limit = TICK_NSEC; > - int i; > + u64 limit; > > - for (i = 1; i < drv->state_count; i++) { > - if (drv->states[i].disabled || dev->states_usage[i].disable) > - continue; > - > - limit = (u64)drv->states[i].target_residency * NSEC_PER_USEC; > - break; > - } > + limit = cpuidle_get_poll_time(drv, dev); > > while (!need_resched()) { > cpu_relax(); > Index: linux-2.6-newcpuidle.git/include/linux/cpuidle.h > =================================================================== > --- linux-2.6-newcpuidle.git.orig/include/linux/cpuidle.h > +++ linux-2.6-newcpuidle.git/include/linux/cpuidle.h > @@ -132,6 +132,8 @@ extern int cpuidle_select(struct cpuidle > extern int cpuidle_enter(struct cpuidle_driver *drv, > struct cpuidle_device *dev, int index); > extern void cpuidle_reflect(struct cpuidle_device *dev, int index); > +extern u64 cpuidle_get_poll_time(struct cpuidle_driver *drv, > + struct cpuidle_device *dev); > > extern int cpuidle_register_driver(struct cpuidle_driver *drv); > extern struct cpuidle_driver *cpuidle_get_driver(void); > @@ -166,6 +168,9 @@ static inline int cpuidle_enter(struct c > struct cpuidle_device *dev, int index) > {return -ENODEV; } > static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { } > +extern u64 cpuidle_get_poll_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 struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; } > @@ -246,6 +251,9 @@ struct cpuidle_governor { > struct cpuidle_device *dev, > bool *stop_tick); > void (*reflect) (struct cpuidle_device *dev, int index); > + > + u64 (*get_poll_time) (struct cpuidle_driver *drv, > + struct cpuidle_device *dev); > }; > > #ifdef CONFIG_CPU_IDLE > >