Messages in this thread Patch in this message | | | Date | Mon, 15 Jun 2020 21:31:54 +0200 | From | Peter Zijlstra <> | Subject | Re: [PATCH][RFC] PM / s2idle: Clear _TIF_POLLING_NRFLAG before suspend to idle |
| |
On Mon, Jun 15, 2020 at 08:40:41PM +0200, Peter Zijlstra wrote:
> > @@ -186,8 +187,10 @@ int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev) > > * be frozen safely. > > */ > > index = find_deepest_state(drv, dev, U64_MAX, 0, true); > > - if (index > 0) > > + if (index > 0) { > > + __current_clr_polling(); > > enter_s2idle_proper(drv, dev, index); > > + } > > > > return index; > > } > > So how is that commit 08e237fa56a1 not suffient? That makes > mwait_idle_with_hints() DTRT for this 'functionally challenged' piece of > hardware. > > AFAICT intel_enter_s2idle() uses mwait_idle_with_hints(). > > What am I missing?
What's missing is that cpuidle_enter_s2idle() doesn't properly match call_cpuidle().
Something like so then. Your version is racy, if someone already set TIF_NEED_RESCHED you just clear POLLING and go to sleep.
---
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index c149d9e20dfd..81bee8d03c6d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -133,8 +133,8 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv, } #ifdef CONFIG_SUSPEND -static void enter_s2idle_proper(struct cpuidle_driver *drv, - struct cpuidle_device *dev, int index) +static void s2idle_enter(struct cpuidle_driver *drv, + struct cpuidle_device *dev, int index) { ktime_t time_start, time_end; @@ -168,6 +168,15 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv, dev->states_usage[index].s2idle_usage++; } +static int call_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev, + int index) +{ + if (!current_clr_polling_and_test()) + s2idle_enter(drv, dev, index); + + return index; +} + /** * cpuidle_enter_s2idle - Enter an idle state suitable for suspend-to-idle. * @drv: cpuidle driver for the given CPU. @@ -187,7 +196,7 @@ int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev) */ index = find_deepest_state(drv, dev, U64_MAX, 0, true); if (index > 0) - enter_s2idle_proper(drv, dev, index); + call_s2idle(drv, dev, index); return index; }
| |