diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-01 16:12:59 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-02 08:29:55 -0400 |
commit | e5291928839877f8e73c2643ee1d3fe0bcdcaf5c (patch) | |
tree | df733cad71610a2f5ce283dcca5f2ad1d83bdf1f | |
parent | f721889ff65afa6243c463832c74dee3bed418d5 (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.txt | 32 | ||||
-rw-r--r-- | drivers/base/power/generic_ops.c | 98 | ||||
-rw-r--r-- | include/linux/pm.h | 6 |
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 | |||
632 | These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), | 658 | These 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(), |
634 | or ->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 | ||
662 | pointers in the subsystem-level dev_pm_ops structures. | ||
635 | 663 | ||
636 | If a subsystem wishes to use all of them at the same time, it can simply assign | 664 | If a subsystem wishes to use all of them at the same time, it can simply assign |
637 | the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its | 665 | the 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 | */ |
102 | static int __pm_generic_call(struct device *dev, int event) | 103 | static 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 | */ | ||
136 | int pm_generic_suspend_noirq(struct device *dev) | ||
137 | { | ||
138 | return __pm_generic_call(dev, PM_EVENT_SUSPEND, true); | ||
139 | } | ||
140 | EXPORT_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 | */ |
135 | int pm_generic_suspend(struct device *dev) | 146 | int 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 | } |
139 | EXPORT_SYMBOL_GPL(pm_generic_suspend); | 150 | EXPORT_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 | */ | ||
156 | int pm_generic_freeze_noirq(struct device *dev) | ||
157 | { | ||
158 | return __pm_generic_call(dev, PM_EVENT_FREEZE, true); | ||
159 | } | ||
160 | EXPORT_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 | */ |
145 | int pm_generic_freeze(struct device *dev) | 166 | int 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 | } |
149 | EXPORT_SYMBOL_GPL(pm_generic_freeze); | 170 | EXPORT_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 | */ | ||
176 | int pm_generic_poweroff_noirq(struct device *dev) | ||
177 | { | ||
178 | return __pm_generic_call(dev, PM_EVENT_HIBERNATE, true); | ||
179 | } | ||
180 | EXPORT_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 | */ |
155 | int pm_generic_poweroff(struct device *dev) | 186 | int 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 | } |
159 | EXPORT_SYMBOL_GPL(pm_generic_poweroff); | 190 | EXPORT_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 | */ | ||
196 | int pm_generic_thaw_noirq(struct device *dev) | ||
197 | { | ||
198 | return __pm_generic_call(dev, PM_EVENT_THAW, true); | ||
199 | } | ||
200 | EXPORT_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 | */ |
165 | int pm_generic_thaw(struct device *dev) | 206 | int 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 | } |
169 | EXPORT_SYMBOL_GPL(pm_generic_thaw); | 210 | EXPORT_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 | */ |
180 | static int __pm_generic_resume(struct device *dev, int event) | 222 | static 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 | */ | ||
260 | int pm_generic_resume_noirq(struct device *dev) | ||
261 | { | ||
262 | return __pm_generic_resume(dev, PM_EVENT_RESUME, true); | ||
263 | } | ||
264 | EXPORT_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 | */ |
218 | int pm_generic_resume(struct device *dev) | 270 | int 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 | } |
222 | EXPORT_SYMBOL_GPL(pm_generic_resume); | 274 | EXPORT_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 | */ | ||
280 | int pm_generic_restore_noirq(struct device *dev) | ||
281 | { | ||
282 | return __pm_generic_resume(dev, PM_EVENT_RESTORE, true); | ||
283 | } | ||
284 | EXPORT_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 | */ |
228 | int pm_generic_restore(struct device *dev) | 290 | int 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 | } |
232 | EXPORT_SYMBOL_GPL(pm_generic_restore); | 294 | EXPORT_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); | |||
553 | extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); | 553 | extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); |
554 | 554 | ||
555 | extern int pm_generic_prepare(struct device *dev); | 555 | extern int pm_generic_prepare(struct device *dev); |
556 | extern int pm_generic_suspend_noirq(struct device *dev); | ||
556 | extern int pm_generic_suspend(struct device *dev); | 557 | extern int pm_generic_suspend(struct device *dev); |
558 | extern int pm_generic_resume_noirq(struct device *dev); | ||
557 | extern int pm_generic_resume(struct device *dev); | 559 | extern int pm_generic_resume(struct device *dev); |
560 | extern int pm_generic_freeze_noirq(struct device *dev); | ||
558 | extern int pm_generic_freeze(struct device *dev); | 561 | extern int pm_generic_freeze(struct device *dev); |
562 | extern int pm_generic_thaw_noirq(struct device *dev); | ||
559 | extern int pm_generic_thaw(struct device *dev); | 563 | extern int pm_generic_thaw(struct device *dev); |
564 | extern int pm_generic_restore_noirq(struct device *dev); | ||
560 | extern int pm_generic_restore(struct device *dev); | 565 | extern int pm_generic_restore(struct device *dev); |
566 | extern int pm_generic_poweroff_noirq(struct device *dev); | ||
561 | extern int pm_generic_poweroff(struct device *dev); | 567 | extern int pm_generic_poweroff(struct device *dev); |
562 | extern void pm_generic_complete(struct device *dev); | 568 | extern void pm_generic_complete(struct device *dev); |
563 | 569 | ||