Branch data Line data Source code
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 : :
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 : 0 : void register_syscore_ops(struct syscore_ops *ops)
22 : : {
23 : 0 : mutex_lock(&syscore_ops_lock);
24 : 0 : list_add_tail(&ops->node, &syscore_ops_list);
25 : 0 : mutex_unlock(&syscore_ops_lock);
26 : 0 : }
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 : : 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 : : struct syscore_ops *ops;
50 : : int ret = 0;
51 : :
52 : : pr_debug("Checking wakeup interrupts\n");
53 : :
54 : : /* Return error code if there are any wakeup interrupts pending. */
55 : 0 : ret = check_wakeup_irqs();
56 [ # # ]: 0 : if (ret)
57 : : return ret;
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 %pF\n", ops->suspend);
66 : 0 : ret = ops->suspend();
67 [ # # ]: 0 : if (ret)
68 : : goto err_out;
69 [ # # ][ # # ]: 0 : WARN_ONCE(!irqs_disabled(),
[ # # ]
70 : : "Interrupts enabled after %pF\n", ops->suspend);
71 : : }
72 : :
73 : : return 0;
74 : :
75 : : err_out:
76 : 0 : pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend);
77 : :
78 [ # # ]: 0 : list_for_each_entry_continue(ops, &syscore_ops_list, node)
79 [ # # ]: 0 : if (ops->resume)
80 : 0 : ops->resume();
81 : :
82 : : return ret;
83 : : }
84 : : EXPORT_SYMBOL_GPL(syscore_suspend);
85 : :
86 : : /**
87 : : * syscore_resume - Execute all the registered system core resume callbacks.
88 : : *
89 : : * This function is executed with one CPU on-line and disabled interrupts.
90 : : */
91 : 0 : void syscore_resume(void)
92 : : {
93 : : struct syscore_ops *ops;
94 : :
95 [ # # ][ # # ]: 0 : WARN_ONCE(!irqs_disabled(),
[ # # ]
96 : : "Interrupts enabled before system core resume.\n");
97 : :
98 [ # # ]: 0 : list_for_each_entry(ops, &syscore_ops_list, node)
99 [ # # ]: 0 : if (ops->resume) {
100 [ # # ]: 0 : if (initcall_debug)
101 : 0 : pr_info("PM: Calling %pF\n", ops->resume);
102 : 0 : ops->resume();
103 [ # # ][ # # ]: 0 : WARN_ONCE(!irqs_disabled(),
[ # # ]
104 : : "Interrupts enabled after %pF\n", ops->resume);
105 : : }
106 : 0 : }
107 : : EXPORT_SYMBOL_GPL(syscore_resume);
108 : : #endif /* CONFIG_PM_SLEEP */
109 : :
110 : : /**
111 : : * syscore_shutdown - Execute all the registered system core shutdown callbacks.
112 : : */
113 : 0 : void syscore_shutdown(void)
114 : : {
115 : : struct syscore_ops *ops;
116 : :
117 : 0 : mutex_lock(&syscore_ops_lock);
118 : :
119 [ # # ]: 0 : list_for_each_entry_reverse(ops, &syscore_ops_list, node)
120 [ # # ]: 0 : if (ops->shutdown) {
121 [ # # ]: 0 : if (initcall_debug)
122 : 0 : pr_info("PM: Calling %pF\n", ops->shutdown);
123 : 0 : ops->shutdown();
124 : : }
125 : :
126 : 0 : mutex_unlock(&syscore_ops_lock);
127 : 0 : }
|