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