aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2009-08-18 17:38:32 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2009-08-22 18:04:44 -0400
commit5e928f77a09a07f9dd595bb8a489965d69a83458 (patch)
treeef53ec90fa3214fd22e36b07c11c06b09e373d8d /include
parent8400146d0dc03590bba051399e4bb7e1cbf1c010 (diff)
PM: Introduce core framework for run-time PM of I/O devices (rev. 17)
Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things. Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Magnus Damm <damm@igel.co.jp>
Diffstat (limited to 'include')
-rw-r--r--include/linux/pm.h101
-rw-r--r--include/linux/pm_runtime.h114
2 files changed, 212 insertions, 3 deletions
diff --git a/include/linux/pm.h b/include/linux/pm.h
index b3f74764a586..2b6e20df0e52 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -22,6 +22,10 @@
22#define _LINUX_PM_H 22#define _LINUX_PM_H
23 23
24#include <linux/list.h> 24#include <linux/list.h>
25#include <linux/workqueue.h>
26#include <linux/spinlock.h>
27#include <linux/wait.h>
28#include <linux/timer.h>
25 29
26/* 30/*
27 * Callbacks for platform drivers to implement. 31 * Callbacks for platform drivers to implement.
@@ -165,6 +169,28 @@ typedef struct pm_message {
165 * It is allowed to unregister devices while the above callbacks are being 169 * It is allowed to unregister devices while the above callbacks are being
166 * executed. However, it is not allowed to unregister a device from within any 170 * executed. However, it is not allowed to unregister a device from within any
167 * of its own callbacks. 171 * of its own callbacks.
172 *
173 * There also are the following callbacks related to run-time power management
174 * of devices:
175 *
176 * @runtime_suspend: Prepare the device for a condition in which it won't be
177 * able to communicate with the CPU(s) and RAM due to power management.
178 * This need not mean that the device should be put into a low power state.
179 * For example, if the device is behind a link which is about to be turned
180 * off, the device may remain at full power. If the device does go to low
181 * power and if device_may_wakeup(dev) is true, remote wake-up (i.e., a
182 * hardware mechanism allowing the device to request a change of its power
183 * state, such as PCI PME) should be enabled for it.
184 *
185 * @runtime_resume: Put the device into the fully active state in response to a
186 * wake-up event generated by hardware or at the request of software. If
187 * necessary, put the device into the full power state and restore its
188 * registers, so that it is fully operational.
189 *
190 * @runtime_idle: Device appears to be inactive and it might be put into a low
191 * power state if all of the necessary conditions are satisfied. Check
192 * these conditions and handle the device as appropriate, possibly queueing
193 * a suspend request for it. The return value is ignored by the PM core.
168 */ 194 */
169 195
170struct dev_pm_ops { 196struct dev_pm_ops {
@@ -182,6 +208,9 @@ struct dev_pm_ops {
182 int (*thaw_noirq)(struct device *dev); 208 int (*thaw_noirq)(struct device *dev);
183 int (*poweroff_noirq)(struct device *dev); 209 int (*poweroff_noirq)(struct device *dev);
184 int (*restore_noirq)(struct device *dev); 210 int (*restore_noirq)(struct device *dev);
211 int (*runtime_suspend)(struct device *dev);
212 int (*runtime_resume)(struct device *dev);
213 int (*runtime_idle)(struct device *dev);
185}; 214};
186 215
187/** 216/**
@@ -315,14 +344,80 @@ enum dpm_state {
315 DPM_OFF_IRQ, 344 DPM_OFF_IRQ,
316}; 345};
317 346
347/**
348 * Device run-time power management status.
349 *
350 * These status labels are used internally by the PM core to indicate the
351 * current status of a device with respect to the PM core operations. They do
352 * not reflect the actual power state of the device or its status as seen by the
353 * driver.
354 *
355 * RPM_ACTIVE Device is fully operational. Indicates that the device
356 * bus type's ->runtime_resume() callback has completed
357 * successfully.
358 *
359 * RPM_SUSPENDED Device bus type's ->runtime_suspend() callback has
360 * completed successfully. The device is regarded as
361 * suspended.
362 *
363 * RPM_RESUMING Device bus type's ->runtime_resume() callback is being
364 * executed.
365 *
366 * RPM_SUSPENDING Device bus type's ->runtime_suspend() callback is being
367 * executed.
368 */
369
370enum rpm_status {
371 RPM_ACTIVE = 0,
372 RPM_RESUMING,
373 RPM_SUSPENDED,
374 RPM_SUSPENDING,
375};
376
377/**
378 * Device run-time power management request types.
379 *
380 * RPM_REQ_NONE Do nothing.
381 *
382 * RPM_REQ_IDLE Run the device bus type's ->runtime_idle() callback
383 *
384 * RPM_REQ_SUSPEND Run the device bus type's ->runtime_suspend() callback
385 *
386 * RPM_REQ_RESUME Run the device bus type's ->runtime_resume() callback
387 */
388
389enum rpm_request {
390 RPM_REQ_NONE = 0,
391 RPM_REQ_IDLE,
392 RPM_REQ_SUSPEND,
393 RPM_REQ_RESUME,
394};
395
318struct dev_pm_info { 396struct dev_pm_info {
319 pm_message_t power_state; 397 pm_message_t power_state;
320 unsigned can_wakeup:1; 398 unsigned int can_wakeup:1;
321 unsigned should_wakeup:1; 399 unsigned int should_wakeup:1;
322 enum dpm_state status; /* Owned by the PM core */ 400 enum dpm_state status; /* Owned by the PM core */
323#ifdef CONFIG_PM_SLEEP 401#ifdef CONFIG_PM_SLEEP
324 struct list_head entry; 402 struct list_head entry;
325#endif 403#endif
404#ifdef CONFIG_PM_RUNTIME
405 struct timer_list suspend_timer;
406 unsigned long timer_expires;
407 struct work_struct work;
408 wait_queue_head_t wait_queue;
409 spinlock_t lock;
410 atomic_t usage_count;
411 atomic_t child_count;
412 unsigned int disable_depth:3;
413 unsigned int ignore_children:1;
414 unsigned int idle_notification:1;
415 unsigned int request_pending:1;
416 unsigned int deferred_resume:1;
417 enum rpm_request request;
418 enum rpm_status runtime_status;
419 int runtime_error;
420#endif
326}; 421};
327 422
328/* 423/*
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
new file mode 100644
index 000000000000..44087044910f
--- /dev/null
+++ b/include/linux/pm_runtime.h
@@ -0,0 +1,114 @@
1/*
2 * pm_runtime.h - Device run-time power management helper functions.
3 *
4 * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>
5 *
6 * This file is released under the GPLv2.
7 */
8
9#ifndef _LINUX_PM_RUNTIME_H
10#define _LINUX_PM_RUNTIME_H
11
12#include <linux/device.h>
13#include <linux/pm.h>
14
15#ifdef CONFIG_PM_RUNTIME
16
17extern struct workqueue_struct *pm_wq;
18
19extern int pm_runtime_idle(struct device *dev);
20extern int pm_runtime_suspend(struct device *dev);
21extern int pm_runtime_resume(struct device *dev);
22extern int pm_request_idle(struct device *dev);
23extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
24extern int pm_request_resume(struct device *dev);
25extern int __pm_runtime_get(struct device *dev, bool sync);
26extern int __pm_runtime_put(struct device *dev, bool sync);
27extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
28extern int pm_runtime_barrier(struct device *dev);
29extern void pm_runtime_enable(struct device *dev);
30extern void __pm_runtime_disable(struct device *dev, bool check_resume);
31
32static inline bool pm_children_suspended(struct device *dev)
33{
34 return dev->power.ignore_children
35 || !atomic_read(&dev->power.child_count);
36}
37
38static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
39{
40 dev->power.ignore_children = enable;
41}
42
43static inline void pm_runtime_get_noresume(struct device *dev)
44{
45 atomic_inc(&dev->power.usage_count);
46}
47
48static inline void pm_runtime_put_noidle(struct device *dev)
49{
50 atomic_add_unless(&dev->power.usage_count, -1, 0);
51}
52
53#else /* !CONFIG_PM_RUNTIME */
54
55static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; }
56static inline int pm_runtime_suspend(struct device *dev) { return -ENOSYS; }
57static inline int pm_runtime_resume(struct device *dev) { return 0; }
58static inline int pm_request_idle(struct device *dev) { return -ENOSYS; }
59static inline int pm_schedule_suspend(struct device *dev, unsigned int delay)
60{
61 return -ENOSYS;
62}
63static inline int pm_request_resume(struct device *dev) { return 0; }
64static inline int __pm_runtime_get(struct device *dev, bool sync) { return 1; }
65static inline int __pm_runtime_put(struct device *dev, bool sync) { return 0; }
66static inline int __pm_runtime_set_status(struct device *dev,
67 unsigned int status) { return 0; }
68static inline int pm_runtime_barrier(struct device *dev) { return 0; }
69static inline void pm_runtime_enable(struct device *dev) {}
70static inline void __pm_runtime_disable(struct device *dev, bool c) {}
71
72static inline bool pm_children_suspended(struct device *dev) { return false; }
73static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}
74static inline void pm_runtime_get_noresume(struct device *dev) {}
75static inline void pm_runtime_put_noidle(struct device *dev) {}
76
77#endif /* !CONFIG_PM_RUNTIME */
78
79static inline int pm_runtime_get(struct device *dev)
80{
81 return __pm_runtime_get(dev, false);
82}
83
84static inline int pm_runtime_get_sync(struct device *dev)
85{
86 return __pm_runtime_get(dev, true);
87}
88
89static inline int pm_runtime_put(struct device *dev)
90{
91 return __pm_runtime_put(dev, false);
92}
93
94static inline int pm_runtime_put_sync(struct device *dev)
95{
96 return __pm_runtime_put(dev, true);
97}
98
99static inline int pm_runtime_set_active(struct device *dev)
100{
101 return __pm_runtime_set_status(dev, RPM_ACTIVE);
102}
103
104static inline void pm_runtime_set_suspended(struct device *dev)
105{
106 __pm_runtime_set_status(dev, RPM_SUSPENDED);
107}
108
109static inline void pm_runtime_disable(struct device *dev)
110{
111 __pm_runtime_disable(dev, true);
112}
113
114#endif