xref: /linux/arch/arm64/kernel/idle.c (revision f4cdf7ca9a1fdcca413157df19753f388a5a224e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Low-level idle sequences
4  */
5 
6 #include <linux/cpu.h>
7 #include <linux/irqflags.h>
8 
9 #include <asm/barrier.h>
10 #include <asm/cpuidle.h>
11 #include <asm/cpufeature.h>
12 #include <asm/sysreg.h>
13 
14 enum {
15     ARM64_IDLE_WFI,
16     ARM64_IDLE_YIELD,
17     ARM64_IDLE_NOP,
18 } idle = ARM64_IDLE_WFI;
19 
20 static int __init setup_idle(char *arg)
21 {
22 	if (!arg)
23 		return -1;
24 	else if (!strcmp(arg, "wfi"))
25 		idle = ARM64_IDLE_WFI;
26 	else if (!strcmp(arg, "yield"))
27 		idle = ARM64_IDLE_YIELD;
28 	else if (!strcmp(arg, "nop"))
29 		idle = ARM64_IDLE_NOP;
30 	else
31 		return -1;
32 
33 	return 0;
34 }
35 early_param("idle", setup_idle);
36 
37 /*
38  *	cpu_do_idle()
39  *
40  *	Idle the processor (wait for interrupt).
41  *
42  *	If the CPU supports priority masking we must do additional work to
43  *	ensure that interrupts are not masked at the PMR (because the core will
44  *	not wake up if we block the wake up signal in the interrupt controller).
45  */
46 void __cpuidle cpu_do_idle(void)
47 {
48 	struct arm_cpuidle_irq_context context;
49 
50 	arm_cpuidle_save_irq_context(&context);
51 
52 	if (likely(idle == ARM64_IDLE_WFI)) {
53 		dsb(sy);
54 		wfi();
55 	} else if (idle == ARM64_IDLE_YIELD) {
56 		dsb(sy);
57 		asm volatile("yield" ::: "memory");
58 	}
59 
60 	arm_cpuidle_restore_irq_context(&context);
61 }
62 
63 /*
64  * This is our default idle handler.
65  */
66 void __cpuidle arch_cpu_idle(void)
67 {
68 	/*
69 	 * This should do all the clock switching and wait for interrupt
70 	 * tricks
71 	 */
72 	cpu_do_idle();
73 }
74