1de818bd4SLorenzo Pieralisi #include <linux/ftrace.h> 2fb4a9602SLorenzo Pieralisi #include <linux/percpu.h> 395322526SLorenzo Pieralisi #include <linux/slab.h> 495322526SLorenzo Pieralisi #include <asm/cacheflush.h> 595322526SLorenzo Pieralisi #include <asm/debug-monitors.h> 695322526SLorenzo Pieralisi #include <asm/pgtable.h> 795322526SLorenzo Pieralisi #include <asm/memory.h> 8f43c2718SLorenzo Pieralisi #include <asm/mmu_context.h> 995322526SLorenzo Pieralisi #include <asm/smp_plat.h> 1095322526SLorenzo Pieralisi #include <asm/suspend.h> 1195322526SLorenzo Pieralisi #include <asm/tlbflush.h> 1295322526SLorenzo Pieralisi 13*adc9b2dfSJames Morse 1495322526SLorenzo Pieralisi /* 15714f5992SLorenzo Pieralisi * This is called by __cpu_suspend_enter() to save the state, and do whatever 1695322526SLorenzo Pieralisi * flushing is required to ensure that when the CPU goes to sleep we have 1795322526SLorenzo Pieralisi * the necessary data available when the caches are not searched. 1895322526SLorenzo Pieralisi * 19*adc9b2dfSJames Morse * ptr: sleep_stack_data containing cpu state virtual address. 20714f5992SLorenzo Pieralisi * save_ptr: address of the location where the context physical address 2195322526SLorenzo Pieralisi * must be saved 2295322526SLorenzo Pieralisi */ 23*adc9b2dfSJames Morse void notrace __cpu_suspend_save(struct sleep_stack_data *ptr, 2495322526SLorenzo Pieralisi phys_addr_t *save_ptr) 2595322526SLorenzo Pieralisi { 2695322526SLorenzo Pieralisi *save_ptr = virt_to_phys(ptr); 2795322526SLorenzo Pieralisi 28*adc9b2dfSJames Morse cpu_do_suspend(&ptr->system_regs); 2995322526SLorenzo Pieralisi /* 3095322526SLorenzo Pieralisi * Only flush the context that must be retrieved with the MMU 3195322526SLorenzo Pieralisi * off. VA primitives ensure the flush is applied to all 3295322526SLorenzo Pieralisi * cache levels so context is pushed to DRAM. 3395322526SLorenzo Pieralisi */ 3495322526SLorenzo Pieralisi __flush_dcache_area(ptr, sizeof(*ptr)); 3595322526SLorenzo Pieralisi __flush_dcache_area(save_ptr, sizeof(*save_ptr)); 3695322526SLorenzo Pieralisi } 3795322526SLorenzo Pieralisi 3865c021bbSLorenzo Pieralisi /* 3965c021bbSLorenzo Pieralisi * This hook is provided so that cpu_suspend code can restore HW 4065c021bbSLorenzo Pieralisi * breakpoints as early as possible in the resume path, before reenabling 4165c021bbSLorenzo Pieralisi * debug exceptions. Code cannot be run from a CPU PM notifier since by the 4265c021bbSLorenzo Pieralisi * time the notifier runs debug exceptions might have been enabled already, 4365c021bbSLorenzo Pieralisi * with HW breakpoints registers content still in an unknown state. 4465c021bbSLorenzo Pieralisi */ 4501b305a2SJisheng Zhang static void (*hw_breakpoint_restore)(void *); 4665c021bbSLorenzo Pieralisi void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) 4765c021bbSLorenzo Pieralisi { 4865c021bbSLorenzo Pieralisi /* Prevent multiple restore hook initializations */ 4965c021bbSLorenzo Pieralisi if (WARN_ON(hw_breakpoint_restore)) 5065c021bbSLorenzo Pieralisi return; 5165c021bbSLorenzo Pieralisi hw_breakpoint_restore = hw_bp_restore; 5265c021bbSLorenzo Pieralisi } 5365c021bbSLorenzo Pieralisi 54*adc9b2dfSJames Morse void notrace __cpu_suspend_exit(void) 55714f5992SLorenzo Pieralisi { 56f43c2718SLorenzo Pieralisi /* 579e8e865bSMark Rutland * We are resuming from reset with the idmap active in TTBR0_EL1. 589e8e865bSMark Rutland * We must uninstall the idmap and restore the expected MMU 599e8e865bSMark Rutland * state before we can possibly return to userspace. 60f43c2718SLorenzo Pieralisi */ 619e8e865bSMark Rutland cpu_uninstall_idmap(); 62fb4a9602SLorenzo Pieralisi 63fb4a9602SLorenzo Pieralisi /* 64fb4a9602SLorenzo Pieralisi * Restore per-cpu offset before any kernel 65fb4a9602SLorenzo Pieralisi * subsystem relying on it has a chance to run. 66fb4a9602SLorenzo Pieralisi */ 67714f5992SLorenzo Pieralisi set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 68fb4a9602SLorenzo Pieralisi 6965c021bbSLorenzo Pieralisi /* 7065c021bbSLorenzo Pieralisi * Restore HW breakpoint registers to sane values 7165c021bbSLorenzo Pieralisi * before debug exceptions are possibly reenabled 7265c021bbSLorenzo Pieralisi * through local_dbg_restore. 7365c021bbSLorenzo Pieralisi */ 7465c021bbSLorenzo Pieralisi if (hw_breakpoint_restore) 7565c021bbSLorenzo Pieralisi hw_breakpoint_restore(NULL); 7695322526SLorenzo Pieralisi } 7795322526SLorenzo Pieralisi 78*adc9b2dfSJames Morse /* 79*adc9b2dfSJames Morse * cpu_suspend 80*adc9b2dfSJames Morse * 81*adc9b2dfSJames Morse * arg: argument to pass to the finisher function 82*adc9b2dfSJames Morse * fn: finisher function pointer 83*adc9b2dfSJames Morse * 84*adc9b2dfSJames Morse */ 85*adc9b2dfSJames Morse int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) 86*adc9b2dfSJames Morse { 87*adc9b2dfSJames Morse int ret = 0; 88*adc9b2dfSJames Morse unsigned long flags; 89*adc9b2dfSJames Morse struct sleep_stack_data state; 90*adc9b2dfSJames Morse 91*adc9b2dfSJames Morse /* 92*adc9b2dfSJames Morse * From this point debug exceptions are disabled to prevent 93*adc9b2dfSJames Morse * updates to mdscr register (saved and restored along with 94*adc9b2dfSJames Morse * general purpose registers) from kernel debuggers. 95*adc9b2dfSJames Morse */ 96*adc9b2dfSJames Morse local_dbg_save(flags); 97*adc9b2dfSJames Morse 98*adc9b2dfSJames Morse /* 99*adc9b2dfSJames Morse * Function graph tracer state gets incosistent when the kernel 100*adc9b2dfSJames Morse * calls functions that never return (aka suspend finishers) hence 101*adc9b2dfSJames Morse * disable graph tracing during their execution. 102*adc9b2dfSJames Morse */ 103*adc9b2dfSJames Morse pause_graph_tracing(); 104*adc9b2dfSJames Morse 105*adc9b2dfSJames Morse if (__cpu_suspend_enter(&state)) { 106*adc9b2dfSJames Morse /* Call the suspend finisher */ 107*adc9b2dfSJames Morse ret = fn(arg); 108*adc9b2dfSJames Morse 109*adc9b2dfSJames Morse /* 110*adc9b2dfSJames Morse * Never gets here, unless the suspend finisher fails. 111*adc9b2dfSJames Morse * Successful cpu_suspend() should return from cpu_resume(), 112*adc9b2dfSJames Morse * returning through this code path is considered an error 113*adc9b2dfSJames Morse * If the return value is set to 0 force ret = -EOPNOTSUPP 114*adc9b2dfSJames Morse * to make sure a proper error condition is propagated 115*adc9b2dfSJames Morse */ 116*adc9b2dfSJames Morse if (!ret) 117*adc9b2dfSJames Morse ret = -EOPNOTSUPP; 118*adc9b2dfSJames Morse } else { 119*adc9b2dfSJames Morse __cpu_suspend_exit(); 120*adc9b2dfSJames Morse } 121*adc9b2dfSJames Morse 122de818bd4SLorenzo Pieralisi unpause_graph_tracing(); 123de818bd4SLorenzo Pieralisi 12495322526SLorenzo Pieralisi /* 12595322526SLorenzo Pieralisi * Restore pstate flags. OS lock and mdscr have been already 12695322526SLorenzo Pieralisi * restored, so from this point onwards, debugging is fully 12795322526SLorenzo Pieralisi * renabled if it was enabled when core started shutdown. 12895322526SLorenzo Pieralisi */ 12995322526SLorenzo Pieralisi local_dbg_restore(flags); 13095322526SLorenzo Pieralisi 13195322526SLorenzo Pieralisi return ret; 13295322526SLorenzo Pieralisi } 13395322526SLorenzo Pieralisi 134c3684fbbSLaura Abbott struct sleep_save_sp sleep_save_sp; 13595322526SLorenzo Pieralisi 13618ab7db6SLorenzo Pieralisi static int __init cpu_suspend_init(void) 13795322526SLorenzo Pieralisi { 13895322526SLorenzo Pieralisi void *ctx_ptr; 13995322526SLorenzo Pieralisi 14095322526SLorenzo Pieralisi /* ctx_ptr is an array of physical addresses */ 14195322526SLorenzo Pieralisi ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(phys_addr_t), GFP_KERNEL); 14295322526SLorenzo Pieralisi 14395322526SLorenzo Pieralisi if (WARN_ON(!ctx_ptr)) 14495322526SLorenzo Pieralisi return -ENOMEM; 14595322526SLorenzo Pieralisi 14695322526SLorenzo Pieralisi sleep_save_sp.save_ptr_stash = ctx_ptr; 14795322526SLorenzo Pieralisi sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr); 14895322526SLorenzo Pieralisi __flush_dcache_area(&sleep_save_sp, sizeof(struct sleep_save_sp)); 14995322526SLorenzo Pieralisi 15095322526SLorenzo Pieralisi return 0; 15195322526SLorenzo Pieralisi } 15295322526SLorenzo Pieralisi early_initcall(cpu_suspend_init); 153