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