Skip to content

Commit 33677ae

Browse files
committed
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
2 parents b51cc5d + edc8fc0 commit 33677ae

2 files changed

Lines changed: 25 additions & 14 deletions

File tree

arch/x86/include/asm/mwait.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ static __always_inline void __mwaitx(unsigned long eax, unsigned long ebx,
8787
:: "a" (eax), "b" (ebx), "c" (ecx));
8888
}
8989

90+
/*
91+
* Re-enable interrupts right upon calling mwait in such a way that
92+
* no interrupt can fire _before_ the execution of mwait, ie: no
93+
* instruction must be placed between "sti" and "mwait".
94+
*
95+
* This is necessary because if an interrupt queues a timer before
96+
* executing mwait, it would otherwise go unnoticed and the next tick
97+
* would not be reprogrammed accordingly before mwait ever wakes up.
98+
*/
9099
static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx)
91100
{
92101
mds_idle_clear_cpu_buffers();
@@ -115,8 +124,15 @@ static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned lo
115124
}
116125

117126
__monitor((void *)&current_thread_info()->flags, 0, 0);
118-
if (!need_resched())
119-
__mwait(eax, ecx);
127+
128+
if (!need_resched()) {
129+
if (ecx & 1) {
130+
__mwait(eax, ecx);
131+
} else {
132+
__sti_mwait(eax, ecx);
133+
raw_local_irq_disable();
134+
}
135+
}
120136
}
121137
current_clr_polling();
122138
}

drivers/idle/intel_idle.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,12 @@ static unsigned int mwait_substates __initdata;
131131
#define MWAIT2flg(eax) ((eax & 0xFF) << 24)
132132

133133
static __always_inline int __intel_idle(struct cpuidle_device *dev,
134-
struct cpuidle_driver *drv, int index)
134+
struct cpuidle_driver *drv,
135+
int index, bool irqoff)
135136
{
136137
struct cpuidle_state *state = &drv->states[index];
137138
unsigned long eax = flg2MWAIT(state->flags);
138-
unsigned long ecx = 1; /* break on interrupt flag */
139+
unsigned long ecx = 1*irqoff; /* break on interrupt flag */
139140

140141
mwait_idle_with_hints(eax, ecx);
141142

@@ -159,19 +160,13 @@ static __always_inline int __intel_idle(struct cpuidle_device *dev,
159160
static __cpuidle int intel_idle(struct cpuidle_device *dev,
160161
struct cpuidle_driver *drv, int index)
161162
{
162-
return __intel_idle(dev, drv, index);
163+
return __intel_idle(dev, drv, index, true);
163164
}
164165

165166
static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
166167
struct cpuidle_driver *drv, int index)
167168
{
168-
int ret;
169-
170-
raw_local_irq_enable();
171-
ret = __intel_idle(dev, drv, index);
172-
raw_local_irq_disable();
173-
174-
return ret;
169+
return __intel_idle(dev, drv, index, false);
175170
}
176171

177172
static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
@@ -184,7 +179,7 @@ static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
184179
if (smt_active)
185180
__update_spec_ctrl(0);
186181

187-
ret = __intel_idle(dev, drv, index);
182+
ret = __intel_idle(dev, drv, index, true);
188183

189184
if (smt_active)
190185
__update_spec_ctrl(spec_ctrl);
@@ -196,7 +191,7 @@ static __cpuidle int intel_idle_xstate(struct cpuidle_device *dev,
196191
struct cpuidle_driver *drv, int index)
197192
{
198193
fpu_idle_fpregs();
199-
return __intel_idle(dev, drv, index);
194+
return __intel_idle(dev, drv, index, true);
200195
}
201196

202197
/**

0 commit comments

Comments
 (0)