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 77 /** 78 * syscore_resume - Execute all the registered system core resume callbacks. 79 * 80 * This function is executed with one CPU on-line and disabled interrupts. 81 */ 82 void syscore_resume(void) 83 { 84 struct syscore_ops *ops; 85 86 WARN_ONCE(!irqs_disabled(), 87 "Interrupts enabled before system core resume.\n"); 88 89 list_for_each_entry(ops, &syscore_ops_list, node) 90 if (ops->resume) { 91 if (initcall_debug) 92 pr_info("PM: Calling %pF\n", ops->resume); 93 ops->resume(); 94 WARN_ONCE(!irqs_disabled(), 95 "Interrupts enabled after %pF\n", ops->resume); 96 } 97 } 98 #endif /* CONFIG_PM_SLEEP */ 99 100 /** 101 * syscore_shutdown - Execute all the registered system core shutdown callbacks. 102 */ 103 void syscore_shutdown(void) 104 { 105 struct syscore_ops *ops; 106 107 mutex_lock(&syscore_ops_lock); 108 109 list_for_each_entry_reverse(ops, &syscore_ops_list, node) 110 if (ops->shutdown) { 111 if (initcall_debug) 112 pr_info("PM: Calling %pF\n", ops->shutdown); 113 ops->shutdown(); 114 } 115 116 mutex_unlock(&syscore_ops_lock); 117 } 118