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