Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cpu_pm.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Google, Inc.
3  *
4  * Author:
5  * Colin Cross <[email protected]>
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  */
17 
18 #include <linux/kernel.h>
19 #include <linux/cpu_pm.h>
20 #include <linux/module.h>
21 #include <linux/notifier.h>
22 #include <linux/spinlock.h>
23 #include <linux/syscore_ops.h>
24 
25 static DEFINE_RWLOCK(cpu_pm_notifier_lock);
26 static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain);
27 
28 static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
29 {
30  int ret;
31 
32  ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
33  nr_to_call, nr_calls);
34 
35  return notifier_to_errno(ret);
36 }
37 
49 {
50  unsigned long flags;
51  int ret;
52 
53  write_lock_irqsave(&cpu_pm_notifier_lock, flags);
54  ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
55  write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
56 
57  return ret;
58 }
60 
71 {
72  unsigned long flags;
73  int ret;
74 
75  write_lock_irqsave(&cpu_pm_notifier_lock, flags);
76  ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
77  write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
78 
79  return ret;
80 }
82 
98 int cpu_pm_enter(void)
99 {
100  int nr_calls;
101  int ret = 0;
102 
103  read_lock(&cpu_pm_notifier_lock);
104  ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
105  if (ret)
106  /*
107  * Inform listeners (nr_calls - 1) about failure of CPU PM
108  * PM entry who are notified earlier to prepare for it.
109  */
110  cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
111  read_unlock(&cpu_pm_notifier_lock);
112 
113  return ret;
114 }
116 
129 int cpu_pm_exit(void)
130 {
131  int ret;
132 
133  read_lock(&cpu_pm_notifier_lock);
134  ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
135  read_unlock(&cpu_pm_notifier_lock);
136 
137  return ret;
138 }
140 
158 {
159  int nr_calls;
160  int ret = 0;
161 
162  read_lock(&cpu_pm_notifier_lock);
163  ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
164  if (ret)
165  /*
166  * Inform listeners (nr_calls - 1) about failure of CPU cluster
167  * PM entry who are notified earlier to prepare for it.
168  */
169  cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
170  read_unlock(&cpu_pm_notifier_lock);
171 
172  return ret;
173 }
175 
192 {
193  int ret;
194 
195  read_lock(&cpu_pm_notifier_lock);
196  ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
197  read_unlock(&cpu_pm_notifier_lock);
198 
199  return ret;
200 }
202 
203 #ifdef CONFIG_PM
204 static int cpu_pm_suspend(void)
205 {
206  int ret;
207 
208  ret = cpu_pm_enter();
209  if (ret)
210  return ret;
211 
212  ret = cpu_cluster_pm_enter();
213  return ret;
214 }
215 
216 static void cpu_pm_resume(void)
217 {
219  cpu_pm_exit();
220 }
221 
222 static struct syscore_ops cpu_pm_syscore_ops = {
223  .suspend = cpu_pm_suspend,
224  .resume = cpu_pm_resume,
225 };
226 
227 static int cpu_pm_init(void)
228 {
229  register_syscore_ops(&cpu_pm_syscore_ops);
230  return 0;
231 }
232 core_initcall(cpu_pm_init);
233 #endif