Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * syscore.c - Execution of system core operations. 4 : : * 5 : : * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. 6 : : */ 7 : : 8 : : #include <linux/syscore_ops.h> 9 : : #include <linux/mutex.h> 10 : : #include <linux/module.h> 11 : : #include <linux/suspend.h> 12 : : #include <trace/events/power.h> 13 : : 14 : : static LIST_HEAD(syscore_ops_list); 15 : : static DEFINE_MUTEX(syscore_ops_lock); 16 : : 17 : : /** 18 : : * register_syscore_ops - Register a set of system core operations. 19 : : * @ops: System core operations to register. 20 : : */ 21 : 130 : void register_syscore_ops(struct syscore_ops *ops) 22 : : { 23 : 130 : mutex_lock(&syscore_ops_lock); 24 : 130 : list_add_tail(&ops->node, &syscore_ops_list); 25 : 130 : mutex_unlock(&syscore_ops_lock); 26 : 130 : } 27 : : EXPORT_SYMBOL_GPL(register_syscore_ops); 28 : : 29 : : /** 30 : : * unregister_syscore_ops - Unregister a set of system core operations. 31 : : * @ops: System core operations to unregister. 32 : : */ 33 : 0 : void unregister_syscore_ops(struct syscore_ops *ops) 34 : : { 35 : 0 : mutex_lock(&syscore_ops_lock); 36 : 0 : list_del(&ops->node); 37 : 0 : mutex_unlock(&syscore_ops_lock); 38 : 0 : } 39 : : EXPORT_SYMBOL_GPL(unregister_syscore_ops); 40 : : 41 : : #ifdef CONFIG_PM_SLEEP 42 : : /** 43 : : * syscore_suspend - Execute all the registered system core suspend callbacks. 44 : : * 45 : : * This function is executed with one CPU on-line and disabled interrupts. 46 : : */ 47 : 0 : int syscore_suspend(void) 48 : : { 49 : 0 : struct syscore_ops *ops; 50 : 0 : int ret = 0; 51 : : 52 : 0 : trace_suspend_resume(TPS("syscore_suspend"), 0, true); 53 : 0 : pr_debug("Checking wakeup interrupts\n"); 54 : : 55 : : /* Return error code if there are any wakeup interrupts pending. */ 56 [ # # ]: 0 : if (pm_wakeup_pending()) 57 : : return -EBUSY; 58 : : 59 [ # # # # ]: 0 : WARN_ONCE(!irqs_disabled(), 60 : : "Interrupts enabled before system core suspend.\n"); 61 : : 62 [ # # ]: 0 : list_for_each_entry_reverse(ops, &syscore_ops_list, node) 63 [ # # ]: 0 : if (ops->suspend) { 64 [ # # ]: 0 : if (initcall_debug) 65 : 0 : pr_info("PM: Calling %pS\n", ops->suspend); 66 : 0 : ret = ops->suspend(); 67 [ # # ]: 0 : if (ret) 68 : 0 : goto err_out; 69 [ # # # # ]: 0 : WARN_ONCE(!irqs_disabled(), 70 : : "Interrupts enabled after %pS\n", ops->suspend); 71 : : } 72 : : 73 : 0 : trace_suspend_resume(TPS("syscore_suspend"), 0, false); 74 : 0 : return 0; 75 : : 76 : : err_out: 77 : 0 : pr_err("PM: System core suspend callback %pS failed.\n", ops->suspend); 78 : : 79 [ # # ]: 0 : list_for_each_entry_continue(ops, &syscore_ops_list, node) 80 [ # # ]: 0 : if (ops->resume) 81 : 0 : ops->resume(); 82 : : 83 : : return ret; 84 : : } 85 : : EXPORT_SYMBOL_GPL(syscore_suspend); 86 : : 87 : : /** 88 : : * syscore_resume - Execute all the registered system core resume callbacks. 89 : : * 90 : : * This function is executed with one CPU on-line and disabled interrupts. 91 : : */ 92 : 0 : void syscore_resume(void) 93 : : { 94 : 0 : struct syscore_ops *ops; 95 : : 96 : 0 : trace_suspend_resume(TPS("syscore_resume"), 0, true); 97 [ # # # # ]: 0 : WARN_ONCE(!irqs_disabled(), 98 : : "Interrupts enabled before system core resume.\n"); 99 : : 100 [ # # ]: 0 : list_for_each_entry(ops, &syscore_ops_list, node) 101 [ # # ]: 0 : if (ops->resume) { 102 [ # # ]: 0 : if (initcall_debug) 103 : 0 : pr_info("PM: Calling %pS\n", ops->resume); 104 : 0 : ops->resume(); 105 [ # # # # ]: 0 : WARN_ONCE(!irqs_disabled(), 106 : : "Interrupts enabled after %pS\n", ops->resume); 107 : : } 108 : 0 : trace_suspend_resume(TPS("syscore_resume"), 0, false); 109 : 0 : } 110 : : EXPORT_SYMBOL_GPL(syscore_resume); 111 : : #endif /* CONFIG_PM_SLEEP */ 112 : : 113 : : /** 114 : : * syscore_shutdown - Execute all the registered system core shutdown callbacks. 115 : : */ 116 : 0 : void syscore_shutdown(void) 117 : : { 118 : 0 : struct syscore_ops *ops; 119 : : 120 : 0 : mutex_lock(&syscore_ops_lock); 121 : : 122 [ # # ]: 0 : list_for_each_entry_reverse(ops, &syscore_ops_list, node) 123 [ # # ]: 0 : if (ops->shutdown) { 124 [ # # ]: 0 : if (initcall_debug) 125 : 0 : pr_info("PM: Calling %pS\n", ops->shutdown); 126 : 0 : ops->shutdown(); 127 : : } 128 : : 129 : 0 : mutex_unlock(&syscore_ops_lock); 130 : 0 : }