summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/idle.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/idle.c')
-rw-r--r--arch/arm64/kernel/idle.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
new file mode 100644
index 000000000..42c5543f9
--- /dev/null
+++ b/arch/arm64/kernel/idle.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Low-level idle sequences
+ */
+
+#include <linux/cpu.h>
+#include <linux/irqflags.h>
+
+#include <asm/barrier.h>
+#include <asm/cpuidle.h>
+#include <asm/cpufeature.h>
+#include <asm/sysreg.h>
+
+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()
+ *
+ * Idle the processor (wait for interrupt).
+ *
+ * If the CPU supports priority masking we must do additional work to
+ * ensure that interrupts are not masked at the PMR (because the core will
+ * not wake up if we block the wake up signal in the interrupt controller).
+ */
+void __cpuidle cpu_do_idle(void)
+{
+ struct arm_cpuidle_irq_context context;
+
+ arm_cpuidle_save_irq_context(&context);
+
+ 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);
+}
+
+/*
+ * This is our default idle handler.
+ */
+void __cpuidle arch_cpu_idle(void)
+{
+ /*
+ * This should do all the clock switching and wait for interrupt
+ * tricks
+ */
+ cpu_do_idle();
+}