Commit 33677aef authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86-core-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 core updates from Ingo Molnar:

 - Add comments about the magic behind the shadow STI
   before MWAIT in __sti_mwait().

 - Fix possible unintended timer delays caused by a race
   in mwait_idle_with_hints().

* tag 'x86-core-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86: Fix CPUIDLE_FLAG_IRQ_ENABLE leaking timer reprogram
  x86: Add a comment about the "magic" behind shadow sti before mwait
parents b51cc5d0 edc8fc01
...@@ -87,6 +87,15 @@ static __always_inline void __mwaitx(unsigned long eax, unsigned long ebx, ...@@ -87,6 +87,15 @@ static __always_inline void __mwaitx(unsigned long eax, unsigned long ebx,
:: "a" (eax), "b" (ebx), "c" (ecx)); :: "a" (eax), "b" (ebx), "c" (ecx));
} }
/*
* Re-enable interrupts right upon calling mwait in such a way that
* no interrupt can fire _before_ the execution of mwait, ie: no
* instruction must be placed between "sti" and "mwait".
*
* This is necessary because if an interrupt queues a timer before
* executing mwait, it would otherwise go unnoticed and the next tick
* would not be reprogrammed accordingly before mwait ever wakes up.
*/
static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx) static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx)
{ {
mds_idle_clear_cpu_buffers(); mds_idle_clear_cpu_buffers();
...@@ -115,8 +124,15 @@ static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned lo ...@@ -115,8 +124,15 @@ static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned lo
} }
__monitor((void *)&current_thread_info()->flags, 0, 0); __monitor((void *)&current_thread_info()->flags, 0, 0);
if (!need_resched())
__mwait(eax, ecx); if (!need_resched()) {
if (ecx & 1) {
__mwait(eax, ecx);
} else {
__sti_mwait(eax, ecx);
raw_local_irq_disable();
}
}
} }
current_clr_polling(); current_clr_polling();
} }
......
...@@ -131,11 +131,12 @@ static unsigned int mwait_substates __initdata; ...@@ -131,11 +131,12 @@ static unsigned int mwait_substates __initdata;
#define MWAIT2flg(eax) ((eax & 0xFF) << 24) #define MWAIT2flg(eax) ((eax & 0xFF) << 24)
static __always_inline int __intel_idle(struct cpuidle_device *dev, static __always_inline int __intel_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) struct cpuidle_driver *drv,
int index, bool irqoff)
{ {
struct cpuidle_state *state = &drv->states[index]; struct cpuidle_state *state = &drv->states[index];
unsigned long eax = flg2MWAIT(state->flags); unsigned long eax = flg2MWAIT(state->flags);
unsigned long ecx = 1; /* break on interrupt flag */ unsigned long ecx = 1*irqoff; /* break on interrupt flag */
mwait_idle_with_hints(eax, ecx); mwait_idle_with_hints(eax, ecx);
...@@ -159,19 +160,13 @@ static __always_inline int __intel_idle(struct cpuidle_device *dev, ...@@ -159,19 +160,13 @@ static __always_inline int __intel_idle(struct cpuidle_device *dev,
static __cpuidle int intel_idle(struct cpuidle_device *dev, static __cpuidle int intel_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) struct cpuidle_driver *drv, int index)
{ {
return __intel_idle(dev, drv, index); return __intel_idle(dev, drv, index, true);
} }
static __cpuidle int intel_idle_irq(struct cpuidle_device *dev, static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) struct cpuidle_driver *drv, int index)
{ {
int ret; return __intel_idle(dev, drv, index, false);
raw_local_irq_enable();
ret = __intel_idle(dev, drv, index);
raw_local_irq_disable();
return ret;
} }
static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev, static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
...@@ -184,7 +179,7 @@ static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev, ...@@ -184,7 +179,7 @@ static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
if (smt_active) if (smt_active)
__update_spec_ctrl(0); __update_spec_ctrl(0);
ret = __intel_idle(dev, drv, index); ret = __intel_idle(dev, drv, index, true);
if (smt_active) if (smt_active)
__update_spec_ctrl(spec_ctrl); __update_spec_ctrl(spec_ctrl);
...@@ -196,7 +191,7 @@ static __cpuidle int intel_idle_xstate(struct cpuidle_device *dev, ...@@ -196,7 +191,7 @@ static __cpuidle int intel_idle_xstate(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) struct cpuidle_driver *drv, int index)
{ {
fpu_idle_fpregs(); fpu_idle_fpregs();
return __intel_idle(dev, drv, index); return __intel_idle(dev, drv, index, true);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment