Merge tag 'media/v4.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[platform/kernel/linux-rpi.git] / 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 ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain);
26
27 static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
28 {
29         int ret;
30
31         /*
32          * __atomic_notifier_call_chain has a RCU read critical section, which
33          * could be disfunctional in cpu idle. Copy RCU_NONIDLE code to let
34          * RCU know this.
35          */
36         rcu_irq_enter_irqson();
37         ret = __atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
38                 nr_to_call, nr_calls);
39         rcu_irq_exit_irqson();
40
41         return notifier_to_errno(ret);
42 }
43
44 /**
45  * cpu_pm_register_notifier - register a driver with cpu_pm
46  * @nb: notifier block to register
47  *
48  * Add a driver to a list of drivers that are notified about
49  * CPU and CPU cluster low power entry and exit.
50  *
51  * This function may sleep, and has the same return conditions as
52  * raw_notifier_chain_register.
53  */
54 int cpu_pm_register_notifier(struct notifier_block *nb)
55 {
56         return atomic_notifier_chain_register(&cpu_pm_notifier_chain, nb);
57 }
58 EXPORT_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  */
69 int cpu_pm_unregister_notifier(struct notifier_block *nb)
70 {
71         return atomic_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
72 }
73 EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
74
75 /**
76  * cpu_pm_enter - CPU low power entry notifier
77  *
78  * Notifies listeners that a single CPU is entering a low power state that may
79  * cause some blocks in the same power domain as the cpu to reset.
80  *
81  * Must be called on the affected CPU with interrupts disabled.  Platform is
82  * responsible for ensuring that cpu_pm_enter is not called twice on the same
83  * CPU before cpu_pm_exit is called. Notified drivers can include VFP
84  * co-processor, interrupt controller and its PM extensions, local CPU
85  * timers context save/restore which shouldn't be interrupted. Hence it
86  * must be called with interrupts disabled.
87  *
88  * Return conditions are same as __raw_notifier_call_chain.
89  */
90 int cpu_pm_enter(void)
91 {
92         int nr_calls;
93         int ret = 0;
94
95         ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
96         if (ret)
97                 /*
98                  * Inform listeners (nr_calls - 1) about failure of CPU PM
99                  * PM entry who are notified earlier to prepare for it.
100                  */
101                 cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
102
103         return ret;
104 }
105 EXPORT_SYMBOL_GPL(cpu_pm_enter);
106
107 /**
108  * cpu_pm_exit - CPU low power exit notifier
109  *
110  * Notifies listeners that a single CPU is exiting a low power state that may
111  * have caused some blocks in the same power domain as the cpu to reset.
112  *
113  * Notified drivers can include VFP co-processor, interrupt controller
114  * and its PM extensions, local CPU timers context save/restore which
115  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
116  *
117  * Return conditions are same as __raw_notifier_call_chain.
118  */
119 int cpu_pm_exit(void)
120 {
121         return cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
122 }
123 EXPORT_SYMBOL_GPL(cpu_pm_exit);
124
125 /**
126  * cpu_cluster_pm_enter - CPU cluster low power entry notifier
127  *
128  * Notifies listeners that all cpus in a power domain are entering a low power
129  * state that may cause some blocks in the same power domain to reset.
130  *
131  * Must be called after cpu_pm_enter has been called on all cpus in the power
132  * domain, and before cpu_pm_exit has been called on any cpu in the power
133  * domain. Notified drivers can include VFP co-processor, interrupt controller
134  * and its PM extensions, local CPU timers context save/restore which
135  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
136  *
137  * Must be called with interrupts disabled.
138  *
139  * Return conditions are same as __raw_notifier_call_chain.
140  */
141 int cpu_cluster_pm_enter(void)
142 {
143         int nr_calls;
144         int ret = 0;
145
146         ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
147         if (ret)
148                 /*
149                  * Inform listeners (nr_calls - 1) about failure of CPU cluster
150                  * PM entry who are notified earlier to prepare for it.
151                  */
152                 cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
153
154         return ret;
155 }
156 EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
157
158 /**
159  * cpu_cluster_pm_exit - CPU cluster low power exit notifier
160  *
161  * Notifies listeners that all cpus in a power domain are exiting form a
162  * low power state that may have caused some blocks in the same power domain
163  * to reset.
164  *
165  * Must be called after cpu_cluster_pm_enter has been called for the power
166  * domain, and before cpu_pm_exit has been called on any cpu in the power
167  * domain. Notified drivers can include VFP co-processor, interrupt controller
168  * and its PM extensions, local CPU timers context save/restore which
169  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
170  *
171  * Return conditions are same as __raw_notifier_call_chain.
172  */
173 int cpu_cluster_pm_exit(void)
174 {
175         return cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
176 }
177 EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
178
179 #ifdef CONFIG_PM
180 static int cpu_pm_suspend(void)
181 {
182         int ret;
183
184         ret = cpu_pm_enter();
185         if (ret)
186                 return ret;
187
188         ret = cpu_cluster_pm_enter();
189         return ret;
190 }
191
192 static void cpu_pm_resume(void)
193 {
194         cpu_cluster_pm_exit();
195         cpu_pm_exit();
196 }
197
198 static struct syscore_ops cpu_pm_syscore_ops = {
199         .suspend = cpu_pm_suspend,
200         .resume = cpu_pm_resume,
201 };
202
203 static int cpu_pm_init(void)
204 {
205         register_syscore_ops(&cpu_pm_syscore_ops);
206         return 0;
207 }
208 core_initcall(cpu_pm_init);
209 #endif