projects/linux·blob master · refs

73 lines · 1.4 KiB

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
14enum {
15 ARM64_IDLE_WFI,
16 ARM64_IDLE_YIELD,
17 ARM64_IDLE_NOP,
18} idle = ARM64_IDLE_WFI;
19
20static 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}
35early_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 */
46void __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 */
66void __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}