diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index b5493a7f8f22..7e9cc49b90a9 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2236,6 +2236,29 @@ Kernel parameters idle=nomwait: Disable mwait for CPU C-states + [ARM64,EARLY] + Format: idle=wfi, idle=yield, idle=nop + + idle=wfi: Use the WFI (Wait For Interrupt) hint + instruction in the idle loop. This is the default and + allows the CPU to enter a low-power state until an + interrupt arrives. + + idle=yield: Use the YIELD hint instruction instead of + WFI. CPUs supporting simultaneous multi-threading (SMT), + can continue executing another thread when the current + thread reaches the idle loop. This will make the CPUs + eat more power, but may be useful to get slightly better + performance in some applications, since the CPUs will + not enter a low-power state. + + idle=nop: Do not execute any idle instruction in the + idle loop. This is useful on platforms where WFI + misbehaves, leading to system instability or loss of CPU + state. This will make the CPUs eat more power, but may + give slightly better performance in some applications, + since the CPUs will not enter a low-power state. + idxd.sva= [HW] Format: Allow force disabling of Shared Virtual Memory (SVA) diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c index 05cfb347ec26..42c5543f9589 100644 --- a/arch/arm64/kernel/idle.c +++ b/arch/arm64/kernel/idle.c @@ -11,6 +11,29 @@ #include #include +enum { + ARM64_IDLE_WFI, + ARM64_IDLE_YIELD, + ARM64_IDLE_NOP, +} idle = ARM64_IDLE_WFI; + +static int __init setup_idle(char *arg) +{ + if (!arg) + return -1; + else if (!strcmp(arg, "wfi")) + idle = ARM64_IDLE_WFI; + else if (!strcmp(arg, "yield")) + idle = ARM64_IDLE_YIELD; + else if (!strcmp(arg, "nop")) + idle = ARM64_IDLE_NOP; + else + return -1; + + return 0; +} +early_param("idle", setup_idle); + /* * cpu_do_idle() * @@ -26,8 +49,13 @@ void __cpuidle cpu_do_idle(void) arm_cpuidle_save_irq_context(&context); - dsb(sy); - wfi(); + if (likely(idle == ARM64_IDLE_WFI)) { + dsb(sy); + wfi(); + } else if (idle == ARM64_IDLE_YIELD) { + dsb(sy); + asm volatile("yield" ::: "memory"); + } arm_cpuidle_restore_irq_context(&context); }