Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/process: Move the buffer clearing before MONITOR

Move the VERW clearing before the MONITOR so that VERW doesn't disarm it
and the machine never enters C1.

Original idea by Kim Phillips <kim.phillips@amd.com>.

Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>

+27 -14
+15 -10
arch/x86/include/asm/mwait.h
··· 43 43 44 44 static __always_inline void __mwait(u32 eax, u32 ecx) 45 45 { 46 - x86_idle_clear_cpu_buffers(); 47 - 48 46 /* 49 47 * Use the instruction mnemonic with implicit operands, as the LLVM 50 48 * assembler fails to assemble the mnemonic with explicit operands: ··· 96 98 */ 97 99 static __always_inline void __sti_mwait(u32 eax, u32 ecx) 98 100 { 99 - x86_idle_clear_cpu_buffers(); 100 101 101 102 asm volatile("sti; mwait" :: "a" (eax), "c" (ecx)); 102 103 } ··· 112 115 */ 113 116 static __always_inline void mwait_idle_with_hints(u32 eax, u32 ecx) 114 117 { 118 + if (need_resched()) 119 + return; 120 + 121 + x86_idle_clear_cpu_buffers(); 122 + 115 123 if (static_cpu_has_bug(X86_BUG_MONITOR) || !current_set_polling_and_test()) { 116 124 const void *addr = &current_thread_info()->flags; 117 125 118 126 alternative_input("", "clflush (%[addr])", X86_BUG_CLFLUSH_MONITOR, [addr] "a" (addr)); 119 127 __monitor(addr, 0, 0); 120 128 121 - if (!need_resched()) { 122 - if (ecx & 1) { 123 - __mwait(eax, ecx); 124 - } else { 125 - __sti_mwait(eax, ecx); 126 - raw_local_irq_disable(); 127 - } 129 + if (need_resched()) 130 + goto out; 131 + 132 + if (ecx & 1) { 133 + __mwait(eax, ecx); 134 + } else { 135 + __sti_mwait(eax, ecx); 136 + raw_local_irq_disable(); 128 137 } 129 138 } 139 + 140 + out: 130 141 current_clr_polling(); 131 142 } 132 143
+12 -4
arch/x86/kernel/process.c
··· 907 907 */ 908 908 static __cpuidle void mwait_idle(void) 909 909 { 910 + if (need_resched()) 911 + return; 912 + 913 + x86_idle_clear_cpu_buffers(); 914 + 910 915 if (!current_set_polling_and_test()) { 911 916 const void *addr = &current_thread_info()->flags; 912 917 913 918 alternative_input("", "clflush (%[addr])", X86_BUG_CLFLUSH_MONITOR, [addr] "a" (addr)); 914 919 __monitor(addr, 0, 0); 915 - if (!need_resched()) { 916 - __sti_mwait(0, 0); 917 - raw_local_irq_disable(); 918 - } 920 + if (need_resched()) 921 + goto out; 922 + 923 + __sti_mwait(0, 0); 924 + raw_local_irq_disable(); 919 925 } 926 + 927 + out: 920 928 __current_clr_polling(); 921 929 } 922 930