arm64: suspend: Use cpuidle context helpers in cpu_suspend()
authorMarc Zyngier <maz@kernel.org>
Tue, 15 Jun 2021 11:12:27 +0000 (12:12 +0100)
committerWill Deacon <will@kernel.org>
Thu, 17 Jun 2021 17:00:39 +0000 (18:00 +0100)
Use cpuidle context helpers to switch to using DAIF.IF instead
of PMR to mask interrupts, ensuring that we suspend with
interrupts being able to reach the CPU interface.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
Link: https://lore.kernel.org/r/20210615111227.2454465-5-maz@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/kernel/suspend.c

index e3f72df9509d72e18b192aa106dec182ace45293..938ce6fbee8a80be5ed1431365874e57311a9807 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/alternative.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
+#include <asm/cpuidle.h>
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
 #include <asm/exec.h>
@@ -91,6 +92,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
        int ret = 0;
        unsigned long flags;
        struct sleep_stack_data state;
+       struct arm_cpuidle_irq_context context;
 
        /* Report any MTE async fault before going to suspend */
        mte_suspend_enter();
@@ -103,12 +105,18 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
        flags = local_daif_save();
 
        /*
-        * Function graph tracer state gets incosistent when the kernel
+        * Function graph tracer state gets inconsistent when the kernel
         * calls functions that never return (aka suspend finishers) hence
         * disable graph tracing during their execution.
         */
        pause_graph_tracing();
 
+       /*
+        * Switch to using DAIF.IF instead of PMR in order to reliably
+        * resume if we're using pseudo-NMIs.
+        */
+       arm_cpuidle_save_irq_context(&context);
+
        if (__cpu_suspend_enter(&state)) {
                /* Call the suspend finisher */
                ret = fn(arg);
@@ -126,6 +134,8 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
                RCU_NONIDLE(__cpu_suspend_exit());
        }
 
+       arm_cpuidle_restore_irq_context(&context);
+
        unpause_graph_tracing();
 
        /*