aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cpu_pm.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-02-10 05:04:45 -0500
committerSantosh Shilimkar <santosh.shilimkar@ti.com>2011-09-23 02:35:29 -0400
commitab10023e0088d5075354afc7cb9e72304757dddd (patch)
tree5e8424c9818056335baeefcddab18b0600417053 /kernel/cpu_pm.c
parentb6fd41e29dea9c6753b1843a77e50433e6123bcb (diff)
cpu_pm: Add cpu power management notifiers
During some CPU power modes entered during idle, hotplug and suspend, peripherals located in the CPU power domain, such as the GIC, localtimers, and VFP, may be powered down. Add a notifier chain that allows drivers for those peripherals to be notified before and after they may be reset. Notified drivers can include VFP co-processor, interrupt controller and it's PM extensions, local CPU timers context save/restore which shouldn't be interrupted. Hence CPU PM event APIs must be called with interrupts disabled. Signed-off-by: Colin Cross <ccross@android.com> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Tested-and-Acked-by: Shawn Guo <shawn.guo@linaro.org> Tested-by: Kevin Hilman <khilman@ti.com> Tested-by: Vishwanath BS <vishwanath.bs@ti.com>
Diffstat (limited to 'kernel/cpu_pm.c')
-rw-r--r--kernel/cpu_pm.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
new file mode 100644
index 000000000000..4d1ff4acd04b
--- /dev/null
+++ b/kernel/cpu_pm.c
@@ -0,0 +1,200 @@
1/*
2 * Copyright (C) 2011 Google, Inc.
3 *
4 * Author:
5 * Colin Cross <ccross@android.com>
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
24static DEFINE_RWLOCK(cpu_pm_notifier_lock);
25static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain);
26
27static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
28{
29 int ret;
30
31 ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
32 nr_to_call, nr_calls);
33
34 return notifier_to_errno(ret);
35}
36
37/**
38 * cpu_pm_register_notifier - register a driver with cpu_pm
39 * @nb: notifier block to register
40 *
41 * Add a driver to a list of drivers that are notified about
42 * CPU and CPU cluster low power entry and exit.
43 *
44 * This function may sleep, and has the same return conditions as
45 * raw_notifier_chain_register.
46 */
47int cpu_pm_register_notifier(struct notifier_block *nb)
48{
49 unsigned long flags;
50 int ret;
51
52 write_lock_irqsave(&cpu_pm_notifier_lock, flags);
53 ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
54 write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
55
56 return ret;
57}
58EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
59
60/**
61 * cpu_pm_unregister_notifier - unregister a driver with cpu_pm
62 * @nb: notifier block to be unregistered
63 *
64 * Remove a driver from the CPU PM notifier list.
65 *
66 * This function may sleep, and has the same return conditions as
67 * raw_notifier_chain_unregister.
68 */
69int cpu_pm_unregister_notifier(struct notifier_block *nb)
70{
71 unsigned long flags;
72 int ret;
73
74 write_lock_irqsave(&cpu_pm_notifier_lock, flags);
75 ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
76 write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
77
78 return ret;
79}
80EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
81
82/**
83 * cpm_pm_enter - CPU low power entry notifier
84 *
85 * Notifies listeners that a single CPU is entering a low power state that may
86 * cause some blocks in the same power domain as the cpu to reset.
87 *
88 * Must be called on the affected CPU with interrupts disabled. Platform is
89 * responsible for ensuring that cpu_pm_enter is not called twice on the same
90 * CPU before cpu_pm_exit is called. Notified drivers can include VFP
91 * co-processor, interrupt controller and it's PM extensions, local CPU
92 * timers context save/restore which shouldn't be interrupted. Hence it
93 * must be called with interrupts disabled.
94 *
95 * Return conditions are same as __raw_notifier_call_chain.
96 */
97int cpu_pm_enter(void)
98{
99 int nr_calls;
100 int ret = 0;
101
102 read_lock(&cpu_pm_notifier_lock);
103 ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
104 if (ret)
105 /*
106 * Inform listeners (nr_calls - 1) about failure of CPU PM
107 * PM entry who are notified earlier to prepare for it.
108 */
109 cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
110 read_unlock(&cpu_pm_notifier_lock);
111
112 return ret;
113}
114EXPORT_SYMBOL_GPL(cpu_pm_enter);
115
116/**
117 * cpm_pm_exit - CPU low power exit notifier
118 *
119 * Notifies listeners that a single CPU is exiting a low power state that may
120 * have caused some blocks in the same power domain as the cpu to reset.
121 *
122 * Notified drivers can include VFP co-processor, interrupt controller
123 * and it's PM extensions, local CPU timers context save/restore which
124 * shouldn't be interrupted. Hence it must be called with interrupts disabled.
125 *
126 * Return conditions are same as __raw_notifier_call_chain.
127 */
128int cpu_pm_exit(void)
129{
130 int ret;
131
132 read_lock(&cpu_pm_notifier_lock);
133 ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
134 read_unlock(&cpu_pm_notifier_lock);
135
136 return ret;
137}
138EXPORT_SYMBOL_GPL(cpu_pm_exit);
139
140/**
141 * cpm_cluster_pm_enter - CPU cluster low power entry notifier
142 *
143 * Notifies listeners that all cpus in a power domain are entering a low power
144 * state that may cause some blocks in the same power domain to reset.
145 *
146 * Must be called after cpu_pm_enter has been called on all cpus in the power
147 * domain, and before cpu_pm_exit has been called on any cpu in the power
148 * domain. Notified drivers can include VFP co-processor, interrupt controller
149 * and it's PM extensions, local CPU timers context save/restore which
150 * shouldn't be interrupted. Hence it must be called with interrupts disabled.
151 *
152 * Must be called with interrupts disabled.
153 *
154 * Return conditions are same as __raw_notifier_call_chain.
155 */
156int cpu_cluster_pm_enter(void)
157{
158 int nr_calls;
159 int ret = 0;
160
161 read_lock(&cpu_pm_notifier_lock);
162 ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
163 if (ret)
164 /*
165 * Inform listeners (nr_calls - 1) about failure of CPU cluster
166 * PM entry who are notified earlier to prepare for it.
167 */
168 cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
169 read_unlock(&cpu_pm_notifier_lock);
170
171 return ret;
172}
173EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
174
175/**
176 * cpm_cluster_pm_exit - CPU cluster low power exit notifier
177 *
178 * Notifies listeners that all cpus in a power domain are exiting form a
179 * low power state that may have caused some blocks in the same power domain
180 * to reset.
181 *
182 * Must be called after cpu_pm_exit has been called on all cpus in the power
183 * domain, and before cpu_pm_exit has been called on any cpu in the power
184 * domain. Notified drivers can include VFP co-processor, interrupt controller
185 * and it's PM extensions, local CPU timers context save/restore which
186 * shouldn't be interrupted. Hence it must be called with interrupts disabled.
187 *
188 * Return conditions are same as __raw_notifier_call_chain.
189 */
190int cpu_cluster_pm_exit(void)
191{
192 int ret;
193
194 read_lock(&cpu_pm_notifier_lock);
195 ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
196 read_unlock(&cpu_pm_notifier_lock);
197
198 return ret;
199}
200EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);