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