| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * drivers/base/power/main.c - Where the driver meets power management. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2003 Patrick Mochel |
|---|
| 5 | 6 | * Copyright (c) 2003 Open Source Development Lab |
|---|
| 6 | | - * |
|---|
| 7 | | - * This file is released under the GPLv2 |
|---|
| 8 | | - * |
|---|
| 9 | 7 | * |
|---|
| 10 | 8 | * The driver model core calls device_pm_add() when a device is registered. |
|---|
| 11 | 9 | * This will initialize the embedded device_pm_info object in the device |
|---|
| .. | .. |
|---|
| 16 | 14 | * domain dependencies may differ from the ancestral dependencies that the |
|---|
| 17 | 15 | * subsystem list maintains. |
|---|
| 18 | 16 | */ |
|---|
| 17 | + |
|---|
| 18 | +#define pr_fmt(fmt) "PM: " fmt |
|---|
| 19 | 19 | |
|---|
| 20 | 20 | #include <linux/device.h> |
|---|
| 21 | 21 | #include <linux/export.h> |
|---|
| .. | .. |
|---|
| 32 | 32 | #include <trace/events/power.h> |
|---|
| 33 | 33 | #include <linux/cpufreq.h> |
|---|
| 34 | 34 | #include <linux/cpuidle.h> |
|---|
| 35 | +#include <linux/devfreq.h> |
|---|
| 35 | 36 | #include <linux/timer.h> |
|---|
| 36 | 37 | #include <linux/wakeup_reason.h> |
|---|
| 37 | 38 | |
|---|
| .. | .. |
|---|
| 39 | 40 | #include "power.h" |
|---|
| 40 | 41 | |
|---|
| 41 | 42 | typedef int (*pm_callback_t)(struct device *); |
|---|
| 43 | + |
|---|
| 44 | +#define list_for_each_entry_rcu_locked(pos, head, member) \ |
|---|
| 45 | + list_for_each_entry_rcu(pos, head, member, \ |
|---|
| 46 | + device_links_read_lock_held()) |
|---|
| 42 | 47 | |
|---|
| 43 | 48 | /* |
|---|
| 44 | 49 | * The entries in the dpm_list list are in a depth first order, simply |
|---|
| .. | .. |
|---|
| 128 | 133 | if (device_pm_not_required(dev)) |
|---|
| 129 | 134 | return; |
|---|
| 130 | 135 | |
|---|
| 131 | | - pr_debug("PM: Adding info for %s:%s\n", |
|---|
| 136 | + pr_debug("Adding info for %s:%s\n", |
|---|
| 132 | 137 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
|---|
| 133 | 138 | device_pm_check_callbacks(dev); |
|---|
| 134 | 139 | mutex_lock(&dpm_list_mtx); |
|---|
| .. | .. |
|---|
| 149 | 154 | if (device_pm_not_required(dev)) |
|---|
| 150 | 155 | return; |
|---|
| 151 | 156 | |
|---|
| 152 | | - pr_debug("PM: Removing info for %s:%s\n", |
|---|
| 157 | + pr_debug("Removing info for %s:%s\n", |
|---|
| 153 | 158 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
|---|
| 154 | 159 | complete_all(&dev->power.completion); |
|---|
| 155 | 160 | mutex_lock(&dpm_list_mtx); |
|---|
| .. | .. |
|---|
| 168 | 173 | */ |
|---|
| 169 | 174 | void device_pm_move_before(struct device *deva, struct device *devb) |
|---|
| 170 | 175 | { |
|---|
| 171 | | - pr_debug("PM: Moving %s:%s before %s:%s\n", |
|---|
| 176 | + pr_debug("Moving %s:%s before %s:%s\n", |
|---|
| 172 | 177 | deva->bus ? deva->bus->name : "No Bus", dev_name(deva), |
|---|
| 173 | 178 | devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); |
|---|
| 174 | 179 | /* Delete deva from dpm_list and reinsert before devb. */ |
|---|
| .. | .. |
|---|
| 182 | 187 | */ |
|---|
| 183 | 188 | void device_pm_move_after(struct device *deva, struct device *devb) |
|---|
| 184 | 189 | { |
|---|
| 185 | | - pr_debug("PM: Moving %s:%s after %s:%s\n", |
|---|
| 190 | + pr_debug("Moving %s:%s after %s:%s\n", |
|---|
| 186 | 191 | deva->bus ? deva->bus->name : "No Bus", dev_name(deva), |
|---|
| 187 | 192 | devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); |
|---|
| 188 | 193 | /* Delete deva from dpm_list and reinsert after devb. */ |
|---|
| .. | .. |
|---|
| 195 | 200 | */ |
|---|
| 196 | 201 | void device_pm_move_last(struct device *dev) |
|---|
| 197 | 202 | { |
|---|
| 198 | | - pr_debug("PM: Moving %s:%s to end of list\n", |
|---|
| 203 | + pr_debug("Moving %s:%s to end of list\n", |
|---|
| 199 | 204 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
|---|
| 200 | 205 | list_move_tail(&dev->power.entry, &dpm_list); |
|---|
| 201 | 206 | } |
|---|
| .. | .. |
|---|
| 205 | 210 | if (!pm_print_times_enabled) |
|---|
| 206 | 211 | return 0; |
|---|
| 207 | 212 | |
|---|
| 208 | | - dev_info(dev, "calling %pF @ %i, parent: %s\n", cb, |
|---|
| 213 | + dev_info(dev, "calling %pS @ %i, parent: %s\n", cb, |
|---|
| 209 | 214 | task_pid_nr(current), |
|---|
| 210 | 215 | dev->parent ? dev_name(dev->parent) : "none"); |
|---|
| 211 | 216 | return ktime_get(); |
|---|
| .. | .. |
|---|
| 223 | 228 | rettime = ktime_get(); |
|---|
| 224 | 229 | nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime)); |
|---|
| 225 | 230 | |
|---|
| 226 | | - dev_info(dev, "%pF returned %d after %Ld usecs\n", cb, error, |
|---|
| 231 | + dev_info(dev, "%pS returned %d after %Ld usecs\n", cb, error, |
|---|
| 227 | 232 | (unsigned long long)nsecs >> 10); |
|---|
| 228 | 233 | } |
|---|
| 229 | 234 | |
|---|
| .. | .. |
|---|
| 266 | 271 | * callbacks freeing the link objects for the links in the list we're |
|---|
| 267 | 272 | * walking. |
|---|
| 268 | 273 | */ |
|---|
| 269 | | - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) |
|---|
| 274 | + list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) |
|---|
| 270 | 275 | if (READ_ONCE(link->status) != DL_STATE_DORMANT) |
|---|
| 271 | 276 | dpm_wait(link->supplier, async); |
|---|
| 272 | 277 | |
|---|
| .. | .. |
|---|
| 323 | 328 | * continue instead of trying to continue in parallel with its |
|---|
| 324 | 329 | * unregistration). |
|---|
| 325 | 330 | */ |
|---|
| 326 | | - list_for_each_entry_rcu(link, &dev->links.consumers, s_node) |
|---|
| 331 | + list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node) |
|---|
| 327 | 332 | if (READ_ONCE(link->status) != DL_STATE_DORMANT) |
|---|
| 328 | 333 | dpm_wait(link->consumer, async); |
|---|
| 329 | 334 | |
|---|
| .. | .. |
|---|
| 359 | 364 | case PM_EVENT_THAW: |
|---|
| 360 | 365 | case PM_EVENT_RECOVER: |
|---|
| 361 | 366 | return ops->thaw; |
|---|
| 362 | | - break; |
|---|
| 363 | 367 | case PM_EVENT_RESTORE: |
|---|
| 364 | 368 | return ops->restore; |
|---|
| 365 | 369 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
|---|
| .. | .. |
|---|
| 446 | 450 | static void pm_dev_err(struct device *dev, pm_message_t state, const char *info, |
|---|
| 447 | 451 | int error) |
|---|
| 448 | 452 | { |
|---|
| 449 | | - printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n", |
|---|
| 450 | | - dev_name(dev), pm_verb(state.event), info, error); |
|---|
| 453 | + pr_err("Device %s failed to %s%s: error %d\n", |
|---|
| 454 | + dev_name(dev), pm_verb(state.event), info, error); |
|---|
| 451 | 455 | } |
|---|
| 452 | 456 | |
|---|
| 453 | 457 | static void dpm_show_time(ktime_t starttime, pm_message_t state, int error, |
|---|
| .. | .. |
|---|
| 504 | 508 | |
|---|
| 505 | 509 | /** |
|---|
| 506 | 510 | * dpm_watchdog_handler - Driver suspend / resume watchdog handler. |
|---|
| 507 | | - * @data: Watchdog object address. |
|---|
| 511 | + * @t: The timer that PM watchdog depends on. |
|---|
| 508 | 512 | * |
|---|
| 509 | 513 | * Called when a driver has timed out suspending or resuming. |
|---|
| 510 | 514 | * There's not much we can do here to recover so panic() to |
|---|
| .. | .. |
|---|
| 515 | 519 | struct dpm_watchdog *wd = from_timer(wd, t, timer); |
|---|
| 516 | 520 | |
|---|
| 517 | 521 | dev_emerg(wd->dev, "**** DPM device timeout ****\n"); |
|---|
| 518 | | - show_stack(wd->tsk, NULL); |
|---|
| 522 | + show_stack(wd->tsk, NULL, KERN_EMERG); |
|---|
| 519 | 523 | panic("%s %s: unrecoverable failure\n", |
|---|
| 520 | 524 | dev_driver_string(wd->dev), dev_name(wd->dev)); |
|---|
| 521 | 525 | } |
|---|
| .. | .. |
|---|
| 558 | 562 | /*------------------------- Resume routines -------------------------*/ |
|---|
| 559 | 563 | |
|---|
| 560 | 564 | /** |
|---|
| 561 | | - * dev_pm_skip_next_resume_phases - Skip next system resume phases for device. |
|---|
| 565 | + * dev_pm_skip_resume - System-wide device resume optimization check. |
|---|
| 562 | 566 | * @dev: Target device. |
|---|
| 563 | 567 | * |
|---|
| 564 | | - * Make the core skip the "early resume" and "resume" phases for @dev. |
|---|
| 565 | | - * |
|---|
| 566 | | - * This function can be called by middle-layer code during the "noirq" phase of |
|---|
| 567 | | - * system resume if necessary, but not by device drivers. |
|---|
| 568 | + * Return: |
|---|
| 569 | + * - %false if the transition under way is RESTORE. |
|---|
| 570 | + * - Return value of dev_pm_skip_suspend() if the transition under way is THAW. |
|---|
| 571 | + * - The logical negation of %power.must_resume otherwise (that is, when the |
|---|
| 572 | + * transition under way is RESUME). |
|---|
| 568 | 573 | */ |
|---|
| 569 | | -void dev_pm_skip_next_resume_phases(struct device *dev) |
|---|
| 574 | +bool dev_pm_skip_resume(struct device *dev) |
|---|
| 570 | 575 | { |
|---|
| 571 | | - dev->power.is_late_suspended = false; |
|---|
| 572 | | - dev->power.is_suspended = false; |
|---|
| 576 | + if (pm_transition.event == PM_EVENT_RESTORE) |
|---|
| 577 | + return false; |
|---|
| 578 | + |
|---|
| 579 | + if (pm_transition.event == PM_EVENT_THAW) |
|---|
| 580 | + return dev_pm_skip_suspend(dev); |
|---|
| 581 | + |
|---|
| 582 | + return !dev->power.must_resume; |
|---|
| 573 | 583 | } |
|---|
| 574 | | - |
|---|
| 575 | | -/** |
|---|
| 576 | | - * suspend_event - Return a "suspend" message for given "resume" one. |
|---|
| 577 | | - * @resume_msg: PM message representing a system-wide resume transition. |
|---|
| 578 | | - */ |
|---|
| 579 | | -static pm_message_t suspend_event(pm_message_t resume_msg) |
|---|
| 580 | | -{ |
|---|
| 581 | | - switch (resume_msg.event) { |
|---|
| 582 | | - case PM_EVENT_RESUME: |
|---|
| 583 | | - return PMSG_SUSPEND; |
|---|
| 584 | | - case PM_EVENT_THAW: |
|---|
| 585 | | - case PM_EVENT_RESTORE: |
|---|
| 586 | | - return PMSG_FREEZE; |
|---|
| 587 | | - case PM_EVENT_RECOVER: |
|---|
| 588 | | - return PMSG_HIBERNATE; |
|---|
| 589 | | - } |
|---|
| 590 | | - return PMSG_ON; |
|---|
| 591 | | -} |
|---|
| 592 | | - |
|---|
| 593 | | -/** |
|---|
| 594 | | - * dev_pm_may_skip_resume - System-wide device resume optimization check. |
|---|
| 595 | | - * @dev: Target device. |
|---|
| 596 | | - * |
|---|
| 597 | | - * Checks whether or not the device may be left in suspend after a system-wide |
|---|
| 598 | | - * transition to the working state. |
|---|
| 599 | | - */ |
|---|
| 600 | | -bool dev_pm_may_skip_resume(struct device *dev) |
|---|
| 601 | | -{ |
|---|
| 602 | | - return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; |
|---|
| 603 | | -} |
|---|
| 604 | | - |
|---|
| 605 | | -static pm_callback_t dpm_subsys_resume_noirq_cb(struct device *dev, |
|---|
| 606 | | - pm_message_t state, |
|---|
| 607 | | - const char **info_p) |
|---|
| 608 | | -{ |
|---|
| 609 | | - pm_callback_t callback; |
|---|
| 610 | | - const char *info; |
|---|
| 611 | | - |
|---|
| 612 | | - if (dev->pm_domain) { |
|---|
| 613 | | - info = "noirq power domain "; |
|---|
| 614 | | - callback = pm_noirq_op(&dev->pm_domain->ops, state); |
|---|
| 615 | | - } else if (dev->type && dev->type->pm) { |
|---|
| 616 | | - info = "noirq type "; |
|---|
| 617 | | - callback = pm_noirq_op(dev->type->pm, state); |
|---|
| 618 | | - } else if (dev->class && dev->class->pm) { |
|---|
| 619 | | - info = "noirq class "; |
|---|
| 620 | | - callback = pm_noirq_op(dev->class->pm, state); |
|---|
| 621 | | - } else if (dev->bus && dev->bus->pm) { |
|---|
| 622 | | - info = "noirq bus "; |
|---|
| 623 | | - callback = pm_noirq_op(dev->bus->pm, state); |
|---|
| 624 | | - } else { |
|---|
| 625 | | - return NULL; |
|---|
| 626 | | - } |
|---|
| 627 | | - |
|---|
| 628 | | - if (info_p) |
|---|
| 629 | | - *info_p = info; |
|---|
| 630 | | - |
|---|
| 631 | | - return callback; |
|---|
| 632 | | -} |
|---|
| 633 | | - |
|---|
| 634 | | -static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, |
|---|
| 635 | | - pm_message_t state, |
|---|
| 636 | | - const char **info_p); |
|---|
| 637 | | - |
|---|
| 638 | | -static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, |
|---|
| 639 | | - pm_message_t state, |
|---|
| 640 | | - const char **info_p); |
|---|
| 641 | 584 | |
|---|
| 642 | 585 | /** |
|---|
| 643 | 586 | * device_resume_noirq - Execute a "noirq resume" callback for given device. |
|---|
| .. | .. |
|---|
| 650 | 593 | */ |
|---|
| 651 | 594 | static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) |
|---|
| 652 | 595 | { |
|---|
| 653 | | - pm_callback_t callback; |
|---|
| 654 | | - const char *info; |
|---|
| 596 | + pm_callback_t callback = NULL; |
|---|
| 597 | + const char *info = NULL; |
|---|
| 655 | 598 | bool skip_resume; |
|---|
| 656 | 599 | int error = 0; |
|---|
| 657 | 600 | |
|---|
| .. | .. |
|---|
| 667 | 610 | if (!dpm_wait_for_superior(dev, async)) |
|---|
| 668 | 611 | goto Out; |
|---|
| 669 | 612 | |
|---|
| 670 | | - skip_resume = dev_pm_may_skip_resume(dev); |
|---|
| 613 | + skip_resume = dev_pm_skip_resume(dev); |
|---|
| 614 | + /* |
|---|
| 615 | + * If the driver callback is skipped below or by the middle layer |
|---|
| 616 | + * callback and device_resume_early() also skips the driver callback for |
|---|
| 617 | + * this device later, it needs to appear as "suspended" to PM-runtime, |
|---|
| 618 | + * so change its status accordingly. |
|---|
| 619 | + * |
|---|
| 620 | + * Otherwise, the device is going to be resumed, so set its PM-runtime |
|---|
| 621 | + * status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set |
|---|
| 622 | + * to avoid confusing drivers that don't use it. |
|---|
| 623 | + */ |
|---|
| 624 | + if (skip_resume) |
|---|
| 625 | + pm_runtime_set_suspended(dev); |
|---|
| 626 | + else if (dev_pm_skip_suspend(dev)) |
|---|
| 627 | + pm_runtime_set_active(dev); |
|---|
| 671 | 628 | |
|---|
| 672 | | - callback = dpm_subsys_resume_noirq_cb(dev, state, &info); |
|---|
| 629 | + if (dev->pm_domain) { |
|---|
| 630 | + info = "noirq power domain "; |
|---|
| 631 | + callback = pm_noirq_op(&dev->pm_domain->ops, state); |
|---|
| 632 | + } else if (dev->type && dev->type->pm) { |
|---|
| 633 | + info = "noirq type "; |
|---|
| 634 | + callback = pm_noirq_op(dev->type->pm, state); |
|---|
| 635 | + } else if (dev->class && dev->class->pm) { |
|---|
| 636 | + info = "noirq class "; |
|---|
| 637 | + callback = pm_noirq_op(dev->class->pm, state); |
|---|
| 638 | + } else if (dev->bus && dev->bus->pm) { |
|---|
| 639 | + info = "noirq bus "; |
|---|
| 640 | + callback = pm_noirq_op(dev->bus->pm, state); |
|---|
| 641 | + } |
|---|
| 673 | 642 | if (callback) |
|---|
| 674 | 643 | goto Run; |
|---|
| 675 | 644 | |
|---|
| 676 | 645 | if (skip_resume) |
|---|
| 677 | 646 | goto Skip; |
|---|
| 678 | | - |
|---|
| 679 | | - if (dev_pm_smart_suspend_and_suspended(dev)) { |
|---|
| 680 | | - pm_message_t suspend_msg = suspend_event(state); |
|---|
| 681 | | - |
|---|
| 682 | | - /* |
|---|
| 683 | | - * If "freeze" callbacks have been skipped during a transition |
|---|
| 684 | | - * related to hibernation, the subsequent "thaw" callbacks must |
|---|
| 685 | | - * be skipped too or bad things may happen. Otherwise, resume |
|---|
| 686 | | - * callbacks are going to be run for the device, so its runtime |
|---|
| 687 | | - * PM status must be changed to reflect the new state after the |
|---|
| 688 | | - * transition under way. |
|---|
| 689 | | - */ |
|---|
| 690 | | - if (!dpm_subsys_suspend_late_cb(dev, suspend_msg, NULL) && |
|---|
| 691 | | - !dpm_subsys_suspend_noirq_cb(dev, suspend_msg, NULL)) { |
|---|
| 692 | | - if (state.event == PM_EVENT_THAW) { |
|---|
| 693 | | - skip_resume = true; |
|---|
| 694 | | - goto Skip; |
|---|
| 695 | | - } else { |
|---|
| 696 | | - pm_runtime_set_active(dev); |
|---|
| 697 | | - } |
|---|
| 698 | | - } |
|---|
| 699 | | - } |
|---|
| 700 | 647 | |
|---|
| 701 | 648 | if (dev->driver && dev->driver->pm) { |
|---|
| 702 | 649 | info = "noirq driver "; |
|---|
| .. | .. |
|---|
| 709 | 656 | Skip: |
|---|
| 710 | 657 | dev->power.is_noirq_suspended = false; |
|---|
| 711 | 658 | |
|---|
| 712 | | - if (skip_resume) { |
|---|
| 713 | | - /* |
|---|
| 714 | | - * The device is going to be left in suspend, but it might not |
|---|
| 715 | | - * have been in runtime suspend before the system suspended, so |
|---|
| 716 | | - * its runtime PM status needs to be updated to avoid confusing |
|---|
| 717 | | - * the runtime PM framework when runtime PM is enabled for the |
|---|
| 718 | | - * device again. |
|---|
| 719 | | - */ |
|---|
| 720 | | - pm_runtime_set_suspended(dev); |
|---|
| 721 | | - dev_pm_skip_next_resume_phases(dev); |
|---|
| 722 | | - } |
|---|
| 723 | | - |
|---|
| 724 | 659 | Out: |
|---|
| 725 | 660 | complete_all(&dev->power.completion); |
|---|
| 726 | 661 | TRACE_RESUME(error); |
|---|
| .. | .. |
|---|
| 731 | 666 | { |
|---|
| 732 | 667 | return dev->power.async_suspend && pm_async_enabled |
|---|
| 733 | 668 | && !pm_trace_is_enabled(); |
|---|
| 669 | +} |
|---|
| 670 | + |
|---|
| 671 | +static bool dpm_async_fn(struct device *dev, async_func_t func) |
|---|
| 672 | +{ |
|---|
| 673 | + reinit_completion(&dev->power.completion); |
|---|
| 674 | + |
|---|
| 675 | + if (is_async(dev)) { |
|---|
| 676 | + get_device(dev); |
|---|
| 677 | + async_schedule_dev(func, dev); |
|---|
| 678 | + return true; |
|---|
| 679 | + } |
|---|
| 680 | + |
|---|
| 681 | + return false; |
|---|
| 734 | 682 | } |
|---|
| 735 | 683 | |
|---|
| 736 | 684 | static void async_resume_noirq(void *data, async_cookie_t cookie) |
|---|
| .. | .. |
|---|
| 745 | 693 | put_device(dev); |
|---|
| 746 | 694 | } |
|---|
| 747 | 695 | |
|---|
| 748 | | -void dpm_noirq_resume_devices(pm_message_t state) |
|---|
| 696 | +static void dpm_noirq_resume_devices(pm_message_t state) |
|---|
| 749 | 697 | { |
|---|
| 750 | 698 | struct device *dev; |
|---|
| 751 | 699 | ktime_t starttime = ktime_get(); |
|---|
| .. | .. |
|---|
| 759 | 707 | * in case the starting of async threads is |
|---|
| 760 | 708 | * delayed by non-async resuming devices. |
|---|
| 761 | 709 | */ |
|---|
| 762 | | - list_for_each_entry(dev, &dpm_noirq_list, power.entry) { |
|---|
| 763 | | - reinit_completion(&dev->power.completion); |
|---|
| 764 | | - if (is_async(dev)) { |
|---|
| 765 | | - get_device(dev); |
|---|
| 766 | | - async_schedule(async_resume_noirq, dev); |
|---|
| 767 | | - } |
|---|
| 768 | | - } |
|---|
| 710 | + list_for_each_entry(dev, &dpm_noirq_list, power.entry) |
|---|
| 711 | + dpm_async_fn(dev, async_resume_noirq); |
|---|
| 769 | 712 | |
|---|
| 770 | 713 | while (!list_empty(&dpm_noirq_list)) { |
|---|
| 771 | 714 | dev = to_device(dpm_noirq_list.next); |
|---|
| .. | .. |
|---|
| 794 | 737 | trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); |
|---|
| 795 | 738 | } |
|---|
| 796 | 739 | |
|---|
| 797 | | -void dpm_noirq_end(void) |
|---|
| 798 | | -{ |
|---|
| 799 | | - resume_device_irqs(); |
|---|
| 800 | | - device_wakeup_disarm_wake_irqs(); |
|---|
| 801 | | - cpuidle_resume(); |
|---|
| 802 | | -} |
|---|
| 803 | | - |
|---|
| 804 | 740 | /** |
|---|
| 805 | 741 | * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. |
|---|
| 806 | 742 | * @state: PM transition of the system being carried out. |
|---|
| .. | .. |
|---|
| 811 | 747 | void dpm_resume_noirq(pm_message_t state) |
|---|
| 812 | 748 | { |
|---|
| 813 | 749 | dpm_noirq_resume_devices(state); |
|---|
| 814 | | - dpm_noirq_end(); |
|---|
| 815 | | -} |
|---|
| 816 | 750 | |
|---|
| 817 | | -static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, |
|---|
| 818 | | - pm_message_t state, |
|---|
| 819 | | - const char **info_p) |
|---|
| 820 | | -{ |
|---|
| 821 | | - pm_callback_t callback; |
|---|
| 822 | | - const char *info; |
|---|
| 751 | + resume_device_irqs(); |
|---|
| 752 | + device_wakeup_disarm_wake_irqs(); |
|---|
| 823 | 753 | |
|---|
| 824 | | - if (dev->pm_domain) { |
|---|
| 825 | | - info = "early power domain "; |
|---|
| 826 | | - callback = pm_late_early_op(&dev->pm_domain->ops, state); |
|---|
| 827 | | - } else if (dev->type && dev->type->pm) { |
|---|
| 828 | | - info = "early type "; |
|---|
| 829 | | - callback = pm_late_early_op(dev->type->pm, state); |
|---|
| 830 | | - } else if (dev->class && dev->class->pm) { |
|---|
| 831 | | - info = "early class "; |
|---|
| 832 | | - callback = pm_late_early_op(dev->class->pm, state); |
|---|
| 833 | | - } else if (dev->bus && dev->bus->pm) { |
|---|
| 834 | | - info = "early bus "; |
|---|
| 835 | | - callback = pm_late_early_op(dev->bus->pm, state); |
|---|
| 836 | | - } else { |
|---|
| 837 | | - return NULL; |
|---|
| 838 | | - } |
|---|
| 839 | | - |
|---|
| 840 | | - if (info_p) |
|---|
| 841 | | - *info_p = info; |
|---|
| 842 | | - |
|---|
| 843 | | - return callback; |
|---|
| 754 | + cpuidle_resume(); |
|---|
| 844 | 755 | } |
|---|
| 845 | 756 | |
|---|
| 846 | 757 | /** |
|---|
| .. | .. |
|---|
| 853 | 764 | */ |
|---|
| 854 | 765 | static int device_resume_early(struct device *dev, pm_message_t state, bool async) |
|---|
| 855 | 766 | { |
|---|
| 856 | | - pm_callback_t callback; |
|---|
| 857 | | - const char *info; |
|---|
| 767 | + pm_callback_t callback = NULL; |
|---|
| 768 | + const char *info = NULL; |
|---|
| 858 | 769 | int error = 0; |
|---|
| 859 | 770 | |
|---|
| 860 | 771 | TRACE_DEVICE(dev); |
|---|
| .. | .. |
|---|
| 869 | 780 | if (!dpm_wait_for_superior(dev, async)) |
|---|
| 870 | 781 | goto Out; |
|---|
| 871 | 782 | |
|---|
| 872 | | - callback = dpm_subsys_resume_early_cb(dev, state, &info); |
|---|
| 783 | + if (dev->pm_domain) { |
|---|
| 784 | + info = "early power domain "; |
|---|
| 785 | + callback = pm_late_early_op(&dev->pm_domain->ops, state); |
|---|
| 786 | + } else if (dev->type && dev->type->pm) { |
|---|
| 787 | + info = "early type "; |
|---|
| 788 | + callback = pm_late_early_op(dev->type->pm, state); |
|---|
| 789 | + } else if (dev->class && dev->class->pm) { |
|---|
| 790 | + info = "early class "; |
|---|
| 791 | + callback = pm_late_early_op(dev->class->pm, state); |
|---|
| 792 | + } else if (dev->bus && dev->bus->pm) { |
|---|
| 793 | + info = "early bus "; |
|---|
| 794 | + callback = pm_late_early_op(dev->bus->pm, state); |
|---|
| 795 | + } |
|---|
| 796 | + if (callback) |
|---|
| 797 | + goto Run; |
|---|
| 873 | 798 | |
|---|
| 874 | | - if (!callback && dev->driver && dev->driver->pm) { |
|---|
| 799 | + if (dev_pm_skip_resume(dev)) |
|---|
| 800 | + goto Skip; |
|---|
| 801 | + |
|---|
| 802 | + if (dev->driver && dev->driver->pm) { |
|---|
| 875 | 803 | info = "early driver "; |
|---|
| 876 | 804 | callback = pm_late_early_op(dev->driver->pm, state); |
|---|
| 877 | 805 | } |
|---|
| 878 | 806 | |
|---|
| 807 | +Run: |
|---|
| 879 | 808 | error = dpm_run_callback(callback, dev, state, info); |
|---|
| 809 | + |
|---|
| 810 | +Skip: |
|---|
| 880 | 811 | dev->power.is_late_suspended = false; |
|---|
| 881 | 812 | |
|---|
| 882 | | - Out: |
|---|
| 813 | +Out: |
|---|
| 883 | 814 | TRACE_RESUME(error); |
|---|
| 884 | 815 | |
|---|
| 885 | 816 | pm_runtime_enable(dev); |
|---|
| .. | .. |
|---|
| 917 | 848 | * in case the starting of async threads is |
|---|
| 918 | 849 | * delayed by non-async resuming devices. |
|---|
| 919 | 850 | */ |
|---|
| 920 | | - list_for_each_entry(dev, &dpm_late_early_list, power.entry) { |
|---|
| 921 | | - reinit_completion(&dev->power.completion); |
|---|
| 922 | | - if (is_async(dev)) { |
|---|
| 923 | | - get_device(dev); |
|---|
| 924 | | - async_schedule(async_resume_early, dev); |
|---|
| 925 | | - } |
|---|
| 926 | | - } |
|---|
| 851 | + list_for_each_entry(dev, &dpm_late_early_list, power.entry) |
|---|
| 852 | + dpm_async_fn(dev, async_resume_early); |
|---|
| 927 | 853 | |
|---|
| 928 | 854 | while (!list_empty(&dpm_late_early_list)) { |
|---|
| 929 | 855 | dev = to_device(dpm_late_early_list.next); |
|---|
| .. | .. |
|---|
| 1083 | 1009 | pm_transition = state; |
|---|
| 1084 | 1010 | async_error = 0; |
|---|
| 1085 | 1011 | |
|---|
| 1086 | | - list_for_each_entry(dev, &dpm_suspended_list, power.entry) { |
|---|
| 1087 | | - reinit_completion(&dev->power.completion); |
|---|
| 1088 | | - if (is_async(dev)) { |
|---|
| 1089 | | - get_device(dev); |
|---|
| 1090 | | - async_schedule(async_resume, dev); |
|---|
| 1091 | | - } |
|---|
| 1092 | | - } |
|---|
| 1012 | + list_for_each_entry(dev, &dpm_suspended_list, power.entry) |
|---|
| 1013 | + dpm_async_fn(dev, async_resume); |
|---|
| 1093 | 1014 | |
|---|
| 1094 | 1015 | while (!list_empty(&dpm_suspended_list)) { |
|---|
| 1095 | 1016 | dev = to_device(dpm_suspended_list.next); |
|---|
| .. | .. |
|---|
| 1118 | 1039 | dpm_show_time(starttime, state, 0, NULL); |
|---|
| 1119 | 1040 | |
|---|
| 1120 | 1041 | cpufreq_resume(); |
|---|
| 1042 | + devfreq_resume(); |
|---|
| 1121 | 1043 | trace_suspend_resume(TPS("dpm_resume"), state.event, false); |
|---|
| 1122 | 1044 | } |
|---|
| 1123 | 1045 | |
|---|
| .. | .. |
|---|
| 1132 | 1054 | const char *info = NULL; |
|---|
| 1133 | 1055 | |
|---|
| 1134 | 1056 | if (dev->power.syscore) |
|---|
| 1135 | | - return; |
|---|
| 1057 | + goto out; |
|---|
| 1136 | 1058 | |
|---|
| 1137 | 1059 | device_lock(dev); |
|---|
| 1138 | 1060 | |
|---|
| .. | .. |
|---|
| 1162 | 1084 | |
|---|
| 1163 | 1085 | device_unlock(dev); |
|---|
| 1164 | 1086 | |
|---|
| 1087 | +out: |
|---|
| 1165 | 1088 | pm_runtime_put(dev); |
|---|
| 1166 | 1089 | } |
|---|
| 1167 | 1090 | |
|---|
| .. | .. |
|---|
| 1252 | 1175 | |
|---|
| 1253 | 1176 | idx = device_links_read_lock(); |
|---|
| 1254 | 1177 | |
|---|
| 1255 | | - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) |
|---|
| 1178 | + list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) |
|---|
| 1256 | 1179 | link->supplier->power.must_resume = true; |
|---|
| 1257 | 1180 | |
|---|
| 1258 | 1181 | device_links_read_unlock(idx); |
|---|
| 1259 | | -} |
|---|
| 1260 | | - |
|---|
| 1261 | | -static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, |
|---|
| 1262 | | - pm_message_t state, |
|---|
| 1263 | | - const char **info_p) |
|---|
| 1264 | | -{ |
|---|
| 1265 | | - pm_callback_t callback; |
|---|
| 1266 | | - const char *info; |
|---|
| 1267 | | - |
|---|
| 1268 | | - if (dev->pm_domain) { |
|---|
| 1269 | | - info = "noirq power domain "; |
|---|
| 1270 | | - callback = pm_noirq_op(&dev->pm_domain->ops, state); |
|---|
| 1271 | | - } else if (dev->type && dev->type->pm) { |
|---|
| 1272 | | - info = "noirq type "; |
|---|
| 1273 | | - callback = pm_noirq_op(dev->type->pm, state); |
|---|
| 1274 | | - } else if (dev->class && dev->class->pm) { |
|---|
| 1275 | | - info = "noirq class "; |
|---|
| 1276 | | - callback = pm_noirq_op(dev->class->pm, state); |
|---|
| 1277 | | - } else if (dev->bus && dev->bus->pm) { |
|---|
| 1278 | | - info = "noirq bus "; |
|---|
| 1279 | | - callback = pm_noirq_op(dev->bus->pm, state); |
|---|
| 1280 | | - } else { |
|---|
| 1281 | | - return NULL; |
|---|
| 1282 | | - } |
|---|
| 1283 | | - |
|---|
| 1284 | | - if (info_p) |
|---|
| 1285 | | - *info_p = info; |
|---|
| 1286 | | - |
|---|
| 1287 | | - return callback; |
|---|
| 1288 | | -} |
|---|
| 1289 | | - |
|---|
| 1290 | | -static bool device_must_resume(struct device *dev, pm_message_t state, |
|---|
| 1291 | | - bool no_subsys_suspend_noirq) |
|---|
| 1292 | | -{ |
|---|
| 1293 | | - pm_message_t resume_msg = resume_event(state); |
|---|
| 1294 | | - |
|---|
| 1295 | | - /* |
|---|
| 1296 | | - * If all of the device driver's "noirq", "late" and "early" callbacks |
|---|
| 1297 | | - * are invoked directly by the core, the decision to allow the device to |
|---|
| 1298 | | - * stay in suspend can be based on its current runtime PM status and its |
|---|
| 1299 | | - * wakeup settings. |
|---|
| 1300 | | - */ |
|---|
| 1301 | | - if (no_subsys_suspend_noirq && |
|---|
| 1302 | | - !dpm_subsys_suspend_late_cb(dev, state, NULL) && |
|---|
| 1303 | | - !dpm_subsys_resume_early_cb(dev, resume_msg, NULL) && |
|---|
| 1304 | | - !dpm_subsys_resume_noirq_cb(dev, resume_msg, NULL)) |
|---|
| 1305 | | - return !pm_runtime_status_suspended(dev) && |
|---|
| 1306 | | - (resume_msg.event != PM_EVENT_RESUME || |
|---|
| 1307 | | - (device_can_wakeup(dev) && !device_may_wakeup(dev))); |
|---|
| 1308 | | - |
|---|
| 1309 | | - /* |
|---|
| 1310 | | - * The only safe strategy here is to require that if the device may not |
|---|
| 1311 | | - * be left in suspend, resume callbacks must be invoked for it. |
|---|
| 1312 | | - */ |
|---|
| 1313 | | - return !dev->power.may_skip_resume; |
|---|
| 1314 | 1182 | } |
|---|
| 1315 | 1183 | |
|---|
| 1316 | 1184 | /** |
|---|
| .. | .. |
|---|
| 1324 | 1192 | */ |
|---|
| 1325 | 1193 | static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) |
|---|
| 1326 | 1194 | { |
|---|
| 1327 | | - pm_callback_t callback; |
|---|
| 1328 | | - const char *info; |
|---|
| 1329 | | - bool no_subsys_cb = false; |
|---|
| 1195 | + pm_callback_t callback = NULL; |
|---|
| 1196 | + const char *info = NULL; |
|---|
| 1330 | 1197 | int error = 0; |
|---|
| 1331 | 1198 | |
|---|
| 1332 | 1199 | TRACE_DEVICE(dev); |
|---|
| .. | .. |
|---|
| 1337 | 1204 | if (async_error) |
|---|
| 1338 | 1205 | goto Complete; |
|---|
| 1339 | 1206 | |
|---|
| 1340 | | - if (pm_wakeup_pending()) { |
|---|
| 1341 | | - async_error = -EBUSY; |
|---|
| 1342 | | - goto Complete; |
|---|
| 1343 | | - } |
|---|
| 1344 | | - |
|---|
| 1345 | 1207 | if (dev->power.syscore || dev->power.direct_complete) |
|---|
| 1346 | 1208 | goto Complete; |
|---|
| 1347 | 1209 | |
|---|
| 1348 | | - callback = dpm_subsys_suspend_noirq_cb(dev, state, &info); |
|---|
| 1210 | + if (dev->pm_domain) { |
|---|
| 1211 | + info = "noirq power domain "; |
|---|
| 1212 | + callback = pm_noirq_op(&dev->pm_domain->ops, state); |
|---|
| 1213 | + } else if (dev->type && dev->type->pm) { |
|---|
| 1214 | + info = "noirq type "; |
|---|
| 1215 | + callback = pm_noirq_op(dev->type->pm, state); |
|---|
| 1216 | + } else if (dev->class && dev->class->pm) { |
|---|
| 1217 | + info = "noirq class "; |
|---|
| 1218 | + callback = pm_noirq_op(dev->class->pm, state); |
|---|
| 1219 | + } else if (dev->bus && dev->bus->pm) { |
|---|
| 1220 | + info = "noirq bus "; |
|---|
| 1221 | + callback = pm_noirq_op(dev->bus->pm, state); |
|---|
| 1222 | + } |
|---|
| 1349 | 1223 | if (callback) |
|---|
| 1350 | 1224 | goto Run; |
|---|
| 1351 | 1225 | |
|---|
| 1352 | | - no_subsys_cb = !dpm_subsys_suspend_late_cb(dev, state, NULL); |
|---|
| 1353 | | - |
|---|
| 1354 | | - if (dev_pm_smart_suspend_and_suspended(dev) && no_subsys_cb) |
|---|
| 1226 | + if (dev_pm_skip_suspend(dev)) |
|---|
| 1355 | 1227 | goto Skip; |
|---|
| 1356 | 1228 | |
|---|
| 1357 | 1229 | if (dev->driver && dev->driver->pm) { |
|---|
| .. | .. |
|---|
| 1363 | 1235 | error = dpm_run_callback(callback, dev, state, info); |
|---|
| 1364 | 1236 | if (error) { |
|---|
| 1365 | 1237 | async_error = error; |
|---|
| 1366 | | - log_suspend_abort_reason("Callback failed on %s in %pS returned %d", |
|---|
| 1367 | | - dev_name(dev), callback, error); |
|---|
| 1238 | + log_suspend_abort_reason("Device %s failed to %s noirq: error %d", |
|---|
| 1239 | + dev_name(dev), pm_verb(state.event), error); |
|---|
| 1368 | 1240 | goto Complete; |
|---|
| 1369 | 1241 | } |
|---|
| 1370 | 1242 | |
|---|
| 1371 | 1243 | Skip: |
|---|
| 1372 | 1244 | dev->power.is_noirq_suspended = true; |
|---|
| 1373 | 1245 | |
|---|
| 1374 | | - if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) { |
|---|
| 1375 | | - dev->power.must_resume = dev->power.must_resume || |
|---|
| 1376 | | - atomic_read(&dev->power.usage_count) > 1 || |
|---|
| 1377 | | - device_must_resume(dev, state, no_subsys_cb); |
|---|
| 1378 | | - } else { |
|---|
| 1246 | + /* |
|---|
| 1247 | + * Skipping the resume of devices that were in use right before the |
|---|
| 1248 | + * system suspend (as indicated by their PM-runtime usage counters) |
|---|
| 1249 | + * would be suboptimal. Also resume them if doing that is not allowed |
|---|
| 1250 | + * to be skipped. |
|---|
| 1251 | + */ |
|---|
| 1252 | + if (atomic_read(&dev->power.usage_count) > 1 || |
|---|
| 1253 | + !(dev_pm_test_driver_flags(dev, DPM_FLAG_MAY_SKIP_RESUME) && |
|---|
| 1254 | + dev->power.may_skip_resume)) |
|---|
| 1379 | 1255 | dev->power.must_resume = true; |
|---|
| 1380 | | - } |
|---|
| 1381 | 1256 | |
|---|
| 1382 | 1257 | if (dev->power.must_resume) |
|---|
| 1383 | 1258 | dpm_superior_set_must_resume(dev); |
|---|
| .. | .. |
|---|
| 1404 | 1279 | |
|---|
| 1405 | 1280 | static int device_suspend_noirq(struct device *dev) |
|---|
| 1406 | 1281 | { |
|---|
| 1407 | | - reinit_completion(&dev->power.completion); |
|---|
| 1408 | | - |
|---|
| 1409 | | - if (is_async(dev)) { |
|---|
| 1410 | | - get_device(dev); |
|---|
| 1411 | | - async_schedule(async_suspend_noirq, dev); |
|---|
| 1282 | + if (dpm_async_fn(dev, async_suspend_noirq)) |
|---|
| 1412 | 1283 | return 0; |
|---|
| 1413 | | - } |
|---|
| 1284 | + |
|---|
| 1414 | 1285 | return __device_suspend_noirq(dev, pm_transition, false); |
|---|
| 1415 | 1286 | } |
|---|
| 1416 | 1287 | |
|---|
| 1417 | | -void dpm_noirq_begin(void) |
|---|
| 1418 | | -{ |
|---|
| 1419 | | - cpuidle_pause(); |
|---|
| 1420 | | - device_wakeup_arm_wake_irqs(); |
|---|
| 1421 | | - suspend_device_irqs(); |
|---|
| 1422 | | -} |
|---|
| 1423 | | - |
|---|
| 1424 | | -int dpm_noirq_suspend_devices(pm_message_t state) |
|---|
| 1288 | +static int dpm_noirq_suspend_devices(pm_message_t state) |
|---|
| 1425 | 1289 | { |
|---|
| 1426 | 1290 | ktime_t starttime = ktime_get(); |
|---|
| 1427 | 1291 | int error = 0; |
|---|
| .. | .. |
|---|
| 1478 | 1342 | { |
|---|
| 1479 | 1343 | int ret; |
|---|
| 1480 | 1344 | |
|---|
| 1481 | | - dpm_noirq_begin(); |
|---|
| 1345 | + cpuidle_pause(); |
|---|
| 1346 | + |
|---|
| 1347 | + device_wakeup_arm_wake_irqs(); |
|---|
| 1348 | + suspend_device_irqs(); |
|---|
| 1349 | + |
|---|
| 1482 | 1350 | ret = dpm_noirq_suspend_devices(state); |
|---|
| 1483 | 1351 | if (ret) |
|---|
| 1484 | 1352 | dpm_resume_noirq(resume_event(state)); |
|---|
| .. | .. |
|---|
| 1501 | 1369 | spin_unlock_irq(&parent->power.lock); |
|---|
| 1502 | 1370 | } |
|---|
| 1503 | 1371 | |
|---|
| 1504 | | -static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, |
|---|
| 1505 | | - pm_message_t state, |
|---|
| 1506 | | - const char **info_p) |
|---|
| 1507 | | -{ |
|---|
| 1508 | | - pm_callback_t callback; |
|---|
| 1509 | | - const char *info; |
|---|
| 1510 | | - |
|---|
| 1511 | | - if (dev->pm_domain) { |
|---|
| 1512 | | - info = "late power domain "; |
|---|
| 1513 | | - callback = pm_late_early_op(&dev->pm_domain->ops, state); |
|---|
| 1514 | | - } else if (dev->type && dev->type->pm) { |
|---|
| 1515 | | - info = "late type "; |
|---|
| 1516 | | - callback = pm_late_early_op(dev->type->pm, state); |
|---|
| 1517 | | - } else if (dev->class && dev->class->pm) { |
|---|
| 1518 | | - info = "late class "; |
|---|
| 1519 | | - callback = pm_late_early_op(dev->class->pm, state); |
|---|
| 1520 | | - } else if (dev->bus && dev->bus->pm) { |
|---|
| 1521 | | - info = "late bus "; |
|---|
| 1522 | | - callback = pm_late_early_op(dev->bus->pm, state); |
|---|
| 1523 | | - } else { |
|---|
| 1524 | | - return NULL; |
|---|
| 1525 | | - } |
|---|
| 1526 | | - |
|---|
| 1527 | | - if (info_p) |
|---|
| 1528 | | - *info_p = info; |
|---|
| 1529 | | - |
|---|
| 1530 | | - return callback; |
|---|
| 1531 | | -} |
|---|
| 1532 | | - |
|---|
| 1533 | 1372 | /** |
|---|
| 1534 | 1373 | * __device_suspend_late - Execute a "late suspend" callback for given device. |
|---|
| 1535 | 1374 | * @dev: Device to handle. |
|---|
| .. | .. |
|---|
| 1540 | 1379 | */ |
|---|
| 1541 | 1380 | static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) |
|---|
| 1542 | 1381 | { |
|---|
| 1543 | | - pm_callback_t callback; |
|---|
| 1544 | | - const char *info; |
|---|
| 1382 | + pm_callback_t callback = NULL; |
|---|
| 1383 | + const char *info = NULL; |
|---|
| 1545 | 1384 | int error = 0; |
|---|
| 1546 | 1385 | |
|---|
| 1547 | 1386 | TRACE_DEVICE(dev); |
|---|
| .. | .. |
|---|
| 1562 | 1401 | if (dev->power.syscore || dev->power.direct_complete) |
|---|
| 1563 | 1402 | goto Complete; |
|---|
| 1564 | 1403 | |
|---|
| 1565 | | - callback = dpm_subsys_suspend_late_cb(dev, state, &info); |
|---|
| 1404 | + if (dev->pm_domain) { |
|---|
| 1405 | + info = "late power domain "; |
|---|
| 1406 | + callback = pm_late_early_op(&dev->pm_domain->ops, state); |
|---|
| 1407 | + } else if (dev->type && dev->type->pm) { |
|---|
| 1408 | + info = "late type "; |
|---|
| 1409 | + callback = pm_late_early_op(dev->type->pm, state); |
|---|
| 1410 | + } else if (dev->class && dev->class->pm) { |
|---|
| 1411 | + info = "late class "; |
|---|
| 1412 | + callback = pm_late_early_op(dev->class->pm, state); |
|---|
| 1413 | + } else if (dev->bus && dev->bus->pm) { |
|---|
| 1414 | + info = "late bus "; |
|---|
| 1415 | + callback = pm_late_early_op(dev->bus->pm, state); |
|---|
| 1416 | + } |
|---|
| 1566 | 1417 | if (callback) |
|---|
| 1567 | 1418 | goto Run; |
|---|
| 1568 | 1419 | |
|---|
| 1569 | | - if (dev_pm_smart_suspend_and_suspended(dev) && |
|---|
| 1570 | | - !dpm_subsys_suspend_noirq_cb(dev, state, NULL)) |
|---|
| 1420 | + if (dev_pm_skip_suspend(dev)) |
|---|
| 1571 | 1421 | goto Skip; |
|---|
| 1572 | 1422 | |
|---|
| 1573 | 1423 | if (dev->driver && dev->driver->pm) { |
|---|
| .. | .. |
|---|
| 1579 | 1429 | error = dpm_run_callback(callback, dev, state, info); |
|---|
| 1580 | 1430 | if (error) { |
|---|
| 1581 | 1431 | async_error = error; |
|---|
| 1582 | | - log_suspend_abort_reason("Callback failed on %s in %pS returned %d", |
|---|
| 1583 | | - dev_name(dev), callback, error); |
|---|
| 1432 | + log_suspend_abort_reason("Device %s failed to %s late: error %d", |
|---|
| 1433 | + dev_name(dev), pm_verb(state.event), error); |
|---|
| 1584 | 1434 | goto Complete; |
|---|
| 1585 | 1435 | } |
|---|
| 1586 | 1436 | dpm_propagate_wakeup_to_parent(dev); |
|---|
| .. | .. |
|---|
| 1609 | 1459 | |
|---|
| 1610 | 1460 | static int device_suspend_late(struct device *dev) |
|---|
| 1611 | 1461 | { |
|---|
| 1612 | | - reinit_completion(&dev->power.completion); |
|---|
| 1613 | | - |
|---|
| 1614 | | - if (is_async(dev)) { |
|---|
| 1615 | | - get_device(dev); |
|---|
| 1616 | | - async_schedule(async_suspend_late, dev); |
|---|
| 1462 | + if (dpm_async_fn(dev, async_suspend_late)) |
|---|
| 1617 | 1463 | return 0; |
|---|
| 1618 | | - } |
|---|
| 1619 | 1464 | |
|---|
| 1620 | 1465 | return __device_suspend_late(dev, pm_transition, false); |
|---|
| 1621 | 1466 | } |
|---|
| .. | .. |
|---|
| 1677 | 1522 | */ |
|---|
| 1678 | 1523 | int dpm_suspend_end(pm_message_t state) |
|---|
| 1679 | 1524 | { |
|---|
| 1680 | | - int error = dpm_suspend_late(state); |
|---|
| 1525 | + ktime_t starttime = ktime_get(); |
|---|
| 1526 | + int error; |
|---|
| 1527 | + |
|---|
| 1528 | + error = dpm_suspend_late(state); |
|---|
| 1681 | 1529 | if (error) |
|---|
| 1682 | | - return error; |
|---|
| 1530 | + goto out; |
|---|
| 1683 | 1531 | |
|---|
| 1684 | 1532 | error = dpm_suspend_noirq(state); |
|---|
| 1685 | | - if (error) { |
|---|
| 1533 | + if (error) |
|---|
| 1686 | 1534 | dpm_resume_early(resume_event(state)); |
|---|
| 1687 | | - return error; |
|---|
| 1688 | | - } |
|---|
| 1689 | 1535 | |
|---|
| 1690 | | - return 0; |
|---|
| 1536 | +out: |
|---|
| 1537 | + dpm_show_time(starttime, state, error, "end"); |
|---|
| 1538 | + return error; |
|---|
| 1691 | 1539 | } |
|---|
| 1692 | 1540 | EXPORT_SYMBOL_GPL(dpm_suspend_end); |
|---|
| 1693 | 1541 | |
|---|
| .. | .. |
|---|
| 1730 | 1578 | |
|---|
| 1731 | 1579 | idx = device_links_read_lock(); |
|---|
| 1732 | 1580 | |
|---|
| 1733 | | - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) { |
|---|
| 1581 | + list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) { |
|---|
| 1734 | 1582 | spin_lock_irq(&link->supplier->power.lock); |
|---|
| 1735 | 1583 | link->supplier->power.direct_complete = false; |
|---|
| 1736 | 1584 | spin_unlock_irq(&link->supplier->power.lock); |
|---|
| .. | .. |
|---|
| 1791 | 1639 | if (dev->power.direct_complete) { |
|---|
| 1792 | 1640 | if (pm_runtime_status_suspended(dev)) { |
|---|
| 1793 | 1641 | pm_runtime_disable(dev); |
|---|
| 1794 | | - if (pm_runtime_status_suspended(dev)) |
|---|
| 1642 | + if (pm_runtime_status_suspended(dev)) { |
|---|
| 1643 | + pm_dev_dbg(dev, state, "direct-complete "); |
|---|
| 1795 | 1644 | goto Complete; |
|---|
| 1645 | + } |
|---|
| 1796 | 1646 | |
|---|
| 1797 | 1647 | pm_runtime_enable(dev); |
|---|
| 1798 | 1648 | } |
|---|
| 1799 | 1649 | dev->power.direct_complete = false; |
|---|
| 1800 | 1650 | } |
|---|
| 1801 | 1651 | |
|---|
| 1802 | | - dev->power.may_skip_resume = false; |
|---|
| 1803 | | - dev->power.must_resume = false; |
|---|
| 1652 | + dev->power.may_skip_resume = true; |
|---|
| 1653 | + dev->power.must_resume = !dev_pm_test_driver_flags(dev, DPM_FLAG_MAY_SKIP_RESUME); |
|---|
| 1804 | 1654 | |
|---|
| 1805 | 1655 | dpm_watchdog_set(&wd, dev); |
|---|
| 1806 | 1656 | device_lock(dev); |
|---|
| .. | .. |
|---|
| 1852 | 1702 | dpm_propagate_wakeup_to_parent(dev); |
|---|
| 1853 | 1703 | dpm_clear_superiors_direct_complete(dev); |
|---|
| 1854 | 1704 | } else { |
|---|
| 1855 | | - log_suspend_abort_reason("Callback failed on %s in %pS returned %d", |
|---|
| 1856 | | - dev_name(dev), callback, error); |
|---|
| 1705 | + log_suspend_abort_reason("Device %s failed to %s: error %d", |
|---|
| 1706 | + dev_name(dev), pm_verb(state.event), error); |
|---|
| 1857 | 1707 | } |
|---|
| 1858 | 1708 | |
|---|
| 1859 | 1709 | device_unlock(dev); |
|---|
| .. | .. |
|---|
| 1884 | 1734 | |
|---|
| 1885 | 1735 | static int device_suspend(struct device *dev) |
|---|
| 1886 | 1736 | { |
|---|
| 1887 | | - reinit_completion(&dev->power.completion); |
|---|
| 1888 | | - |
|---|
| 1889 | | - if (is_async(dev)) { |
|---|
| 1890 | | - get_device(dev); |
|---|
| 1891 | | - async_schedule(async_suspend, dev); |
|---|
| 1737 | + if (dpm_async_fn(dev, async_suspend)) |
|---|
| 1892 | 1738 | return 0; |
|---|
| 1893 | | - } |
|---|
| 1894 | 1739 | |
|---|
| 1895 | 1740 | return __device_suspend(dev, pm_transition, false); |
|---|
| 1896 | 1741 | } |
|---|
| .. | .. |
|---|
| 1907 | 1752 | trace_suspend_resume(TPS("dpm_suspend"), state.event, true); |
|---|
| 1908 | 1753 | might_sleep(); |
|---|
| 1909 | 1754 | |
|---|
| 1755 | + devfreq_suspend(); |
|---|
| 1910 | 1756 | cpufreq_suspend(); |
|---|
| 1911 | 1757 | |
|---|
| 1912 | 1758 | mutex_lock(&dpm_list_mtx); |
|---|
| .. | .. |
|---|
| 1959 | 1805 | int (*callback)(struct device *) = NULL; |
|---|
| 1960 | 1806 | int ret = 0; |
|---|
| 1961 | 1807 | |
|---|
| 1962 | | - if (dev->power.syscore) |
|---|
| 1963 | | - return 0; |
|---|
| 1964 | | - |
|---|
| 1965 | | - WARN_ON(!pm_runtime_enabled(dev) && |
|---|
| 1966 | | - dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | |
|---|
| 1967 | | - DPM_FLAG_LEAVE_SUSPENDED)); |
|---|
| 1968 | | - |
|---|
| 1969 | 1808 | /* |
|---|
| 1970 | 1809 | * If a device's parent goes into runtime suspend at the wrong time, |
|---|
| 1971 | 1810 | * it won't be possible to resume the device. To prevent this we |
|---|
| .. | .. |
|---|
| 1973 | 1812 | * it again during the complete phase. |
|---|
| 1974 | 1813 | */ |
|---|
| 1975 | 1814 | pm_runtime_get_noresume(dev); |
|---|
| 1815 | + |
|---|
| 1816 | + if (dev->power.syscore) |
|---|
| 1817 | + return 0; |
|---|
| 1976 | 1818 | |
|---|
| 1977 | 1819 | device_lock(dev); |
|---|
| 1978 | 1820 | |
|---|
| .. | .. |
|---|
| 2013 | 1855 | */ |
|---|
| 2014 | 1856 | spin_lock_irq(&dev->power.lock); |
|---|
| 2015 | 1857 | dev->power.direct_complete = state.event == PM_EVENT_SUSPEND && |
|---|
| 2016 | | - ((pm_runtime_suspended(dev) && ret > 0) || |
|---|
| 2017 | | - dev->power.no_pm_callbacks) && |
|---|
| 2018 | | - !dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP); |
|---|
| 1858 | + (ret > 0 || dev->power.no_pm_callbacks) && |
|---|
| 1859 | + !dev_pm_test_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE); |
|---|
| 2019 | 1860 | spin_unlock_irq(&dev->power.lock); |
|---|
| 2020 | 1861 | return 0; |
|---|
| 2021 | 1862 | } |
|---|
| .. | .. |
|---|
| 2065 | 1906 | error = 0; |
|---|
| 2066 | 1907 | continue; |
|---|
| 2067 | 1908 | } |
|---|
| 2068 | | - printk(KERN_INFO "PM: Device %s not prepared " |
|---|
| 2069 | | - "for power transition: code %d\n", |
|---|
| 1909 | + pr_info("Device %s not prepared for power transition: code %d\n", |
|---|
| 2070 | 1910 | dev_name(dev), error); |
|---|
| 2071 | 1911 | log_suspend_abort_reason("Device %s not prepared for power transition: code %d", |
|---|
| 2072 | 1912 | dev_name(dev), error); |
|---|
| .. | .. |
|---|
| 2093 | 1933 | */ |
|---|
| 2094 | 1934 | int dpm_suspend_start(pm_message_t state) |
|---|
| 2095 | 1935 | { |
|---|
| 1936 | + ktime_t starttime = ktime_get(); |
|---|
| 2096 | 1937 | int error; |
|---|
| 2097 | 1938 | |
|---|
| 2098 | 1939 | error = dpm_prepare(state); |
|---|
| .. | .. |
|---|
| 2101 | 1942 | dpm_save_failed_step(SUSPEND_PREPARE); |
|---|
| 2102 | 1943 | } else |
|---|
| 2103 | 1944 | error = dpm_suspend(state); |
|---|
| 1945 | + dpm_show_time(starttime, state, error, "start"); |
|---|
| 2104 | 1946 | return error; |
|---|
| 2105 | 1947 | } |
|---|
| 2106 | 1948 | EXPORT_SYMBOL_GPL(dpm_suspend_start); |
|---|
| .. | .. |
|---|
| 2108 | 1950 | void __suspend_report_result(const char *function, void *fn, int ret) |
|---|
| 2109 | 1951 | { |
|---|
| 2110 | 1952 | if (ret) |
|---|
| 2111 | | - printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret); |
|---|
| 1953 | + pr_err("%s(): %pS returns %d\n", function, fn, ret); |
|---|
| 2112 | 1954 | } |
|---|
| 2113 | 1955 | EXPORT_SYMBOL_GPL(__suspend_report_result); |
|---|
| 2114 | 1956 | |
|---|
| 2115 | 1957 | /** |
|---|
| 2116 | 1958 | * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete. |
|---|
| 2117 | | - * @dev: Device to wait for. |
|---|
| 2118 | 1959 | * @subordinate: Device that needs to wait for @dev. |
|---|
| 1960 | + * @dev: Device to wait for. |
|---|
| 2119 | 1961 | */ |
|---|
| 2120 | 1962 | int device_pm_wait_for_dev(struct device *subordinate, struct device *dev) |
|---|
| 2121 | 1963 | { |
|---|
| .. | .. |
|---|
| 2163 | 2005 | |
|---|
| 2164 | 2006 | void device_pm_check_callbacks(struct device *dev) |
|---|
| 2165 | 2007 | { |
|---|
| 2166 | | - spin_lock_irq(&dev->power.lock); |
|---|
| 2008 | + unsigned long flags; |
|---|
| 2009 | + |
|---|
| 2010 | + spin_lock_irqsave(&dev->power.lock, flags); |
|---|
| 2167 | 2011 | dev->power.no_pm_callbacks = |
|---|
| 2168 | 2012 | (!dev->bus || (pm_ops_is_empty(dev->bus->pm) && |
|---|
| 2169 | 2013 | !dev->bus->suspend && !dev->bus->resume)) && |
|---|
| .. | .. |
|---|
| 2172 | 2016 | (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) && |
|---|
| 2173 | 2017 | (!dev->driver || (pm_ops_is_empty(dev->driver->pm) && |
|---|
| 2174 | 2018 | !dev->driver->suspend && !dev->driver->resume)); |
|---|
| 2175 | | - spin_unlock_irq(&dev->power.lock); |
|---|
| 2019 | + spin_unlock_irqrestore(&dev->power.lock, flags); |
|---|
| 2176 | 2020 | } |
|---|
| 2177 | 2021 | |
|---|
| 2178 | | -bool dev_pm_smart_suspend_and_suspended(struct device *dev) |
|---|
| 2022 | +bool dev_pm_skip_suspend(struct device *dev) |
|---|
| 2179 | 2023 | { |
|---|
| 2180 | 2024 | return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) && |
|---|
| 2181 | 2025 | pm_runtime_status_suspended(dev); |
|---|