domain.c revision 5248051b9afb6684cd817b2fbdaefa5063761dab
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
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}
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
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
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
237	genpd = dev_to_genpd(dev);
238	if (IS_ERR(genpd))
239		return -EINVAL;
240
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
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
278	genpd = dev_to_genpd(dev);
279	if (IS_ERR(genpd))
280		return -EINVAL;
281
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}
505