]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/base/power/domain.c
PM: Introduce generic "noirq" callback routines for subsystems (v2)
[mirror_ubuntu-artful-kernel.git] / drivers / base / power / domain.c
CommitLineData
f721889f
RW
1/*
2 * drivers/base/power/domain.c - Common code related to device power domains.
3 *
4 * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
5 *
6 * This file is released under the GPLv2.
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/io.h>
12#include <linux/pm_runtime.h>
13#include <linux/pm_domain.h>
14#include <linux/slab.h>
15#include <linux/err.h>
16
17#ifdef CONFIG_PM_RUNTIME
18
19static void genpd_sd_counter_dec(struct generic_pm_domain *genpd)
20{
21 if (!WARN_ON(genpd->sd_count == 0))
22 genpd->sd_count--;
23}
24
25/**
26 * __pm_genpd_save_device - Save the pre-suspend state of a device.
27 * @dle: Device list entry of the device to save the state of.
28 * @genpd: PM domain the device belongs to.
29 */
30static int __pm_genpd_save_device(struct dev_list_entry *dle,
31 struct generic_pm_domain *genpd)
32{
33 struct device *dev = dle->dev;
34 struct device_driver *drv = dev->driver;
35 int ret = 0;
36
37 if (dle->need_restore)
38 return 0;
39
40 if (drv && drv->pm && drv->pm->runtime_suspend) {
41 if (genpd->start_device)
42 genpd->start_device(dev);
43
44 ret = drv->pm->runtime_suspend(dev);
45
46 if (genpd->stop_device)
47 genpd->stop_device(dev);
48 }
49
50 if (!ret)
51 dle->need_restore = true;
52
53 return ret;
54}
55
56/**
57 * __pm_genpd_restore_device - Restore the pre-suspend state of a device.
58 * @dle: Device list entry of the device to restore the state of.
59 * @genpd: PM domain the device belongs to.
60 */
61static void __pm_genpd_restore_device(struct dev_list_entry *dle,
62 struct generic_pm_domain *genpd)
63{
64 struct device *dev = dle->dev;
65 struct device_driver *drv = dev->driver;
66
67 if (!dle->need_restore)
68 return;
69
70 if (drv && drv->pm && drv->pm->runtime_resume) {
71 if (genpd->start_device)
72 genpd->start_device(dev);
73
74 drv->pm->runtime_resume(dev);
75
76 if (genpd->stop_device)
77 genpd->stop_device(dev);
78 }
79
80 dle->need_restore = false;
81}
82
83/**
84 * pm_genpd_poweroff - Remove power from a given PM domain.
85 * @genpd: PM domain to power down.
86 *
87 * If all of the @genpd's devices have been suspended and all of its subdomains
88 * have been powered down, run the runtime suspend callbacks provided by all of
89 * the @genpd's devices' drivers and remove power from @genpd.
90 */
91static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
92{
93 struct generic_pm_domain *parent;
94 struct dev_list_entry *dle;
95 unsigned int not_suspended;
96 int ret;
97
98 if (genpd->power_is_off)
99 return 0;
100
101 if (genpd->sd_count > 0)
102 return -EBUSY;
103
104 not_suspended = 0;
105 list_for_each_entry(dle, &genpd->dev_list, node)
106 if (dle->dev->driver && !pm_runtime_suspended(dle->dev))
107 not_suspended++;
108
109 if (not_suspended > genpd->in_progress)
110 return -EBUSY;
111
112 if (genpd->gov && genpd->gov->power_down_ok) {
113 if (!genpd->gov->power_down_ok(&genpd->domain))
114 return -EAGAIN;
115 }
116
117 list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
118 ret = __pm_genpd_save_device(dle, genpd);
119 if (ret)
120 goto err_dev;
121 }
122
123 if (genpd->power_off)
124 genpd->power_off(genpd);
125
126 genpd->power_is_off = true;
127
128 parent = genpd->parent;
129 if (parent) {
130 genpd_sd_counter_dec(parent);
131 if (parent->sd_count == 0)
132 queue_work(pm_wq, &parent->power_off_work);
133 }
134
135 return 0;
136
137 err_dev:
138 list_for_each_entry_continue(dle, &genpd->dev_list, node)
139 __pm_genpd_restore_device(dle, genpd);
140
141 return ret;
142}
143
144/**
145 * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0.
146 * @work: Work structure used for scheduling the execution of this function.
147 */
148static void genpd_power_off_work_fn(struct work_struct *work)
149{
150 struct generic_pm_domain *genpd;
151
152 genpd = container_of(work, struct generic_pm_domain, power_off_work);
153
154 if (genpd->parent)
155 mutex_lock(&genpd->parent->lock);
156 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
157 pm_genpd_poweroff(genpd);
158 mutex_unlock(&genpd->lock);
159 if (genpd->parent)
160 mutex_unlock(&genpd->parent->lock);
161}
162
163/**
164 * pm_genpd_runtime_suspend - Suspend a device belonging to I/O PM domain.
165 * @dev: Device to suspend.
166 *
167 * Carry out a runtime suspend of a device under the assumption that its
168 * pm_domain field points to the domain member of an object of type
169 * struct generic_pm_domain representing a PM domain consisting of I/O devices.
170 */
171static int pm_genpd_runtime_suspend(struct device *dev)
172{
173 struct generic_pm_domain *genpd;
174
175 dev_dbg(dev, "%s()\n", __func__);
176
177 if (IS_ERR_OR_NULL(dev->pm_domain))
178 return -EINVAL;
179
180 genpd = container_of(dev->pm_domain, struct generic_pm_domain, domain);
181
182 if (genpd->parent)
183 mutex_lock(&genpd->parent->lock);
184 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
185
186 if (genpd->stop_device) {
187 int ret = genpd->stop_device(dev);
188 if (ret)
189 goto out;
190 }
191 genpd->in_progress++;
192 pm_genpd_poweroff(genpd);
193 genpd->in_progress--;
194
195 out:
196 mutex_unlock(&genpd->lock);
197 if (genpd->parent)
198 mutex_unlock(&genpd->parent->lock);
199
200 return 0;
201}
202
203/**
204 * pm_genpd_poweron - Restore power to a given PM domain and its parents.
205 * @genpd: PM domain to power up.
206 *
207 * Restore power to @genpd and all of its parents so that it is possible to
208 * resume a device belonging to it.
209 */
210static int pm_genpd_poweron(struct generic_pm_domain *genpd)
211{
212 int ret = 0;
213
214 start:
215 if (genpd->parent)
216 mutex_lock(&genpd->parent->lock);
217 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
218
219 if (!genpd->power_is_off)
220 goto out;
221
222 if (genpd->parent && genpd->parent->power_is_off) {
223 mutex_unlock(&genpd->lock);
224 mutex_unlock(&genpd->parent->lock);
225
226 ret = pm_genpd_poweron(genpd->parent);
227 if (ret)
228 return ret;
229
230 goto start;
231 }
232
233 if (genpd->power_on) {
234 int ret = genpd->power_on(genpd);
235 if (ret)
236 goto out;
237 }
238
239 genpd->power_is_off = false;
240 if (genpd->parent)
241 genpd->parent->sd_count++;
242
243 out:
244 mutex_unlock(&genpd->lock);
245 if (genpd->parent)
246 mutex_unlock(&genpd->parent->lock);
247
248 return ret;
249}
250
251/**
252 * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
253 * @dev: Device to resume.
254 *
255 * Carry out a runtime resume of a device under the assumption that its
256 * pm_domain field points to the domain member of an object of type
257 * struct generic_pm_domain representing a PM domain consisting of I/O devices.
258 */
259static int pm_genpd_runtime_resume(struct device *dev)
260{
261 struct generic_pm_domain *genpd;
262 struct dev_list_entry *dle;
263 int ret;
264
265 dev_dbg(dev, "%s()\n", __func__);
266
267 if (IS_ERR_OR_NULL(dev->pm_domain))
268 return -EINVAL;
269
270 genpd = container_of(dev->pm_domain, struct generic_pm_domain, domain);
271
272 ret = pm_genpd_poweron(genpd);
273 if (ret)
274 return ret;
275
276 mutex_lock(&genpd->lock);
277
278 list_for_each_entry(dle, &genpd->dev_list, node) {
279 if (dle->dev == dev) {
280 __pm_genpd_restore_device(dle, genpd);
281 break;
282 }
283 }
284
285 if (genpd->start_device)
286 genpd->start_device(dev);
287
288 mutex_unlock(&genpd->lock);
289
290 return 0;
291}
292
293#else
294
295static inline void genpd_power_off_work_fn(struct work_struct *work) {}
296
297#define pm_genpd_runtime_suspend NULL
298#define pm_genpd_runtime_resume NULL
299
300#endif /* CONFIG_PM_RUNTIME */
301
302/**
303 * pm_genpd_add_device - Add a device to an I/O PM domain.
304 * @genpd: PM domain to add the device to.
305 * @dev: Device to be added.
306 */
307int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
308{
309 struct dev_list_entry *dle;
310 int ret = 0;
311
312 dev_dbg(dev, "%s()\n", __func__);
313
314 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
315 return -EINVAL;
316
317 mutex_lock(&genpd->lock);
318
319 if (genpd->power_is_off) {
320 ret = -EINVAL;
321 goto out;
322 }
323
324 list_for_each_entry(dle, &genpd->dev_list, node)
325 if (dle->dev == dev) {
326 ret = -EINVAL;
327 goto out;
328 }
329
330 dle = kzalloc(sizeof(*dle), GFP_KERNEL);
331 if (!dle) {
332 ret = -ENOMEM;
333 goto out;
334 }
335
336 dle->dev = dev;
337 dle->need_restore = false;
338 list_add_tail(&dle->node, &genpd->dev_list);
339
340 spin_lock_irq(&dev->power.lock);
341 dev->pm_domain = &genpd->domain;
342 spin_unlock_irq(&dev->power.lock);
343
344 out:
345 mutex_unlock(&genpd->lock);
346
347 return ret;
348}
349
350/**
351 * pm_genpd_remove_device - Remove a device from an I/O PM domain.
352 * @genpd: PM domain to remove the device from.
353 * @dev: Device to be removed.
354 */
355int pm_genpd_remove_device(struct generic_pm_domain *genpd,
356 struct device *dev)
357{
358 struct dev_list_entry *dle;
359 int ret = -EINVAL;
360
361 dev_dbg(dev, "%s()\n", __func__);
362
363 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
364 return -EINVAL;
365
366 mutex_lock(&genpd->lock);
367
368 list_for_each_entry(dle, &genpd->dev_list, node) {
369 if (dle->dev != dev)
370 continue;
371
372 spin_lock_irq(&dev->power.lock);
373 dev->pm_domain = NULL;
374 spin_unlock_irq(&dev->power.lock);
375
376 list_del(&dle->node);
377 kfree(dle);
378
379 ret = 0;
380 break;
381 }
382
383 mutex_unlock(&genpd->lock);
384
385 return ret;
386}
387
388/**
389 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
390 * @genpd: Master PM domain to add the subdomain to.
391 * @new_subdomain: Subdomain to be added.
392 */
393int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
394 struct generic_pm_domain *new_subdomain)
395{
396 struct generic_pm_domain *subdomain;
397 int ret = 0;
398
399 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
400 return -EINVAL;
401
402 mutex_lock(&genpd->lock);
403
404 if (genpd->power_is_off && !new_subdomain->power_is_off) {
405 ret = -EINVAL;
406 goto out;
407 }
408
409 list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
410 if (subdomain == new_subdomain) {
411 ret = -EINVAL;
412 goto out;
413 }
414 }
415
416 mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING);
417
418 list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
419 new_subdomain->parent = genpd;
420 if (!subdomain->power_is_off)
421 genpd->sd_count++;
422
423 mutex_unlock(&new_subdomain->lock);
424
425 out:
426 mutex_unlock(&genpd->lock);
427
428 return ret;
429}
430
431/**
432 * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
433 * @genpd: Master PM domain to remove the subdomain from.
434 * @target: Subdomain to be removed.
435 */
436int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
437 struct generic_pm_domain *target)
438{
439 struct generic_pm_domain *subdomain;
440 int ret = -EINVAL;
441
442 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target))
443 return -EINVAL;
444
445 mutex_lock(&genpd->lock);
446
447 list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
448 if (subdomain != target)
449 continue;
450
451 mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
452
453 list_del(&subdomain->sd_node);
454 subdomain->parent = NULL;
455 if (!subdomain->power_is_off)
456 genpd_sd_counter_dec(genpd);
457
458 mutex_unlock(&subdomain->lock);
459
460 ret = 0;
461 break;
462 }
463
464 mutex_unlock(&genpd->lock);
465
466 return ret;
467}
468
469/**
470 * pm_genpd_init - Initialize a generic I/O PM domain object.
471 * @genpd: PM domain object to initialize.
472 * @gov: PM domain governor to associate with the domain (may be NULL).
473 * @is_off: Initial value of the domain's power_is_off field.
474 */
475void pm_genpd_init(struct generic_pm_domain *genpd,
476 struct dev_power_governor *gov, bool is_off)
477{
478 if (IS_ERR_OR_NULL(genpd))
479 return;
480
481 INIT_LIST_HEAD(&genpd->sd_node);
482 genpd->parent = NULL;
483 INIT_LIST_HEAD(&genpd->dev_list);
484 INIT_LIST_HEAD(&genpd->sd_list);
485 mutex_init(&genpd->lock);
486 genpd->gov = gov;
487 INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
488 genpd->in_progress = 0;
489 genpd->sd_count = 0;
490 genpd->power_is_off = is_off;
491 genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
492 genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
493 genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
494}