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 | |
| 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>
| -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; |
