1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2021 Western Digital Corporation or its affiliates. 4 * Copyright (c) 2022 Ventana Micro Systems Inc. 5 */ 6 7 #include <linux/ftrace.h> 8 #include <asm/csr.h> 9 #include <asm/suspend.h> 10 11 static void suspend_save_csrs(struct suspend_context *context) 12 { 13 context->scratch = csr_read(CSR_SCRATCH); 14 context->tvec = csr_read(CSR_TVEC); 15 context->ie = csr_read(CSR_IE); 16 17 /* 18 * No need to save/restore IP CSR (i.e. MIP or SIP) because: 19 * 20 * 1. For no-MMU (M-mode) kernel, the bits in MIP are set by 21 * external devices (such as interrupt controller, timer, etc). 22 * 2. For MMU (S-mode) kernel, the bits in SIP are set by 23 * M-mode firmware and external devices (such as interrupt 24 * controller, etc). 25 */ 26 27 #ifdef CONFIG_MMU 28 context->satp = csr_read(CSR_SATP); 29 #endif 30 } 31 32 static void suspend_restore_csrs(struct suspend_context *context) 33 { 34 csr_write(CSR_SCRATCH, context->scratch); 35 csr_write(CSR_TVEC, context->tvec); 36 csr_write(CSR_IE, context->ie); 37 38 #ifdef CONFIG_MMU 39 csr_write(CSR_SATP, context->satp); 40 #endif 41 } 42 43 int cpu_suspend(unsigned long arg, 44 int (*finish)(unsigned long arg, 45 unsigned long entry, 46 unsigned long context)) 47 { 48 int rc = 0; 49 struct suspend_context context = { 0 }; 50 51 /* Finisher should be non-NULL */ 52 if (!finish) 53 return -EINVAL; 54 55 /* Save additional CSRs*/ 56 suspend_save_csrs(&context); 57 58 /* 59 * Function graph tracer state gets incosistent when the kernel 60 * calls functions that never return (aka finishers) hence disable 61 * graph tracing during their execution. 62 */ 63 pause_graph_tracing(); 64 65 /* Save context on stack */ 66 if (__cpu_suspend_enter(&context)) { 67 /* Call the finisher */ 68 rc = finish(arg, __pa_symbol(__cpu_resume_enter), 69 (ulong)&context); 70 71 /* 72 * Should never reach here, unless the suspend finisher 73 * fails. Successful cpu_suspend() should return from 74 * __cpu_resume_entry() 75 */ 76 if (!rc) 77 rc = -EOPNOTSUPP; 78 } 79 80 /* Enable function graph tracer */ 81 unpause_graph_tracing(); 82 83 /* Restore additional CSRs */ 84 suspend_restore_csrs(&context); 85 86 return rc; 87 } 88