Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

Linux/kernel/cpu_pm.c

  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 #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 
 38 /**
 39  * cpu_pm_register_notifier - register a driver with cpu_pm
 40  * @nb: notifier block to register
 41  *
 42  * Add a driver to a list of drivers that are notified about
 43  * CPU and CPU cluster low power entry and exit.
 44  *
 45  * This function may sleep, and has the same return conditions as
 46  * raw_notifier_chain_register.
 47  */
 48 int cpu_pm_register_notifier(struct notifier_block *nb)
 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 }
 59 EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
 60 
 61 /**
 62  * cpu_pm_unregister_notifier - unregister a driver with cpu_pm
 63  * @nb: notifier block to be unregistered
 64  *
 65  * Remove a driver from the CPU PM notifier list.
 66  *
 67  * This function may sleep, and has the same return conditions as
 68  * raw_notifier_chain_unregister.
 69  */
 70 int cpu_pm_unregister_notifier(struct notifier_block *nb)
 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 }
 81 EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
 82 
 83 /**
 84  * cpu_pm_enter - CPU low power entry notifier
 85  *
 86  * Notifies listeners that a single CPU is entering a low power state that may
 87  * cause some blocks in the same power domain as the cpu to reset.
 88  *
 89  * Must be called on the affected CPU with interrupts disabled.  Platform is
 90  * responsible for ensuring that cpu_pm_enter is not called twice on the same
 91  * CPU before cpu_pm_exit is called. Notified drivers can include VFP
 92  * co-processor, interrupt controller and its PM extensions, local CPU
 93  * timers context save/restore which shouldn't be interrupted. Hence it
 94  * must be called with interrupts disabled.
 95  *
 96  * Return conditions are same as __raw_notifier_call_chain.
 97  */
 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 }
115 EXPORT_SYMBOL_GPL(cpu_pm_enter);
116 
117 /**
118  * cpu_pm_exit - CPU low power exit notifier
119  *
120  * Notifies listeners that a single CPU is exiting a low power state that may
121  * have caused some blocks in the same power domain as the cpu to reset.
122  *
123  * Notified drivers can include VFP co-processor, interrupt controller
124  * and its PM extensions, local CPU timers context save/restore which
125  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
126  *
127  * Return conditions are same as __raw_notifier_call_chain.
128  */
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 }
139 EXPORT_SYMBOL_GPL(cpu_pm_exit);
140 
141 /**
142  * cpu_cluster_pm_enter - CPU cluster low power entry notifier
143  *
144  * Notifies listeners that all cpus in a power domain are entering a low power
145  * state that may cause some blocks in the same power domain to reset.
146  *
147  * Must be called after cpu_pm_enter has been called on all cpus in the power
148  * domain, and before cpu_pm_exit has been called on any cpu in the power
149  * domain. Notified drivers can include VFP co-processor, interrupt controller
150  * and its PM extensions, local CPU timers context save/restore which
151  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
152  *
153  * Must be called with interrupts disabled.
154  *
155  * Return conditions are same as __raw_notifier_call_chain.
156  */
157 int cpu_cluster_pm_enter(void)
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 }
174 EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
175 
176 /**
177  * cpu_cluster_pm_exit - CPU cluster low power exit notifier
178  *
179  * Notifies listeners that all cpus in a power domain are exiting form a
180  * low power state that may have caused some blocks in the same power domain
181  * to reset.
182  *
183  * Must be called after cpu_cluster_pm_enter has been called for the power
184  * domain, and before cpu_pm_exit has been called on any cpu in the power
185  * domain. Notified drivers can include VFP co-processor, interrupt controller
186  * and its PM extensions, local CPU timers context save/restore which
187  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
188  *
189  * Return conditions are same as __raw_notifier_call_chain.
190  */
191 int cpu_cluster_pm_exit(void)
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 }
201 EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
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 {
218         cpu_cluster_pm_exit();
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
234 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us