domain.c revision f721889ff65afa6243c463832c74dee3bed418d5
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}
495