diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-12-17 18:34:01 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-12-21 16:00:56 -0500 |
commit | 9cf519d1c15fa05a538c2b3963c5f3903daf765a (patch) | |
tree | 44500e7eba98e682663ab253e4ba7edff7e9f875 /drivers/base | |
parent | b00f4dc5ff022cb9cbaffd376d9454d7fa1e496f (diff) |
PM / Sleep: Make pm_op() and pm_noirq_op() return callback pointers
Make the pm_op() and pm_noirq_op() functions return pointers to
appropriate callbacks instead of executing those callbacks and
returning their results.
This change is required for a subsequent modification that will
execute the corresponding driver callback if the subsystem
callback returned by either pm_op(), or pm_noirq_op() is NULL.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/main.c | 197 |
1 files changed, 95 insertions, 102 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index b570189d4f2d..b5cef7e7de23 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include "../base.h" | 32 | #include "../base.h" |
33 | #include "power.h" | 33 | #include "power.h" |
34 | 34 | ||
35 | typedef int (*pm_callback_t)(struct device *); | ||
36 | |||
35 | /* | 37 | /* |
36 | * The entries in the dpm_list list are in a depth first order, simply | 38 | * The entries in the dpm_list list are in a depth first order, simply |
37 | * because children are guaranteed to be discovered after parents, and | 39 | * because children are guaranteed to be discovered after parents, and |
@@ -211,113 +213,70 @@ static void dpm_wait_for_children(struct device *dev, bool async) | |||
211 | device_for_each_child(dev, &async, dpm_wait_fn); | 213 | device_for_each_child(dev, &async, dpm_wait_fn); |
212 | } | 214 | } |
213 | 215 | ||
214 | static int dpm_run_callback(struct device *dev, int (*cb)(struct device *)) | ||
215 | { | ||
216 | ktime_t calltime; | ||
217 | int error; | ||
218 | |||
219 | if (!cb) | ||
220 | return 0; | ||
221 | |||
222 | calltime = initcall_debug_start(dev); | ||
223 | |||
224 | error = cb(dev); | ||
225 | suspend_report_result(cb, error); | ||
226 | |||
227 | initcall_debug_report(dev, calltime, error); | ||
228 | |||
229 | return error; | ||
230 | } | ||
231 | |||
232 | /** | 216 | /** |
233 | * pm_op - Execute the PM operation appropriate for given PM event. | 217 | * pm_op - Return the PM operation appropriate for given PM event. |
234 | * @dev: Device to handle. | ||
235 | * @ops: PM operations to choose from. | 218 | * @ops: PM operations to choose from. |
236 | * @state: PM transition of the system being carried out. | 219 | * @state: PM transition of the system being carried out. |
237 | */ | 220 | */ |
238 | static int pm_op(struct device *dev, | 221 | static pm_callback_t pm_op(const struct dev_pm_ops *ops, pm_message_t state) |
239 | const struct dev_pm_ops *ops, | ||
240 | pm_message_t state) | ||
241 | { | 222 | { |
242 | int error = 0; | ||
243 | |||
244 | switch (state.event) { | 223 | switch (state.event) { |
245 | #ifdef CONFIG_SUSPEND | 224 | #ifdef CONFIG_SUSPEND |
246 | case PM_EVENT_SUSPEND: | 225 | case PM_EVENT_SUSPEND: |
247 | error = dpm_run_callback(dev, ops->suspend); | 226 | return ops->suspend; |
248 | break; | ||
249 | case PM_EVENT_RESUME: | 227 | case PM_EVENT_RESUME: |
250 | error = dpm_run_callback(dev, ops->resume); | 228 | return ops->resume; |
251 | break; | ||
252 | #endif /* CONFIG_SUSPEND */ | 229 | #endif /* CONFIG_SUSPEND */ |
253 | #ifdef CONFIG_HIBERNATE_CALLBACKS | 230 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
254 | case PM_EVENT_FREEZE: | 231 | case PM_EVENT_FREEZE: |
255 | case PM_EVENT_QUIESCE: | 232 | case PM_EVENT_QUIESCE: |
256 | error = dpm_run_callback(dev, ops->freeze); | 233 | return ops->freeze; |
257 | break; | ||
258 | case PM_EVENT_HIBERNATE: | 234 | case PM_EVENT_HIBERNATE: |
259 | error = dpm_run_callback(dev, ops->poweroff); | 235 | return ops->poweroff; |
260 | break; | ||
261 | case PM_EVENT_THAW: | 236 | case PM_EVENT_THAW: |
262 | case PM_EVENT_RECOVER: | 237 | case PM_EVENT_RECOVER: |
263 | error = dpm_run_callback(dev, ops->thaw); | 238 | return ops->thaw; |
264 | break; | 239 | break; |
265 | case PM_EVENT_RESTORE: | 240 | case PM_EVENT_RESTORE: |
266 | error = dpm_run_callback(dev, ops->restore); | 241 | return ops->restore; |
267 | break; | ||
268 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | 242 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
269 | default: | ||
270 | error = -EINVAL; | ||
271 | } | 243 | } |
272 | 244 | ||
273 | return error; | 245 | return NULL; |
274 | } | 246 | } |
275 | 247 | ||
276 | /** | 248 | /** |
277 | * pm_noirq_op - Execute the PM operation appropriate for given PM event. | 249 | * pm_noirq_op - Return the PM operation appropriate for given PM event. |
278 | * @dev: Device to handle. | ||
279 | * @ops: PM operations to choose from. | 250 | * @ops: PM operations to choose from. |
280 | * @state: PM transition of the system being carried out. | 251 | * @state: PM transition of the system being carried out. |
281 | * | 252 | * |
282 | * The driver of @dev will not receive interrupts while this function is being | 253 | * The driver of @dev will not receive interrupts while this function is being |
283 | * executed. | 254 | * executed. |
284 | */ | 255 | */ |
285 | static int pm_noirq_op(struct device *dev, | 256 | static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t state) |
286 | const struct dev_pm_ops *ops, | ||
287 | pm_message_t state) | ||
288 | { | 257 | { |
289 | int error = 0; | ||
290 | |||
291 | switch (state.event) { | 258 | switch (state.event) { |
292 | #ifdef CONFIG_SUSPEND | 259 | #ifdef CONFIG_SUSPEND |
293 | case PM_EVENT_SUSPEND: | 260 | case PM_EVENT_SUSPEND: |
294 | error = dpm_run_callback(dev, ops->suspend_noirq); | 261 | return ops->suspend_noirq; |
295 | break; | ||
296 | case PM_EVENT_RESUME: | 262 | case PM_EVENT_RESUME: |
297 | error = dpm_run_callback(dev, ops->resume_noirq); | 263 | return ops->resume_noirq; |
298 | break; | ||
299 | #endif /* CONFIG_SUSPEND */ | 264 | #endif /* CONFIG_SUSPEND */ |
300 | #ifdef CONFIG_HIBERNATE_CALLBACKS | 265 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
301 | case PM_EVENT_FREEZE: | 266 | case PM_EVENT_FREEZE: |
302 | case PM_EVENT_QUIESCE: | 267 | case PM_EVENT_QUIESCE: |
303 | error = dpm_run_callback(dev, ops->freeze_noirq); | 268 | return ops->freeze_noirq; |
304 | break; | ||
305 | case PM_EVENT_HIBERNATE: | 269 | case PM_EVENT_HIBERNATE: |
306 | error = dpm_run_callback(dev, ops->poweroff_noirq); | 270 | return ops->poweroff_noirq; |
307 | break; | ||
308 | case PM_EVENT_THAW: | 271 | case PM_EVENT_THAW: |
309 | case PM_EVENT_RECOVER: | 272 | case PM_EVENT_RECOVER: |
310 | error = dpm_run_callback(dev, ops->thaw_noirq); | 273 | return ops->thaw_noirq; |
311 | break; | ||
312 | case PM_EVENT_RESTORE: | 274 | case PM_EVENT_RESTORE: |
313 | error = dpm_run_callback(dev, ops->restore_noirq); | 275 | return ops->restore_noirq; |
314 | break; | ||
315 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | 276 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
316 | default: | ||
317 | error = -EINVAL; | ||
318 | } | 277 | } |
319 | 278 | ||
320 | return error; | 279 | return NULL; |
321 | } | 280 | } |
322 | 281 | ||
323 | static char *pm_verb(int event) | 282 | static char *pm_verb(int event) |
@@ -375,6 +334,26 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) | |||
375 | usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); | 334 | usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); |
376 | } | 335 | } |
377 | 336 | ||
337 | static int dpm_run_callback(pm_callback_t cb, struct device *dev, | ||
338 | pm_message_t state, char *info) | ||
339 | { | ||
340 | ktime_t calltime; | ||
341 | int error; | ||
342 | |||
343 | if (!cb) | ||
344 | return 0; | ||
345 | |||
346 | calltime = initcall_debug_start(dev); | ||
347 | |||
348 | pm_dev_dbg(dev, state, info); | ||
349 | error = cb(dev); | ||
350 | suspend_report_result(cb, error); | ||
351 | |||
352 | initcall_debug_report(dev, calltime, error); | ||
353 | |||
354 | return error; | ||
355 | } | ||
356 | |||
378 | /*------------------------- Resume routines -------------------------*/ | 357 | /*------------------------- Resume routines -------------------------*/ |
379 | 358 | ||
380 | /** | 359 | /** |
@@ -387,25 +366,29 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) | |||
387 | */ | 366 | */ |
388 | static int device_resume_noirq(struct device *dev, pm_message_t state) | 367 | static int device_resume_noirq(struct device *dev, pm_message_t state) |
389 | { | 368 | { |
369 | pm_callback_t callback = NULL; | ||
370 | char *info = NULL; | ||
390 | int error = 0; | 371 | int error = 0; |
391 | 372 | ||
392 | TRACE_DEVICE(dev); | 373 | TRACE_DEVICE(dev); |
393 | TRACE_RESUME(0); | 374 | TRACE_RESUME(0); |
394 | 375 | ||
395 | if (dev->pm_domain) { | 376 | if (dev->pm_domain) { |
396 | pm_dev_dbg(dev, state, "EARLY power domain "); | 377 | info = "EARLY power domain "; |
397 | error = pm_noirq_op(dev, &dev->pm_domain->ops, state); | 378 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
398 | } else if (dev->type && dev->type->pm) { | 379 | } else if (dev->type && dev->type->pm) { |
399 | pm_dev_dbg(dev, state, "EARLY type "); | 380 | info = "EARLY type "; |
400 | error = pm_noirq_op(dev, dev->type->pm, state); | 381 | callback = pm_noirq_op(dev->type->pm, state); |
401 | } else if (dev->class && dev->class->pm) { | 382 | } else if (dev->class && dev->class->pm) { |
402 | pm_dev_dbg(dev, state, "EARLY class "); | 383 | info = "EARLY class "; |
403 | error = pm_noirq_op(dev, dev->class->pm, state); | 384 | callback = pm_noirq_op(dev->class->pm, state); |
404 | } else if (dev->bus && dev->bus->pm) { | 385 | } else if (dev->bus && dev->bus->pm) { |
405 | pm_dev_dbg(dev, state, "EARLY "); | 386 | info = "EARLY "; |
406 | error = pm_noirq_op(dev, dev->bus->pm, state); | 387 | callback = pm_noirq_op(dev->bus->pm, state); |
407 | } | 388 | } |
408 | 389 | ||
390 | error = dpm_run_callback(callback, dev, state, info); | ||
391 | |||
409 | TRACE_RESUME(error); | 392 | TRACE_RESUME(error); |
410 | return error; | 393 | return error; |
411 | } | 394 | } |
@@ -455,6 +438,8 @@ EXPORT_SYMBOL_GPL(dpm_resume_noirq); | |||
455 | */ | 438 | */ |
456 | static int device_resume(struct device *dev, pm_message_t state, bool async) | 439 | static int device_resume(struct device *dev, pm_message_t state, bool async) |
457 | { | 440 | { |
441 | pm_callback_t callback = NULL; | ||
442 | char *info = NULL; | ||
458 | int error = 0; | 443 | int error = 0; |
459 | bool put = false; | 444 | bool put = false; |
460 | 445 | ||
@@ -477,40 +462,41 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
477 | put = true; | 462 | put = true; |
478 | 463 | ||
479 | if (dev->pm_domain) { | 464 | if (dev->pm_domain) { |
480 | pm_dev_dbg(dev, state, "power domain "); | 465 | info = "power domain "; |
481 | error = pm_op(dev, &dev->pm_domain->ops, state); | 466 | callback = pm_op(&dev->pm_domain->ops, state); |
482 | goto End; | 467 | goto End; |
483 | } | 468 | } |
484 | 469 | ||
485 | if (dev->type && dev->type->pm) { | 470 | if (dev->type && dev->type->pm) { |
486 | pm_dev_dbg(dev, state, "type "); | 471 | info = "type "; |
487 | error = pm_op(dev, dev->type->pm, state); | 472 | callback = pm_op(dev->type->pm, state); |
488 | goto End; | 473 | goto End; |
489 | } | 474 | } |
490 | 475 | ||
491 | if (dev->class) { | 476 | if (dev->class) { |
492 | if (dev->class->pm) { | 477 | if (dev->class->pm) { |
493 | pm_dev_dbg(dev, state, "class "); | 478 | info = "class "; |
494 | error = pm_op(dev, dev->class->pm, state); | 479 | callback = pm_op(dev->class->pm, state); |
495 | goto End; | 480 | goto End; |
496 | } else if (dev->class->resume) { | 481 | } else if (dev->class->resume) { |
497 | pm_dev_dbg(dev, state, "legacy class "); | 482 | info = "legacy class "; |
498 | error = dpm_run_callback(dev, dev->class->resume); | 483 | callback = dev->class->resume; |
499 | goto End; | 484 | goto End; |
500 | } | 485 | } |
501 | } | 486 | } |
502 | 487 | ||
503 | if (dev->bus) { | 488 | if (dev->bus) { |
504 | if (dev->bus->pm) { | 489 | if (dev->bus->pm) { |
505 | pm_dev_dbg(dev, state, ""); | 490 | info = ""; |
506 | error = pm_op(dev, dev->bus->pm, state); | 491 | callback = pm_op(dev->bus->pm, state); |
507 | } else if (dev->bus->resume) { | 492 | } else if (dev->bus->resume) { |
508 | pm_dev_dbg(dev, state, "legacy "); | 493 | info = "legacy "; |
509 | error = dpm_run_callback(dev, dev->bus->resume); | 494 | callback = dev->bus->resume; |
510 | } | 495 | } |
511 | } | 496 | } |
512 | 497 | ||
513 | End: | 498 | End: |
499 | error = dpm_run_callback(callback, dev, state, info); | ||
514 | dev->power.is_suspended = false; | 500 | dev->power.is_suspended = false; |
515 | 501 | ||
516 | Unlock: | 502 | Unlock: |
@@ -705,23 +691,24 @@ static pm_message_t resume_event(pm_message_t sleep_state) | |||
705 | */ | 691 | */ |
706 | static int device_suspend_noirq(struct device *dev, pm_message_t state) | 692 | static int device_suspend_noirq(struct device *dev, pm_message_t state) |
707 | { | 693 | { |
708 | int error = 0; | 694 | pm_callback_t callback = NULL; |
695 | char *info = NULL; | ||
709 | 696 | ||
710 | if (dev->pm_domain) { | 697 | if (dev->pm_domain) { |
711 | pm_dev_dbg(dev, state, "LATE power domain "); | 698 | info = "LATE power domain "; |
712 | error = pm_noirq_op(dev, &dev->pm_domain->ops, state); | 699 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
713 | } else if (dev->type && dev->type->pm) { | 700 | } else if (dev->type && dev->type->pm) { |
714 | pm_dev_dbg(dev, state, "LATE type "); | 701 | info = "LATE type "; |
715 | error = pm_noirq_op(dev, dev->type->pm, state); | 702 | callback = pm_noirq_op(dev->type->pm, state); |
716 | } else if (dev->class && dev->class->pm) { | 703 | } else if (dev->class && dev->class->pm) { |
717 | pm_dev_dbg(dev, state, "LATE class "); | 704 | info = "LATE class "; |
718 | error = pm_noirq_op(dev, dev->class->pm, state); | 705 | callback = pm_noirq_op(dev->class->pm, state); |
719 | } else if (dev->bus && dev->bus->pm) { | 706 | } else if (dev->bus && dev->bus->pm) { |
720 | pm_dev_dbg(dev, state, "LATE "); | 707 | info = "LATE "; |
721 | error = pm_noirq_op(dev, dev->bus->pm, state); | 708 | callback = pm_noirq_op(dev->bus->pm, state); |
722 | } | 709 | } |
723 | 710 | ||
724 | return error; | 711 | return dpm_run_callback(callback, dev, state, info); |
725 | } | 712 | } |
726 | 713 | ||
727 | /** | 714 | /** |
@@ -798,6 +785,8 @@ static int legacy_suspend(struct device *dev, pm_message_t state, | |||
798 | */ | 785 | */ |
799 | static int __device_suspend(struct device *dev, pm_message_t state, bool async) | 786 | static int __device_suspend(struct device *dev, pm_message_t state, bool async) |
800 | { | 787 | { |
788 | pm_callback_t callback = NULL; | ||
789 | char *info = NULL; | ||
801 | int error = 0; | 790 | int error = 0; |
802 | 791 | ||
803 | dpm_wait_for_children(dev, async); | 792 | dpm_wait_for_children(dev, async); |
@@ -818,22 +807,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
818 | device_lock(dev); | 807 | device_lock(dev); |
819 | 808 | ||
820 | if (dev->pm_domain) { | 809 | if (dev->pm_domain) { |
821 | pm_dev_dbg(dev, state, "power domain "); | 810 | info = "power domain "; |
822 | error = pm_op(dev, &dev->pm_domain->ops, state); | 811 | callback = pm_op(&dev->pm_domain->ops, state); |
823 | goto End; | 812 | goto Run; |
824 | } | 813 | } |
825 | 814 | ||
826 | if (dev->type && dev->type->pm) { | 815 | if (dev->type && dev->type->pm) { |
827 | pm_dev_dbg(dev, state, "type "); | 816 | info = "type "; |
828 | error = pm_op(dev, dev->type->pm, state); | 817 | callback = pm_op(dev->type->pm, state); |
829 | goto End; | 818 | goto Run; |
830 | } | 819 | } |
831 | 820 | ||
832 | if (dev->class) { | 821 | if (dev->class) { |
833 | if (dev->class->pm) { | 822 | if (dev->class->pm) { |
834 | pm_dev_dbg(dev, state, "class "); | 823 | info = "class "; |
835 | error = pm_op(dev, dev->class->pm, state); | 824 | callback = pm_op(dev->class->pm, state); |
836 | goto End; | 825 | goto Run; |
837 | } else if (dev->class->suspend) { | 826 | } else if (dev->class->suspend) { |
838 | pm_dev_dbg(dev, state, "legacy class "); | 827 | pm_dev_dbg(dev, state, "legacy class "); |
839 | error = legacy_suspend(dev, state, dev->class->suspend); | 828 | error = legacy_suspend(dev, state, dev->class->suspend); |
@@ -843,14 +832,18 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
843 | 832 | ||
844 | if (dev->bus) { | 833 | if (dev->bus) { |
845 | if (dev->bus->pm) { | 834 | if (dev->bus->pm) { |
846 | pm_dev_dbg(dev, state, ""); | 835 | info = ""; |
847 | error = pm_op(dev, dev->bus->pm, state); | 836 | callback = pm_op(dev->bus->pm, state); |
848 | } else if (dev->bus->suspend) { | 837 | } else if (dev->bus->suspend) { |
849 | pm_dev_dbg(dev, state, "legacy "); | 838 | pm_dev_dbg(dev, state, "legacy "); |
850 | error = legacy_suspend(dev, state, dev->bus->suspend); | 839 | error = legacy_suspend(dev, state, dev->bus->suspend); |
840 | goto End; | ||
851 | } | 841 | } |
852 | } | 842 | } |
853 | 843 | ||
844 | Run: | ||
845 | error = dpm_run_callback(callback, dev, state, info); | ||
846 | |||
854 | End: | 847 | End: |
855 | if (!error) { | 848 | if (!error) { |
856 | dev->power.is_suspended = true; | 849 | dev->power.is_suspended = true; |