Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

PM: sleep: core: Fix runtime PM enabling in device_resume_early()

Runtime PM should only be enabled in device_resume_early() if it has
been disabled for the given device by device_suspend_late(). Otherwise,
it may cause runtime PM callbacks to run prematurely in some cases
which leads to further functional issues.

Make two changes to address this problem.

First, reorder device_suspend_late() to only disable runtime PM for a
device when it is going to look for the device's callback or if the
device is a "syscore" one. In all of the other cases, disabling runtime
PM for the device is not in fact necessary. However, if the device's
callback returns an error and the power.is_late_suspended flag is not
going to be set, enable runtime PM so it only remains disabled when
power.is_late_suspended is set.

Second, make device_resume_early() only enable runtime PM for the
devices with the power.is_late_suspended flag set.

Fixes: 443046d1ad66 ("PM: sleep: Make suspend of devices more asynchronous")
Reported-by: Rose Wu <ya-jou.wu@mediatek.com>
Closes: https://lore.kernel.org/linux-pm/70b25dca6f8c2756d78f076f4a7dee7edaaffc33.camel@mediatek.com/
Cc: 6.16+ <stable@vger.kernel.org> # 6.16+
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/12784270.O9o76ZdvQC@rafael.j.wysocki

+16 -9
+16 -9
drivers/base/power/main.c
··· 888 888 TRACE_DEVICE(dev); 889 889 TRACE_RESUME(0); 890 890 891 - if (dev->power.syscore || dev->power.direct_complete) 891 + if (dev->power.direct_complete) 892 892 goto Out; 893 893 894 894 if (!dev->power.is_late_suspended) 895 895 goto Out; 896 + 897 + if (dev->power.syscore) 898 + goto Skip; 896 899 897 900 if (!dpm_wait_for_superior(dev, async)) 898 901 goto Out; ··· 929 926 930 927 Skip: 931 928 dev->power.is_late_suspended = false; 929 + pm_runtime_enable(dev); 932 930 933 931 Out: 934 932 TRACE_RESUME(error); 935 933 936 - pm_runtime_enable(dev); 937 934 complete_all(&dev->power.completion); 938 935 939 936 if (error) { ··· 1618 1615 TRACE_DEVICE(dev); 1619 1616 TRACE_SUSPEND(0); 1620 1617 1621 - /* 1622 - * Disable runtime PM for the device without checking if there is a 1623 - * pending resume request for it. 1624 - */ 1625 - __pm_runtime_disable(dev, false); 1626 - 1627 1618 dpm_wait_for_subordinate(dev, async); 1628 1619 1629 1620 if (READ_ONCE(async_error)) ··· 1628 1631 goto Complete; 1629 1632 } 1630 1633 1631 - if (dev->power.syscore || dev->power.direct_complete) 1634 + if (dev->power.direct_complete) 1632 1635 goto Complete; 1636 + 1637 + /* 1638 + * Disable runtime PM for the device without checking if there is a 1639 + * pending resume request for it. 1640 + */ 1641 + __pm_runtime_disable(dev, false); 1642 + 1643 + if (dev->power.syscore) 1644 + goto Skip; 1633 1645 1634 1646 if (dev->pm_domain) { 1635 1647 info = "late power domain "; ··· 1670 1664 WRITE_ONCE(async_error, error); 1671 1665 dpm_save_failed_dev(dev_name(dev)); 1672 1666 pm_dev_err(dev, state, async ? " async late" : " late", error); 1667 + pm_runtime_enable(dev); 1673 1668 goto Complete; 1674 1669 } 1675 1670 dpm_propagate_wakeup_to_parent(dev);