* [PATCH] arch: arm64: add early_param idle=<wfi|yield|nop>
@ 2026-07-05 10:02 Yureka Lilian
2026-07-06 5:23 ` Anshuman Khandual
2026-07-06 23:21 ` Joshua Peisach
0 siblings, 2 replies; 3+ messages in thread
From: Yureka Lilian @ 2026-07-05 10:02 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Catalin Marinas, Will Deacon
Cc: linux-doc, linux-kernel, linux-arm-kernel, asahi, Yureka Lilian
Overriding the idle mechanism might be useful for debugging, performance
testing and on platforms where the WFI instruction misbehaves, such as
Apple Silicon SoCs.
Signed-off-by: Yureka Lilian <yureka@cyberchaos.dev>
---
Thanks to Will Daecon for suggesting this path, since, when treating the WFI
misbehavior as an erratum, we had difficulties telling when the alternatives
should be applied. This solution is more flexible and leaves it up to
bootloader to add the appropriate idle= parameter as a workaround.
---
Documentation/admin-guide/kernel-parameters.txt | 23 ++++++++++++++++++
arch/arm64/kernel/idle.c | 31 +++++++++++++++++++++++--
arch/arm64/kernel/idle.h | 11 +++++++++
arch/arm64/lib/delay.c | 7 +++++-
4 files changed, 69 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b2d7d3540ded..d7f5471edf8f 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2239,6 +2239,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: <bool>
Allow force disabling of Shared Virtual Memory (SVA)
diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
index 05cfb347ec26..018bcc812d45 100644
--- a/arch/arm64/kernel/idle.c
+++ b/arch/arm64/kernel/idle.c
@@ -11,6 +11,28 @@
#include <asm/cpufeature.h>
#include <asm/sysreg.h>
+#include "idle.h"
+
+enum idle_mode idle = WFI;
+
+/* User can over-ride above with "idle=<wfi|yield|nop>" in cmdline */
+static int __init setup_idle(char *s)
+{
+ if (!s)
+ return -1;
+ else if (!strcmp(s, "wfi"))
+ idle = WFI;
+ else if (!strcmp(s, "yield"))
+ idle = YIELD;
+ else if (!strcmp(s, "nop"))
+ idle = NOP;
+ else
+ return -1;
+
+ return 0;
+}
+early_param("idle", setup_idle);
+
/*
* cpu_do_idle()
*
@@ -26,8 +48,13 @@ void __cpuidle cpu_do_idle(void)
arm_cpuidle_save_irq_context(&context);
- dsb(sy);
- wfi();
+ if (likely(idle == WFI)) {
+ dsb(sy);
+ wfi();
+ } else if (idle == YIELD) {
+ dsb(sy);
+ asm volatile("yield" ::: "memory");
+ }
arm_cpuidle_restore_irq_context(&context);
}
diff --git a/arch/arm64/kernel/idle.h b/arch/arm64/kernel/idle.h
new file mode 100644
index 000000000000..350b758ea215
--- /dev/null
+++ b/arch/arm64/kernel/idle.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ARM64_KERNEL_IDLE_H
+#define __ARM64_KERNEL_IDLE_H
+
+enum idle_mode {
+ WFI,
+ YIELD,
+ NOP,
+};
+
+#endif
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
index e278e060e78a..d6fd09466abc 100644
--- a/arch/arm64/lib/delay.c
+++ b/arch/arm64/lib/delay.c
@@ -15,9 +15,13 @@
#include <clocksource/arm_arch_timer.h>
+#include "../kernel/idle.h"
+
#define USECS_TO_CYCLES(time_usecs) \
xloops_to_cycles((time_usecs) * 0x10C7UL)
+extern enum idle_mode idle;
+
static inline unsigned long xloops_to_cycles(unsigned long xloops)
{
return (xloops * loops_per_jiffy * HZ) >> 32;
@@ -49,7 +53,8 @@ void __delay(unsigned long cycles)
* Start with WFIT. If an interrupt makes us resume
* early, use a WFET loop to complete the delay.
*/
- wfit(end);
+ if (likely(idle == WFI))
+ wfit(end);
while ((__delay_cycles() - start) < cycles)
wfet(end);
} else if (arch_timer_evtstrm_available()) {
---
base-commit: 96cb07bd64bf4d3c8c9159636314c6fbdd9b9881
change-id: 20260705-arm64-idle-param-c27fc0e7ea05
Best regards,
--
Yureka Lilian <yureka@cyberchaos.dev>
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] arch: arm64: add early_param idle=<wfi|yield|nop>
2026-07-05 10:02 [PATCH] arch: arm64: add early_param idle=<wfi|yield|nop> Yureka Lilian
@ 2026-07-06 5:23 ` Anshuman Khandual
2026-07-06 23:21 ` Joshua Peisach
1 sibling, 0 replies; 3+ messages in thread
From: Anshuman Khandual @ 2026-07-06 5:23 UTC (permalink / raw)
To: Yureka Lilian, Jonathan Corbet, Shuah Khan, Catalin Marinas,
Will Deacon
Cc: linux-doc, linux-kernel, linux-arm-kernel, asahi
On 05/07/26 3:32 PM, Yureka Lilian wrote:
> Overriding the idle mechanism might be useful for debugging, performance
> testing and on platforms where the WFI instruction misbehaves, such as
> Apple Silicon SoCs.
The commit message should have little more description given the proposed
code churn here e.g 'idle=' is not new but an existing kernel command line
parameter already being used on x86 platform and describe different values
it takes on arm64 platform.
>
> Signed-off-by: Yureka Lilian <yureka@cyberchaos.dev>
> ---
> Thanks to Will Daecon for suggesting this path, since, when treating the WFI
> misbehavior as an erratum, we had difficulties telling when the alternatives
This "why standard erratum method could not be used" should be mentioned along
with earlier discussion link in the commit message. Please add 'Suggested-by'.
> should be applied. This solution is more flexible and leaves it up to
> bootloader to add the appropriate idle= parameter as a workaround.
Please do mention this in commit message as well.
> ---> Documentation/admin-guide/kernel-parameters.txt | 23 ++++++++++++++++++
> arch/arm64/kernel/idle.c | 31 +++++++++++++++++++++++--
> arch/arm64/kernel/idle.h | 11 +++++++++
> arch/arm64/lib/delay.c | 7 +++++-
> 4 files changed, 69 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index b2d7d3540ded..d7f5471edf8f 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -2239,6 +2239,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: <bool>
> Allow force disabling of Shared Virtual Memory (SVA)
> diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
> index 05cfb347ec26..018bcc812d45 100644
> --- a/arch/arm64/kernel/idle.c
> +++ b/arch/arm64/kernel/idle.c
> @@ -11,6 +11,28 @@
> #include <asm/cpufeature.h>
> #include <asm/sysreg.h>
>
> +#include "idle.h"
> +
> +enum idle_mode idle = WFI;
> +> +/* User can over-ride above with "idle=<wfi|yield|nop>" in cmdline */
This comment is redundant as the usage in mentioned in Documentation.
> +static int __init setup_idle(char *s)
> +{
> + if (!s)
Small nit - renaming 's' as 'arg' or 'str' might be better I guess.
> + return -1;
> + else if (!strcmp(s, "wfi"))
> + idle = WFI;
> + else if (!strcmp(s, "yield"))
> + idle = YIELD;
> + else if (!strcmp(s, "nop"))
> + idle = NOP;
> + else
> + return -1;
> +
> + return 0;
> +}
> +early_param("idle", setup_idle);
Small nit - s/setup_idle/setup_arm64_idle/
> +
> /*
> * cpu_do_idle()
> *
> @@ -26,8 +48,13 @@ void __cpuidle cpu_do_idle(void)
>
> arm_cpuidle_save_irq_context(&context);
>
> - dsb(sy);
> - wfi();
> + if (likely(idle == WFI)) {
> + dsb(sy);
> + wfi();
> + } else if (idle == YIELD) {
> + dsb(sy);
> + asm volatile("yield" ::: "memory");
> + }
>
> arm_cpuidle_restore_irq_context(&context);
> }
> diff --git a/arch/arm64/kernel/idle.h b/arch/arm64/kernel/idle.h
> new file mode 100644
> index 000000000000..350b758ea215
> --- /dev/null
> +++ b/arch/arm64/kernel/idle.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ARM64_KERNEL_IDLE_H
> +#define __ARM64_KERNEL_IDLE_H
> +
> +enum idle_mode {
Small nit - s/idle_mode/arm64_idle_mode
> + WFI,
> + YIELD,
> + NOP,
Small nit - ARM64_IDLE_[WFI|YIELD|NOP] to be more descriptive
> +};
> +
> +#endif
> diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
> index e278e060e78a..d6fd09466abc 100644
> --- a/arch/arm64/lib/delay.c
> +++ b/arch/arm64/lib/delay.c
> @@ -15,9 +15,13 @@
>
> #include <clocksource/arm_arch_timer.h>
>
> +#include "../kernel/idle.h"
> +
> #define USECS_TO_CYCLES(time_usecs) \
> xloops_to_cycles((time_usecs) * 0x10C7UL)
>
> +extern enum idle_mode idle;
Could the extern be moved inside arch/arm64/kernel/idle.h instead
> +
> static inline unsigned long xloops_to_cycles(unsigned long xloops)
> {
> return (xloops * loops_per_jiffy * HZ) >> 32;
> @@ -49,7 +53,8 @@ void __delay(unsigned long cycles)
> * Start with WFIT. If an interrupt makes us resume
> * early, use a WFET loop to complete the delay.
> */
> - wfit(end);
> + if (likely(idle == WFI))
> + wfit(end);
> while ((__delay_cycles() - start) < cycles)
> wfet(end);
> } else if (arch_timer_evtstrm_available()) {
>
> ---
> base-commit: 96cb07bd64bf4d3c8c9159636314c6fbdd9b9881
> change-id: 20260705-arm64-idle-param-c27fc0e7ea05
>
> Best regards,
> --
> Yureka Lilian <yureka@cyberchaos.dev>
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] arch: arm64: add early_param idle=<wfi|yield|nop>
2026-07-05 10:02 [PATCH] arch: arm64: add early_param idle=<wfi|yield|nop> Yureka Lilian
2026-07-06 5:23 ` Anshuman Khandual
@ 2026-07-06 23:21 ` Joshua Peisach
1 sibling, 0 replies; 3+ messages in thread
From: Joshua Peisach @ 2026-07-06 23:21 UTC (permalink / raw)
To: Yureka Lilian, Jonathan Corbet, Shuah Khan, Catalin Marinas,
Will Deacon
Cc: linux-doc, linux-kernel, linux-arm-kernel, asahi
On Sun Jul 5, 2026 at 6:02 AM EDT, Yureka Lilian wrote:
> +
> +enum idle_mode idle = WFI;
> +
> +/* User can over-ride above with "idle=<wfi|yield|nop>" in cmdline */
> +static int __init setup_idle(char *s)
> +{
> + if (!s)
> + return -1;
> + else if (!strcmp(s, "wfi"))
> + idle = WFI;
> + else if (!strcmp(s, "yield"))
> + idle = YIELD;
> + else if (!strcmp(s, "nop"))
> + idle = NOP;
> + else
> + return -1;
> +
> + return 0;
> +}
> +early_param("idle", setup_idle);
> +
> /*
> * cpu_do_idle()
> *
> @@ -26,8 +48,13 @@ void __cpuidle cpu_do_idle(void)
>
> arm_cpuidle_save_irq_context(&context);
>
> - dsb(sy);
> - wfi();
> + if (likely(idle == WFI)) {
> + dsb(sy);
> + wfi();
> + } else if (idle == YIELD) {
> + dsb(sy);
> + asm volatile("yield" ::: "memory");
> + }
>
And otherwise...........?
I guess it would be NOP, so do nothing - is this expected behavior?
-Josh
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-06 23:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-05 10:02 [PATCH] arch: arm64: add early_param idle=<wfi|yield|nop> Yureka Lilian
2026-07-06 5:23 ` Anshuman Khandual
2026-07-06 23:21 ` Joshua Peisach
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox