root/arch/arm64/kernel/suspend.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cpu_suspend_set_dbg_restorer
  2. __cpu_suspend_exit
  3. cpu_suspend
  4. cpu_suspend_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/ftrace.h>
   3 #include <linux/percpu.h>
   4 #include <linux/slab.h>
   5 #include <linux/uaccess.h>
   6 #include <asm/alternative.h>
   7 #include <asm/cacheflush.h>
   8 #include <asm/cpufeature.h>
   9 #include <asm/daifflags.h>
  10 #include <asm/debug-monitors.h>
  11 #include <asm/exec.h>
  12 #include <asm/pgtable.h>
  13 #include <asm/memory.h>
  14 #include <asm/mmu_context.h>
  15 #include <asm/smp_plat.h>
  16 #include <asm/suspend.h>
  17 
  18 /*
  19  * This is allocated by cpu_suspend_init(), and used to store a pointer to
  20  * the 'struct sleep_stack_data' the contains a particular CPUs state.
  21  */
  22 unsigned long *sleep_save_stash;
  23 
  24 /*
  25  * This hook is provided so that cpu_suspend code can restore HW
  26  * breakpoints as early as possible in the resume path, before reenabling
  27  * debug exceptions. Code cannot be run from a CPU PM notifier since by the
  28  * time the notifier runs debug exceptions might have been enabled already,
  29  * with HW breakpoints registers content still in an unknown state.
  30  */
  31 static int (*hw_breakpoint_restore)(unsigned int);
  32 void __init cpu_suspend_set_dbg_restorer(int (*hw_bp_restore)(unsigned int))
  33 {
  34         /* Prevent multiple restore hook initializations */
  35         if (WARN_ON(hw_breakpoint_restore))
  36                 return;
  37         hw_breakpoint_restore = hw_bp_restore;
  38 }
  39 
  40 void notrace __cpu_suspend_exit(void)
  41 {
  42         unsigned int cpu = smp_processor_id();
  43 
  44         /*
  45          * We are resuming from reset with the idmap active in TTBR0_EL1.
  46          * We must uninstall the idmap and restore the expected MMU
  47          * state before we can possibly return to userspace.
  48          */
  49         cpu_uninstall_idmap();
  50 
  51         /* Restore CnP bit in TTBR1_EL1 */
  52         if (system_supports_cnp())
  53                 cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
  54 
  55         /*
  56          * PSTATE was not saved over suspend/resume, re-enable any detected
  57          * features that might not have been set correctly.
  58          */
  59         __uaccess_enable_hw_pan();
  60         uao_thread_switch(current);
  61 
  62         /*
  63          * Restore HW breakpoint registers to sane values
  64          * before debug exceptions are possibly reenabled
  65          * by cpu_suspend()s local_daif_restore() call.
  66          */
  67         if (hw_breakpoint_restore)
  68                 hw_breakpoint_restore(cpu);
  69 
  70         /*
  71          * On resume, firmware implementing dynamic mitigation will
  72          * have turned the mitigation on. If the user has forcefully
  73          * disabled it, make sure their wishes are obeyed.
  74          */
  75         if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE)
  76                 arm64_set_ssbd_mitigation(false);
  77 }
  78 
  79 /*
  80  * cpu_suspend
  81  *
  82  * arg: argument to pass to the finisher function
  83  * fn: finisher function pointer
  84  *
  85  */
  86 int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
  87 {
  88         int ret = 0;
  89         unsigned long flags;
  90         struct sleep_stack_data state;
  91 
  92         /*
  93          * From this point debug exceptions are disabled to prevent
  94          * updates to mdscr register (saved and restored along with
  95          * general purpose registers) from kernel debuggers.
  96          */
  97         flags = local_daif_save();
  98 
  99         /*
 100          * Function graph tracer state gets incosistent when the kernel
 101          * calls functions that never return (aka suspend finishers) hence
 102          * disable graph tracing during their execution.
 103          */
 104         pause_graph_tracing();
 105 
 106         if (__cpu_suspend_enter(&state)) {
 107                 /* Call the suspend finisher */
 108                 ret = fn(arg);
 109 
 110                 /*
 111                  * Never gets here, unless the suspend finisher fails.
 112                  * Successful cpu_suspend() should return from cpu_resume(),
 113                  * returning through this code path is considered an error
 114                  * If the return value is set to 0 force ret = -EOPNOTSUPP
 115                  * to make sure a proper error condition is propagated
 116                  */
 117                 if (!ret)
 118                         ret = -EOPNOTSUPP;
 119         } else {
 120                 __cpu_suspend_exit();
 121         }
 122 
 123         unpause_graph_tracing();
 124 
 125         /*
 126          * Restore pstate flags. OS lock and mdscr have been already
 127          * restored, so from this point onwards, debugging is fully
 128          * renabled if it was enabled when core started shutdown.
 129          */
 130         local_daif_restore(flags);
 131 
 132         return ret;
 133 }
 134 
 135 static int __init cpu_suspend_init(void)
 136 {
 137         /* ctx_ptr is an array of physical addresses */
 138         sleep_save_stash = kcalloc(mpidr_hash_size(), sizeof(*sleep_save_stash),
 139                                    GFP_KERNEL);
 140 
 141         if (WARN_ON(!sleep_save_stash))
 142                 return -ENOMEM;
 143 
 144         return 0;
 145 }
 146 early_initcall(cpu_suspend_init);

/* [<][>][^][v][top][bottom][index][help] */