aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-07-01 16:12:59 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-07-02 08:29:55 -0400
commite5291928839877f8e73c2643ee1d3fe0bcdcaf5c (patch)
treedf733cad71610a2f5ce283dcca5f2ad1d83bdf1f
parentf721889ff65afa6243c463832c74dee3bed418d5 (diff)
PM: Introduce generic "noirq" callback routines for subsystems (v2)
Introduce generic "noirq" power management callback routines for subsystems in addition to the "regular" generic PM callback routines. The new routines will be used, among other things, for implementing system-wide PM transitions support for generic PM domains. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--Documentation/power/runtime_pm.txt32
-rw-r--r--drivers/base/power/generic_ops.c98
-rw-r--r--include/linux/pm.h6
3 files changed, 119 insertions, 17 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index b24875b1ced5..4b011b171be4 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -606,32 +606,60 @@ driver/base/power/generic_ops.c:
606 callback provided by its driver and return its result, or return 0 if not 606 callback provided by its driver and return its result, or return 0 if not
607 defined 607 defined
608 608
609 int pm_generic_suspend_noirq(struct device *dev);
610 - if pm_runtime_suspended(dev) returns "false", invoke the ->suspend_noirq()
611 callback provided by the device's driver and return its result, or return
612 0 if not defined
613
609 int pm_generic_resume(struct device *dev); 614 int pm_generic_resume(struct device *dev);
610 - invoke the ->resume() callback provided by the driver of this device and, 615 - invoke the ->resume() callback provided by the driver of this device and,
611 if successful, change the device's runtime PM status to 'active' 616 if successful, change the device's runtime PM status to 'active'
612 617
618 int pm_generic_resume_noirq(struct device *dev);
619 - invoke the ->resume_noirq() callback provided by the driver of this device
620
613 int pm_generic_freeze(struct device *dev); 621 int pm_generic_freeze(struct device *dev);
614 - if the device has not been suspended at run time, invoke the ->freeze() 622 - if the device has not been suspended at run time, invoke the ->freeze()
615 callback provided by its driver and return its result, or return 0 if not 623 callback provided by its driver and return its result, or return 0 if not
616 defined 624 defined
617 625
626 int pm_generic_freeze_noirq(struct device *dev);
627 - if pm_runtime_suspended(dev) returns "false", invoke the ->freeze_noirq()
628 callback provided by the device's driver and return its result, or return
629 0 if not defined
630
618 int pm_generic_thaw(struct device *dev); 631 int pm_generic_thaw(struct device *dev);
619 - if the device has not been suspended at run time, invoke the ->thaw() 632 - if the device has not been suspended at run time, invoke the ->thaw()
620 callback provided by its driver and return its result, or return 0 if not 633 callback provided by its driver and return its result, or return 0 if not
621 defined 634 defined
622 635
636 int pm_generic_thaw_noirq(struct device *dev);
637 - if pm_runtime_suspended(dev) returns "false", invoke the ->thaw_noirq()
638 callback provided by the device's driver and return its result, or return
639 0 if not defined
640
623 int pm_generic_poweroff(struct device *dev); 641 int pm_generic_poweroff(struct device *dev);
624 - if the device has not been suspended at run time, invoke the ->poweroff() 642 - if the device has not been suspended at run time, invoke the ->poweroff()
625 callback provided by its driver and return its result, or return 0 if not 643 callback provided by its driver and return its result, or return 0 if not
626 defined 644 defined
627 645
646 int pm_generic_poweroff_noirq(struct device *dev);
647 - if pm_runtime_suspended(dev) returns "false", run the ->poweroff_noirq()
648 callback provided by the device's driver and return its result, or return
649 0 if not defined
650
628 int pm_generic_restore(struct device *dev); 651 int pm_generic_restore(struct device *dev);
629 - invoke the ->restore() callback provided by the driver of this device and, 652 - invoke the ->restore() callback provided by the driver of this device and,
630 if successful, change the device's runtime PM status to 'active' 653 if successful, change the device's runtime PM status to 'active'
631 654
655 int pm_generic_restore_noirq(struct device *dev);
656 - invoke the ->restore_noirq() callback provided by the device's driver
657
632These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), 658These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(),
633->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), 659->runtime_resume(), ->suspend(), ->suspend_noirq(), ->resume(),
634or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. 660->resume_noirq(), ->freeze(), ->freeze_noirq(), ->thaw(), ->thaw_noirq(),
661->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() callback
662pointers in the subsystem-level dev_pm_ops structures.
635 663
636If a subsystem wishes to use all of them at the same time, it can simply assign 664If a subsystem wishes to use all of them at the same time, it can simply assign
637the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its 665the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index cb3bb368681c..9508df71274b 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -94,12 +94,13 @@ int pm_generic_prepare(struct device *dev)
94 * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. 94 * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
95 * @dev: Device to handle. 95 * @dev: Device to handle.
96 * @event: PM transition of the system under way. 96 * @event: PM transition of the system under way.
97 * @bool: Whether or not this is the "noirq" stage.
97 * 98 *
98 * If the device has not been suspended at run time, execute the 99 * If the device has not been suspended at run time, execute the
99 * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and 100 * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and
100 * return its error code. Otherwise, return zero. 101 * return its error code. Otherwise, return zero.
101 */ 102 */
102static int __pm_generic_call(struct device *dev, int event) 103static int __pm_generic_call(struct device *dev, int event, bool noirq)
103{ 104{
104 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 105 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
105 int (*callback)(struct device *); 106 int (*callback)(struct device *);
@@ -109,16 +110,16 @@ static int __pm_generic_call(struct device *dev, int event)
109 110
110 switch (event) { 111 switch (event) {
111 case PM_EVENT_SUSPEND: 112 case PM_EVENT_SUSPEND:
112 callback = pm->suspend; 113 callback = noirq ? pm->suspend_noirq : pm->suspend;
113 break; 114 break;
114 case PM_EVENT_FREEZE: 115 case PM_EVENT_FREEZE:
115 callback = pm->freeze; 116 callback = noirq ? pm->freeze_noirq : pm->freeze;
116 break; 117 break;
117 case PM_EVENT_HIBERNATE: 118 case PM_EVENT_HIBERNATE:
118 callback = pm->poweroff; 119 callback = noirq ? pm->poweroff_noirq : pm->poweroff;
119 break; 120 break;
120 case PM_EVENT_THAW: 121 case PM_EVENT_THAW:
121 callback = pm->thaw; 122 callback = noirq ? pm->thaw_noirq : pm->thaw;
122 break; 123 break;
123 default: 124 default:
124 callback = NULL; 125 callback = NULL;
@@ -129,42 +130,82 @@ static int __pm_generic_call(struct device *dev, int event)
129} 130}
130 131
131/** 132/**
133 * pm_generic_suspend_noirq - Generic suspend_noirq callback for subsystems.
134 * @dev: Device to suspend.
135 */
136int pm_generic_suspend_noirq(struct device *dev)
137{
138 return __pm_generic_call(dev, PM_EVENT_SUSPEND, true);
139}
140EXPORT_SYMBOL_GPL(pm_generic_suspend_noirq);
141
142/**
132 * pm_generic_suspend - Generic suspend callback for subsystems. 143 * pm_generic_suspend - Generic suspend callback for subsystems.
133 * @dev: Device to suspend. 144 * @dev: Device to suspend.
134 */ 145 */
135int pm_generic_suspend(struct device *dev) 146int pm_generic_suspend(struct device *dev)
136{ 147{
137 return __pm_generic_call(dev, PM_EVENT_SUSPEND); 148 return __pm_generic_call(dev, PM_EVENT_SUSPEND, false);
138} 149}
139EXPORT_SYMBOL_GPL(pm_generic_suspend); 150EXPORT_SYMBOL_GPL(pm_generic_suspend);
140 151
141/** 152/**
153 * pm_generic_freeze_noirq - Generic freeze_noirq callback for subsystems.
154 * @dev: Device to freeze.
155 */
156int pm_generic_freeze_noirq(struct device *dev)
157{
158 return __pm_generic_call(dev, PM_EVENT_FREEZE, true);
159}
160EXPORT_SYMBOL_GPL(pm_generic_freeze_noirq);
161
162/**
142 * pm_generic_freeze - Generic freeze callback for subsystems. 163 * pm_generic_freeze - Generic freeze callback for subsystems.
143 * @dev: Device to freeze. 164 * @dev: Device to freeze.
144 */ 165 */
145int pm_generic_freeze(struct device *dev) 166int pm_generic_freeze(struct device *dev)
146{ 167{
147 return __pm_generic_call(dev, PM_EVENT_FREEZE); 168 return __pm_generic_call(dev, PM_EVENT_FREEZE, false);
148} 169}
149EXPORT_SYMBOL_GPL(pm_generic_freeze); 170EXPORT_SYMBOL_GPL(pm_generic_freeze);
150 171
151/** 172/**
173 * pm_generic_poweroff_noirq - Generic poweroff_noirq callback for subsystems.
174 * @dev: Device to handle.
175 */
176int pm_generic_poweroff_noirq(struct device *dev)
177{
178 return __pm_generic_call(dev, PM_EVENT_HIBERNATE, true);
179}
180EXPORT_SYMBOL_GPL(pm_generic_poweroff_noirq);
181
182/**
152 * pm_generic_poweroff - Generic poweroff callback for subsystems. 183 * pm_generic_poweroff - Generic poweroff callback for subsystems.
153 * @dev: Device to handle. 184 * @dev: Device to handle.
154 */ 185 */
155int pm_generic_poweroff(struct device *dev) 186int pm_generic_poweroff(struct device *dev)
156{ 187{
157 return __pm_generic_call(dev, PM_EVENT_HIBERNATE); 188 return __pm_generic_call(dev, PM_EVENT_HIBERNATE, false);
158} 189}
159EXPORT_SYMBOL_GPL(pm_generic_poweroff); 190EXPORT_SYMBOL_GPL(pm_generic_poweroff);
160 191
161/** 192/**
193 * pm_generic_thaw_noirq - Generic thaw_noirq callback for subsystems.
194 * @dev: Device to thaw.
195 */
196int pm_generic_thaw_noirq(struct device *dev)
197{
198 return __pm_generic_call(dev, PM_EVENT_THAW, true);
199}
200EXPORT_SYMBOL_GPL(pm_generic_thaw_noirq);
201
202/**
162 * pm_generic_thaw - Generic thaw callback for subsystems. 203 * pm_generic_thaw - Generic thaw callback for subsystems.
163 * @dev: Device to thaw. 204 * @dev: Device to thaw.
164 */ 205 */
165int pm_generic_thaw(struct device *dev) 206int pm_generic_thaw(struct device *dev)
166{ 207{
167 return __pm_generic_call(dev, PM_EVENT_THAW); 208 return __pm_generic_call(dev, PM_EVENT_THAW, false);
168} 209}
169EXPORT_SYMBOL_GPL(pm_generic_thaw); 210EXPORT_SYMBOL_GPL(pm_generic_thaw);
170 211
@@ -172,12 +213,13 @@ EXPORT_SYMBOL_GPL(pm_generic_thaw);
172 * __pm_generic_resume - Generic resume/restore callback for subsystems. 213 * __pm_generic_resume - Generic resume/restore callback for subsystems.
173 * @dev: Device to handle. 214 * @dev: Device to handle.
174 * @event: PM transition of the system under way. 215 * @event: PM transition of the system under way.
216 * @bool: Whether or not this is the "noirq" stage.
175 * 217 *
176 * Execute the resume/resotre callback provided by the @dev's driver, if 218 * Execute the resume/resotre callback provided by the @dev's driver, if
177 * defined. If it returns 0, change the device's runtime PM status to 'active'. 219 * defined. If it returns 0, change the device's runtime PM status to 'active'.
178 * Return the callback's error code. 220 * Return the callback's error code.
179 */ 221 */
180static int __pm_generic_resume(struct device *dev, int event) 222static int __pm_generic_resume(struct device *dev, int event, bool noirq)
181{ 223{
182 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 224 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
183 int (*callback)(struct device *); 225 int (*callback)(struct device *);
@@ -188,10 +230,10 @@ static int __pm_generic_resume(struct device *dev, int event)
188 230
189 switch (event) { 231 switch (event) {
190 case PM_EVENT_RESUME: 232 case PM_EVENT_RESUME:
191 callback = pm->resume; 233 callback = noirq ? pm->resume_noirq : pm->resume;
192 break; 234 break;
193 case PM_EVENT_RESTORE: 235 case PM_EVENT_RESTORE:
194 callback = pm->restore; 236 callback = noirq ? pm->restore_noirq : pm->restore;
195 break; 237 break;
196 default: 238 default:
197 callback = NULL; 239 callback = NULL;
@@ -202,7 +244,7 @@ static int __pm_generic_resume(struct device *dev, int event)
202 return 0; 244 return 0;
203 245
204 ret = callback(dev); 246 ret = callback(dev);
205 if (!ret && pm_runtime_enabled(dev)) { 247 if (!ret && !noirq && pm_runtime_enabled(dev)) {
206 pm_runtime_disable(dev); 248 pm_runtime_disable(dev);
207 pm_runtime_set_active(dev); 249 pm_runtime_set_active(dev);
208 pm_runtime_enable(dev); 250 pm_runtime_enable(dev);
@@ -212,22 +254,42 @@ static int __pm_generic_resume(struct device *dev, int event)
212} 254}
213 255
214/** 256/**
257 * pm_generic_resume_noirq - Generic resume_noirq callback for subsystems.
258 * @dev: Device to resume.
259 */
260int pm_generic_resume_noirq(struct device *dev)
261{
262 return __pm_generic_resume(dev, PM_EVENT_RESUME, true);
263}
264EXPORT_SYMBOL_GPL(pm_generic_resume_noirq);
265
266/**
215 * pm_generic_resume - Generic resume callback for subsystems. 267 * pm_generic_resume - Generic resume callback for subsystems.
216 * @dev: Device to resume. 268 * @dev: Device to resume.
217 */ 269 */
218int pm_generic_resume(struct device *dev) 270int pm_generic_resume(struct device *dev)
219{ 271{
220 return __pm_generic_resume(dev, PM_EVENT_RESUME); 272 return __pm_generic_resume(dev, PM_EVENT_RESUME, false);
221} 273}
222EXPORT_SYMBOL_GPL(pm_generic_resume); 274EXPORT_SYMBOL_GPL(pm_generic_resume);
223 275
224/** 276/**
277 * pm_generic_restore_noirq - Generic restore_noirq callback for subsystems.
278 * @dev: Device to restore.
279 */
280int pm_generic_restore_noirq(struct device *dev)
281{
282 return __pm_generic_resume(dev, PM_EVENT_RESTORE, true);
283}
284EXPORT_SYMBOL_GPL(pm_generic_restore_noirq);
285
286/**
225 * pm_generic_restore - Generic restore callback for subsystems. 287 * pm_generic_restore - Generic restore callback for subsystems.
226 * @dev: Device to restore. 288 * @dev: Device to restore.
227 */ 289 */
228int pm_generic_restore(struct device *dev) 290int pm_generic_restore(struct device *dev)
229{ 291{
230 return __pm_generic_resume(dev, PM_EVENT_RESTORE); 292 return __pm_generic_resume(dev, PM_EVENT_RESTORE, false);
231} 293}
232EXPORT_SYMBOL_GPL(pm_generic_restore); 294EXPORT_SYMBOL_GPL(pm_generic_restore);
233 295
@@ -256,11 +318,17 @@ struct dev_pm_ops generic_subsys_pm_ops = {
256#ifdef CONFIG_PM_SLEEP 318#ifdef CONFIG_PM_SLEEP
257 .prepare = pm_generic_prepare, 319 .prepare = pm_generic_prepare,
258 .suspend = pm_generic_suspend, 320 .suspend = pm_generic_suspend,
321 .suspend_noirq = pm_generic_suspend_noirq,
259 .resume = pm_generic_resume, 322 .resume = pm_generic_resume,
323 .resume_noirq = pm_generic_resume_noirq,
260 .freeze = pm_generic_freeze, 324 .freeze = pm_generic_freeze,
325 .freeze_noirq = pm_generic_freeze_noirq,
261 .thaw = pm_generic_thaw, 326 .thaw = pm_generic_thaw,
327 .thaw_noirq = pm_generic_thaw_noirq,
262 .poweroff = pm_generic_poweroff, 328 .poweroff = pm_generic_poweroff,
329 .poweroff_noirq = pm_generic_poweroff_noirq,
263 .restore = pm_generic_restore, 330 .restore = pm_generic_restore,
331 .restore_noirq = pm_generic_restore_noirq,
264 .complete = pm_generic_complete, 332 .complete = pm_generic_complete,
265#endif 333#endif
266#ifdef CONFIG_PM_RUNTIME 334#ifdef CONFIG_PM_RUNTIME
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 7e8f0763d1ec..f7c84c9abd30 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -553,11 +553,17 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
553extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); 553extern int device_pm_wait_for_dev(struct device *sub, struct device *dev);
554 554
555extern int pm_generic_prepare(struct device *dev); 555extern int pm_generic_prepare(struct device *dev);
556extern int pm_generic_suspend_noirq(struct device *dev);
556extern int pm_generic_suspend(struct device *dev); 557extern int pm_generic_suspend(struct device *dev);
558extern int pm_generic_resume_noirq(struct device *dev);
557extern int pm_generic_resume(struct device *dev); 559extern int pm_generic_resume(struct device *dev);
560extern int pm_generic_freeze_noirq(struct device *dev);
558extern int pm_generic_freeze(struct device *dev); 561extern int pm_generic_freeze(struct device *dev);
562extern int pm_generic_thaw_noirq(struct device *dev);
559extern int pm_generic_thaw(struct device *dev); 563extern int pm_generic_thaw(struct device *dev);
564extern int pm_generic_restore_noirq(struct device *dev);
560extern int pm_generic_restore(struct device *dev); 565extern int pm_generic_restore(struct device *dev);
566extern int pm_generic_poweroff_noirq(struct device *dev);
561extern int pm_generic_poweroff(struct device *dev); 567extern int pm_generic_poweroff(struct device *dev);
562extern void pm_generic_complete(struct device *dev); 568extern void pm_generic_complete(struct device *dev);
563 569