diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/base/syscore.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/base/syscore.c')
-rw-r--r-- | drivers/base/syscore.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c new file mode 100644 index 000000000000..e8d11b6630ee --- /dev/null +++ b/drivers/base/syscore.c | |||
@@ -0,0 +1,127 @@ | |||
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 | void register_syscore_ops(struct syscore_ops *ops) | ||
22 | { | ||
23 | mutex_lock(&syscore_ops_lock); | ||
24 | list_add_tail(&ops->node, &syscore_ops_list); | ||
25 | mutex_unlock(&syscore_ops_lock); | ||
26 | } | ||
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 | void unregister_syscore_ops(struct syscore_ops *ops) | ||
34 | { | ||
35 | mutex_lock(&syscore_ops_lock); | ||
36 | list_del(&ops->node); | ||
37 | mutex_unlock(&syscore_ops_lock); | ||
38 | } | ||
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 | 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 | ret = check_wakeup_irqs(); | ||
56 | if (ret) | ||
57 | return ret; | ||
58 | |||
59 | WARN_ONCE(!irqs_disabled(), | ||
60 | "Interrupts enabled before system core suspend.\n"); | ||
61 | |||
62 | list_for_each_entry_reverse(ops, &syscore_ops_list, node) | ||
63 | if (ops->suspend) { | ||
64 | if (initcall_debug) | ||
65 | pr_info("PM: Calling %pF\n", ops->suspend); | ||
66 | ret = ops->suspend(); | ||
67 | if (ret) | ||
68 | goto err_out; | ||
69 | WARN_ONCE(!irqs_disabled(), | ||
70 | "Interrupts enabled after %pF\n", ops->suspend); | ||
71 | } | ||
72 | |||
73 | return 0; | ||
74 | |||
75 | err_out: | ||
76 | pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend); | ||
77 | |||
78 | list_for_each_entry_continue(ops, &syscore_ops_list, node) | ||
79 | if (ops->resume) | ||
80 | 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 | void syscore_resume(void) | ||
92 | { | ||
93 | struct syscore_ops *ops; | ||
94 | |||
95 | WARN_ONCE(!irqs_disabled(), | ||
96 | "Interrupts enabled before system core resume.\n"); | ||
97 | |||
98 | list_for_each_entry(ops, &syscore_ops_list, node) | ||
99 | if (ops->resume) { | ||
100 | if (initcall_debug) | ||
101 | pr_info("PM: Calling %pF\n", ops->resume); | ||
102 | ops->resume(); | ||
103 | WARN_ONCE(!irqs_disabled(), | ||
104 | "Interrupts enabled after %pF\n", ops->resume); | ||
105 | } | ||
106 | } | ||
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 | void syscore_shutdown(void) | ||
114 | { | ||
115 | struct syscore_ops *ops; | ||
116 | |||
117 | mutex_lock(&syscore_ops_lock); | ||
118 | |||
119 | list_for_each_entry_reverse(ops, &syscore_ops_list, node) | ||
120 | if (ops->shutdown) { | ||
121 | if (initcall_debug) | ||
122 | pr_info("PM: Calling %pF\n", ops->shutdown); | ||
123 | ops->shutdown(); | ||
124 | } | ||
125 | |||
126 | mutex_unlock(&syscore_ops_lock); | ||
127 | } | ||