Message ID | 20220608144516.172460444@infradead.org |
---|---|
State | Not Applicable |
Headers | show |
Series | cpuidle,rcu: Cleanup the mess | expand |
On Wed, Jun 8, 2022 at 4:47 PM Peter Zijlstra <peterz@infradead.org> wrote: > > Commit c227233ad64c ("intel_idle: enable interrupts before C1 on > Xeons") wrecked intel_idle in two ways: > > - must not have tracing in idle functions > - must return with IRQs disabled > > Additionally, it added a branch for no good reason. > > Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> And do I think correctly that this can be applied without the rest of the series? > --- > drivers/idle/intel_idle.c | 48 +++++++++++++++++++++++++++++++++++----------- > 1 file changed, 37 insertions(+), 11 deletions(-) > > --- a/drivers/idle/intel_idle.c > +++ b/drivers/idle/intel_idle.c > @@ -129,21 +137,37 @@ static unsigned int mwait_substates __in > * > * Must be called under local_irq_disable(). > */ > + > -static __cpuidle int intel_idle(struct cpuidle_device *dev, > - struct cpuidle_driver *drv, int index) > +static __always_inline int __intel_idle(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int index) > { > struct cpuidle_state *state = &drv->states[index]; > unsigned long eax = flg2MWAIT(state->flags); > unsigned long ecx = 1; /* break on interrupt flag */ > > - if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE) > - local_irq_enable(); > - > mwait_idle_with_hints(eax, ecx); > > return index; > } > > +static __cpuidle int intel_idle(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int index) > +{ > + return __intel_idle(dev, drv, index); > +} > + > +static __cpuidle int intel_idle_irq(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int index) > +{ > + int ret; > + > + raw_local_irq_enable(); > + ret = __intel_idle(dev, drv, index); > + raw_local_irq_disable(); > + > + return ret; > +} > + > /** > * intel_idle_s2idle - Ask the processor to enter the given idle state. > * @dev: cpuidle device of the target CPU. > @@ -1801,6 +1824,9 @@ static void __init intel_idle_init_cstat > /* Structure copy. */ > drv->states[drv->state_count] = cpuidle_state_table[cstate]; > > + if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) > + drv->states[drv->state_count].enter = intel_idle_irq; > + > if ((disabled_states_mask & BIT(drv->state_count)) || > ((icpu->use_acpi || force_use_acpi) && > intel_idle_off_by_default(mwait_hint) && > >
On Wed, Jun 08, 2022 at 05:01:05PM +0200, Rafael J. Wysocki wrote: > On Wed, Jun 8, 2022 at 4:47 PM Peter Zijlstra <peterz@infradead.org> wrote: > > > > Commit c227233ad64c ("intel_idle: enable interrupts before C1 on > > Xeons") wrecked intel_idle in two ways: > > > > - must not have tracing in idle functions > > - must return with IRQs disabled > > > > Additionally, it added a branch for no good reason. > > > > Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > And do I think correctly that this can be applied without the rest of > the series? Yeah, I don't think this relies on any of the preceding patches. If you want to route this through the pm/fixes tree that's fine. Thanks!
On Wed, Jun 8, 2022 at 5:48 PM Peter Zijlstra <peterz@infradead.org> wrote: > > On Wed, Jun 08, 2022 at 05:01:05PM +0200, Rafael J. Wysocki wrote: > > On Wed, Jun 8, 2022 at 4:47 PM Peter Zijlstra <peterz@infradead.org> wrote: > > > > > > Commit c227233ad64c ("intel_idle: enable interrupts before C1 on > > > Xeons") wrecked intel_idle in two ways: > > > > > > - must not have tracing in idle functions > > > - must return with IRQs disabled > > > > > > Additionally, it added a branch for no good reason. > > > > > > Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") > > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > > > Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > > > And do I think correctly that this can be applied without the rest of > > the series? > > Yeah, I don't think this relies on any of the preceding patches. If you > want to route this through the pm/fixes tree that's fine. OK, thanks, applied (and I moved the intel_idle() kerneldoc so it is next to the function to avoid the docs build warning).
Hi Peter, On Wed, 08 Jun 2022 16:27:27 +0200, Peter Zijlstra <peterz@infradead.org> wrote: > Commit c227233ad64c ("intel_idle: enable interrupts before C1 on > Xeons") wrecked intel_idle in two ways: > > - must not have tracing in idle functions > - must return with IRQs disabled > > Additionally, it added a branch for no good reason. > > Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > --- > drivers/idle/intel_idle.c | 48 > +++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 > insertions(+), 11 deletions(-) > > --- a/drivers/idle/intel_idle.c > +++ b/drivers/idle/intel_idle.c > @@ -129,21 +137,37 @@ static unsigned int mwait_substates __in > * > * Must be called under local_irq_disable(). > */ nit: this comment is no long true, right? > + > -static __cpuidle int intel_idle(struct cpuidle_device *dev, > - struct cpuidle_driver *drv, int index) > +static __always_inline int __intel_idle(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int > index) { > struct cpuidle_state *state = &drv->states[index]; > unsigned long eax = flg2MWAIT(state->flags); > unsigned long ecx = 1; /* break on interrupt flag */ > > - if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE) > - local_irq_enable(); > - > mwait_idle_with_hints(eax, ecx); > > return index; > } > > +static __cpuidle int intel_idle(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int index) > +{ > + return __intel_idle(dev, drv, index); > +} > + > +static __cpuidle int intel_idle_irq(struct cpuidle_device *dev, > + struct cpuidle_driver *drv, int > index) +{ > + int ret; > + > + raw_local_irq_enable(); > + ret = __intel_idle(dev, drv, index); > + raw_local_irq_disable(); > + > + return ret; > +} > + > /** > * intel_idle_s2idle - Ask the processor to enter the given idle state. > * @dev: cpuidle device of the target CPU. > @@ -1801,6 +1824,9 @@ static void __init intel_idle_init_cstat > /* Structure copy. */ > drv->states[drv->state_count] = > cpuidle_state_table[cstate]; > + if (cpuidle_state_table[cstate].flags & > CPUIDLE_FLAG_IRQ_ENABLE) > + drv->states[drv->state_count].enter = > intel_idle_irq; + > if ((disabled_states_mask & BIT(drv->state_count)) || > ((icpu->use_acpi || force_use_acpi) && > intel_idle_off_by_default(mwait_hint) && > > Thanks, Jacob
On Thu, Jun 09, 2022 at 04:49:21PM -0700, Jacob Pan wrote: > Hi Peter, > > On Wed, 08 Jun 2022 16:27:27 +0200, Peter Zijlstra <peterz@infradead.org> > wrote: > > > Commit c227233ad64c ("intel_idle: enable interrupts before C1 on > > Xeons") wrecked intel_idle in two ways: > > > > - must not have tracing in idle functions > > - must return with IRQs disabled > > > > Additionally, it added a branch for no good reason. > > > > Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > --- > > drivers/idle/intel_idle.c | 48 > > +++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 > > insertions(+), 11 deletions(-) > > > > --- a/drivers/idle/intel_idle.c > > +++ b/drivers/idle/intel_idle.c > > @@ -129,21 +137,37 @@ static unsigned int mwait_substates __in > > * > > * Must be called under local_irq_disable(). > > */ > nit: this comment is no long true, right? It still is, all the idle routines are called with interrupts disabled, but must also exit with interrupts disabled. If the idle method requires interrupts to be enabled, it must be sure to disable them again before returning. Given all the RCU/tracing concerns it must use raw_local_irq_*() for this though.
Hi Peter, On Mon, 13 Jun 2022 10:44:22 +0200, Peter Zijlstra <peterz@infradead.org> wrote: > On Thu, Jun 09, 2022 at 04:49:21PM -0700, Jacob Pan wrote: > > Hi Peter, > > > > On Wed, 08 Jun 2022 16:27:27 +0200, Peter Zijlstra > > <peterz@infradead.org> wrote: > > > > > Commit c227233ad64c ("intel_idle: enable interrupts before C1 on > > > Xeons") wrecked intel_idle in two ways: > > > > > > - must not have tracing in idle functions > > > - must return with IRQs disabled > > > > > > Additionally, it added a branch for no good reason. > > > > > > Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on > > > Xeons") Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> > > > --- > > > drivers/idle/intel_idle.c | 48 > > > +++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 > > > insertions(+), 11 deletions(-) > > > > > > --- a/drivers/idle/intel_idle.c > > > +++ b/drivers/idle/intel_idle.c > > > @@ -129,21 +137,37 @@ static unsigned int mwait_substates __in > > > * > > > * Must be called under local_irq_disable(). > > > */ > > nit: this comment is no long true, right? > > It still is, all the idle routines are called with interrupts disabled, > but must also exit with interrupts disabled. > > If the idle method requires interrupts to be enabled, it must be sure to > disable them again before returning. Given all the RCU/tracing concerns > it must use raw_local_irq_*() for this though. Makes sense, it is just little confusing when the immediate caller does raw_local_irq_enable() which does not cancel out local_irq_disable(). Thanks, Jacob
--- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -129,21 +137,37 @@ static unsigned int mwait_substates __in * * Must be called under local_irq_disable(). */ + -static __cpuidle int intel_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) +static __always_inline int __intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct cpuidle_state *state = &drv->states[index]; unsigned long eax = flg2MWAIT(state->flags); unsigned long ecx = 1; /* break on interrupt flag */ - if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE) - local_irq_enable(); - mwait_idle_with_hints(eax, ecx); return index; } +static __cpuidle int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + return __intel_idle(dev, drv, index); +} + +static __cpuidle int intel_idle_irq(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + int ret; + + raw_local_irq_enable(); + ret = __intel_idle(dev, drv, index); + raw_local_irq_disable(); + + return ret; +} + /** * intel_idle_s2idle - Ask the processor to enter the given idle state. * @dev: cpuidle device of the target CPU. @@ -1801,6 +1824,9 @@ static void __init intel_idle_init_cstat /* Structure copy. */ drv->states[drv->state_count] = cpuidle_state_table[cstate]; + if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) + drv->states[drv->state_count].enter = intel_idle_irq; + if ((disabled_states_mask & BIT(drv->state_count)) || ((icpu->use_acpi || force_use_acpi) && intel_idle_off_by_default(mwait_hint) &&
Commit c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") wrecked intel_idle in two ways: - must not have tracing in idle functions - must return with IRQs disabled Additionally, it added a branch for no good reason. Fixes: c227233ad64c ("intel_idle: enable interrupts before C1 on Xeons") Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> --- drivers/idle/intel_idle.c | 48 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-)