18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_MWAIT_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_MWAIT_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/sched.h> 68c2ecf20Sopenharmony_ci#include <linux/sched/idle.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <asm/cpufeature.h> 98c2ecf20Sopenharmony_ci#include <asm/nospec-branch.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define MWAIT_SUBSTATE_MASK 0xf 128c2ecf20Sopenharmony_ci#define MWAIT_CSTATE_MASK 0xf 138c2ecf20Sopenharmony_ci#define MWAIT_SUBSTATE_SIZE 4 148c2ecf20Sopenharmony_ci#define MWAIT_HINT2CSTATE(hint) (((hint) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) 158c2ecf20Sopenharmony_ci#define MWAIT_HINT2SUBSTATE(hint) ((hint) & MWAIT_CSTATE_MASK) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define CPUID_MWAIT_LEAF 5 188c2ecf20Sopenharmony_ci#define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1 198c2ecf20Sopenharmony_ci#define CPUID5_ECX_INTERRUPT_BREAK 0x2 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define MWAIT_ECX_INTERRUPT_BREAK 0x1 228c2ecf20Sopenharmony_ci#define MWAITX_ECX_TIMER_ENABLE BIT(1) 238c2ecf20Sopenharmony_ci#define MWAITX_MAX_WAIT_CYCLES UINT_MAX 248c2ecf20Sopenharmony_ci#define MWAITX_DISABLE_CSTATES 0xf0 258c2ecf20Sopenharmony_ci#define TPAUSE_C01_STATE 1 268c2ecf20Sopenharmony_ci#define TPAUSE_C02_STATE 0 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic inline void __monitor(const void *eax, unsigned long ecx, 298c2ecf20Sopenharmony_ci unsigned long edx) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci /* "monitor %eax, %ecx, %edx;" */ 328c2ecf20Sopenharmony_ci asm volatile(".byte 0x0f, 0x01, 0xc8;" 338c2ecf20Sopenharmony_ci :: "a" (eax), "c" (ecx), "d"(edx)); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic inline void __monitorx(const void *eax, unsigned long ecx, 378c2ecf20Sopenharmony_ci unsigned long edx) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci /* "monitorx %eax, %ecx, %edx;" */ 408c2ecf20Sopenharmony_ci asm volatile(".byte 0x0f, 0x01, 0xfa;" 418c2ecf20Sopenharmony_ci :: "a" (eax), "c" (ecx), "d"(edx)); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline void __mwait(unsigned long eax, unsigned long ecx) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci mds_idle_clear_cpu_buffers(); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* "mwait %eax, %ecx;" */ 498c2ecf20Sopenharmony_ci asm volatile(".byte 0x0f, 0x01, 0xc9;" 508c2ecf20Sopenharmony_ci :: "a" (eax), "c" (ecx)); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * MWAITX allows for a timer expiration to get the core out a wait state in 558c2ecf20Sopenharmony_ci * addition to the default MWAIT exit condition of a store appearing at a 568c2ecf20Sopenharmony_ci * monitored virtual address. 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * Registers: 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * MWAITX ECX[1]: enable timer if set 618c2ecf20Sopenharmony_ci * MWAITX EBX[31:0]: max wait time expressed in SW P0 clocks. The software P0 628c2ecf20Sopenharmony_ci * frequency is the same as the TSC frequency. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * Below is a comparison between MWAIT and MWAITX on AMD processors: 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * MWAIT MWAITX 678c2ecf20Sopenharmony_ci * opcode 0f 01 c9 | 0f 01 fb 688c2ecf20Sopenharmony_ci * ECX[0] value of RFLAGS.IF seen by instruction 698c2ecf20Sopenharmony_ci * ECX[1] unused/#GP if set | enable timer if set 708c2ecf20Sopenharmony_ci * ECX[31:2] unused/#GP if set 718c2ecf20Sopenharmony_ci * EAX unused (reserve for hint) 728c2ecf20Sopenharmony_ci * EBX[31:0] unused | max wait time (P0 clocks) 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * MONITOR MONITORX 758c2ecf20Sopenharmony_ci * opcode 0f 01 c8 | 0f 01 fa 768c2ecf20Sopenharmony_ci * EAX (logical) address to monitor 778c2ecf20Sopenharmony_ci * ECX #GP if not zero 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistatic inline void __mwaitx(unsigned long eax, unsigned long ebx, 808c2ecf20Sopenharmony_ci unsigned long ecx) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci /* No MDS buffer clear as this is AMD/HYGON only */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* "mwaitx %eax, %ebx, %ecx;" */ 858c2ecf20Sopenharmony_ci asm volatile(".byte 0x0f, 0x01, 0xfb;" 868c2ecf20Sopenharmony_ci :: "a" (eax), "b" (ebx), "c" (ecx)); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic inline void __sti_mwait(unsigned long eax, unsigned long ecx) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci mds_idle_clear_cpu_buffers(); 928c2ecf20Sopenharmony_ci /* "mwait %eax, %ecx;" */ 938c2ecf20Sopenharmony_ci asm volatile("sti; .byte 0x0f, 0x01, 0xc9;" 948c2ecf20Sopenharmony_ci :: "a" (eax), "c" (ecx)); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, 998c2ecf20Sopenharmony_ci * which can obviate IPI to trigger checking of need_resched. 1008c2ecf20Sopenharmony_ci * We execute MONITOR against need_resched and enter optimized wait state 1018c2ecf20Sopenharmony_ci * through MWAIT. Whenever someone changes need_resched, we would be woken 1028c2ecf20Sopenharmony_ci * up from MWAIT (without an IPI). 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * New with Core Duo processors, MWAIT can take some hints based on CPU 1058c2ecf20Sopenharmony_ci * capability. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistatic inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (static_cpu_has_bug(X86_BUG_MONITOR) || !current_set_polling_and_test()) { 1108c2ecf20Sopenharmony_ci if (static_cpu_has_bug(X86_BUG_CLFLUSH_MONITOR)) { 1118c2ecf20Sopenharmony_ci mb(); 1128c2ecf20Sopenharmony_ci clflush((void *)¤t_thread_info()->flags); 1138c2ecf20Sopenharmony_ci mb(); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci __monitor((void *)¤t_thread_info()->flags, 0, 0); 1178c2ecf20Sopenharmony_ci if (!need_resched()) 1188c2ecf20Sopenharmony_ci __mwait(eax, ecx); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci current_clr_polling(); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Caller can specify whether to enter C0.1 (low latency, less 1258c2ecf20Sopenharmony_ci * power saving) or C0.2 state (saves more power, but longer wakeup 1268c2ecf20Sopenharmony_ci * latency). This may be overridden by the IA32_UMWAIT_CONTROL MSR 1278c2ecf20Sopenharmony_ci * which can force requests for C0.2 to be downgraded to C0.1. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cistatic inline void __tpause(u32 ecx, u32 edx, u32 eax) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci /* "tpause %ecx, %edx, %eax;" */ 1328c2ecf20Sopenharmony_ci #ifdef CONFIG_AS_TPAUSE 1338c2ecf20Sopenharmony_ci asm volatile("tpause %%ecx\n" 1348c2ecf20Sopenharmony_ci : 1358c2ecf20Sopenharmony_ci : "c"(ecx), "d"(edx), "a"(eax)); 1368c2ecf20Sopenharmony_ci #else 1378c2ecf20Sopenharmony_ci asm volatile(".byte 0x66, 0x0f, 0xae, 0xf1\t\n" 1388c2ecf20Sopenharmony_ci : 1398c2ecf20Sopenharmony_ci : "c"(ecx), "d"(edx), "a"(eax)); 1408c2ecf20Sopenharmony_ci #endif 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#endif /* _ASM_X86_MWAIT_H */ 144