Loading Documentation/power/runtime_pm.rst +10 −4 Original line number Diff line number Diff line Loading @@ -265,6 +265,10 @@ defined in include/linux/pm.h: RPM_SUSPENDED, which means that each device is initially regarded by the PM core as 'suspended', regardless of its real hardware status `enum rpm_status last_status;` - the last runtime PM status of the device captured before disabling runtime PM for it (invalid initially and when disable_depth is 0) `unsigned int runtime_auto;` - if set, indicates that the user space has allowed the device driver to power manage the device at run time via the /sys/devices/.../power/control Loading Loading @@ -333,10 +337,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: `int pm_runtime_resume(struct device *dev);` - execute the subsystem-level resume callback for the device; returns 0 on success, 1 if the device's runtime PM status was already 'active' or error code on failure, where -EAGAIN means it may be safe to attempt to resume the device again in future, but 'power.runtime_error' should be checked additionally, and -EACCES means that 'power.disable_depth' is success, 1 if the device's runtime PM status is already 'active' (also if 'power.disable_depth' is nonzero, but the status was 'active' when it was changing from 0 to 1) or error code on failure, where -EAGAIN means it may be safe to attempt to resume the device again in future, but 'power.runtime_error' should be checked additionally, and -EACCES means that the callback could not be run, because 'power.disable_depth' was different from 0 `int pm_runtime_resume_and_get(struct device *dev);` Loading drivers/base/core.c +1 −2 Original line number Diff line number Diff line Loading @@ -485,8 +485,7 @@ static void device_link_release_fn(struct work_struct *work) /* Ensure that all references to the link object have been dropped. */ device_link_synchronize_removal(); while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put(link->supplier); pm_runtime_release_supplier(link, true); put_device(link->consumer); put_device(link->supplier); Loading drivers/base/power/runtime.c +55 −31 Original line number Diff line number Diff line Loading @@ -305,19 +305,40 @@ static int rpm_get_suppliers(struct device *dev) return 0; } /** * pm_runtime_release_supplier - Drop references to device link's supplier. * @link: Target device link. * @check_idle: Whether or not to check if the supplier device is idle. * * Drop all runtime PM references associated with @link to its supplier device * and if @check_idle is set, check if that device is idle (and so it can be * suspended). */ void pm_runtime_release_supplier(struct device_link *link, bool check_idle) { struct device *supplier = link->supplier; /* * The additional power.usage_count check is a safety net in case * the rpm_active refcount becomes saturated, in which case * refcount_dec_not_one() would return true forever, but it is not * strictly necessary. */ while (refcount_dec_not_one(&link->rpm_active) && atomic_read(&supplier->power.usage_count) > 0) pm_runtime_put_noidle(supplier); if (check_idle) pm_request_idle(supplier); } static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend) { struct device_link *link; list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, device_links_read_lock_held()) { while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put_noidle(link->supplier); if (try_to_suspend) pm_request_idle(link->supplier); } device_links_read_lock_held()) pm_runtime_release_supplier(link, try_to_suspend); } static void rpm_put_suppliers(struct device *dev) Loading Loading @@ -742,13 +763,15 @@ static int rpm_resume(struct device *dev, int rpmflags) trace_rpm_resume_rcuidle(dev, rpmflags); repeat: if (dev->power.runtime_error) if (dev->power.runtime_error) { retval = -EINVAL; else if (dev->power.disable_depth == 1 && dev->power.is_suspended && dev->power.runtime_status == RPM_ACTIVE) } else if (dev->power.disable_depth > 0) { if (dev->power.runtime_status == RPM_ACTIVE && dev->power.last_status == RPM_ACTIVE) retval = 1; else if (dev->power.disable_depth > 0) else retval = -EACCES; } if (retval) goto out; Loading Loading @@ -1410,8 +1433,10 @@ void __pm_runtime_disable(struct device *dev, bool check_resume) /* Update time accounting before disabling PM-runtime. */ update_pm_runtime_accounting(dev); if (!dev->power.disable_depth++) if (!dev->power.disable_depth++) { __pm_runtime_barrier(dev); dev->power.last_status = dev->power.runtime_status; } out: spin_unlock_irq(&dev->power.lock); Loading @@ -1428,23 +1453,23 @@ void pm_runtime_enable(struct device *dev) spin_lock_irqsave(&dev->power.lock, flags); if (dev->power.disable_depth > 0) { dev->power.disable_depth--; /* About to enable runtime pm, set accounting_timestamp to now */ if (!dev->power.disable_depth) dev->power.accounting_timestamp = ktime_get_mono_fast_ns(); } else { if (!dev->power.disable_depth) { dev_warn(dev, "Unbalanced %s!\n", __func__); goto out; } WARN(!dev->power.disable_depth && dev->power.runtime_status == RPM_SUSPENDED && if (--dev->power.disable_depth > 0) goto out; dev->power.last_status = RPM_INVALID; dev->power.accounting_timestamp = ktime_get_mono_fast_ns(); if (dev->power.runtime_status == RPM_SUSPENDED && !dev->power.ignore_children && atomic_read(&dev->power.child_count) > 0, "Enabling runtime PM for inactive device (%s) with active children\n", dev_name(dev)); atomic_read(&dev->power.child_count) > 0) dev_warn(dev, "Enabling runtime PM for inactive device with active children\n"); out: spin_unlock_irqrestore(&dev->power.lock, flags); } EXPORT_SYMBOL_GPL(pm_runtime_enable); Loading Loading @@ -1640,6 +1665,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend); void pm_runtime_init(struct device *dev) { dev->power.runtime_status = RPM_SUSPENDED; dev->power.last_status = RPM_INVALID; dev->power.idle_notification = false; dev->power.disable_depth = 1; Loading Loading @@ -1772,9 +1798,7 @@ void pm_runtime_drop_link(struct device_link *link) return; pm_runtime_drop_link_count(link->consumer); while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put(link->supplier); pm_runtime_release_supplier(link, true); } static bool pm_runtime_need_not_resume(struct device *dev) Loading drivers/mmc/host/jz4740_mmc.c +4 −4 Original line number Diff line number Diff line Loading @@ -1103,17 +1103,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev) return 0; } static int __maybe_unused jz4740_mmc_suspend(struct device *dev) static int jz4740_mmc_suspend(struct device *dev) { return pinctrl_pm_select_sleep_state(dev); } static int __maybe_unused jz4740_mmc_resume(struct device *dev) static int jz4740_mmc_resume(struct device *dev) { return pinctrl_select_default_state(dev); } static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, jz4740_mmc_resume); static struct platform_driver jz4740_mmc_driver = { Loading @@ -1123,7 +1123,7 @@ static struct platform_driver jz4740_mmc_driver = { .name = "jz4740-mmc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(jz4740_mmc_of_match), .pm = pm_ptr(&jz4740_mmc_pm_ops), .pm = pm_sleep_ptr(&jz4740_mmc_pm_ops), }, }; Loading drivers/mmc/host/mxcmmc.c +2 −4 Original line number Diff line number Diff line Loading @@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev) return 0; } #ifdef CONFIG_PM_SLEEP static int mxcmci_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); Loading @@ -1210,9 +1209,8 @@ static int mxcmci_resume(struct device *dev) return ret; } #endif static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, Loading @@ -1220,7 +1218,7 @@ static struct platform_driver mxcmci_driver = { .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &mxcmci_pm_ops, .pm = pm_sleep_ptr(&mxcmci_pm_ops), .of_match_table = mxcmci_of_match, } }; Loading Loading
Documentation/power/runtime_pm.rst +10 −4 Original line number Diff line number Diff line Loading @@ -265,6 +265,10 @@ defined in include/linux/pm.h: RPM_SUSPENDED, which means that each device is initially regarded by the PM core as 'suspended', regardless of its real hardware status `enum rpm_status last_status;` - the last runtime PM status of the device captured before disabling runtime PM for it (invalid initially and when disable_depth is 0) `unsigned int runtime_auto;` - if set, indicates that the user space has allowed the device driver to power manage the device at run time via the /sys/devices/.../power/control Loading Loading @@ -333,10 +337,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: `int pm_runtime_resume(struct device *dev);` - execute the subsystem-level resume callback for the device; returns 0 on success, 1 if the device's runtime PM status was already 'active' or error code on failure, where -EAGAIN means it may be safe to attempt to resume the device again in future, but 'power.runtime_error' should be checked additionally, and -EACCES means that 'power.disable_depth' is success, 1 if the device's runtime PM status is already 'active' (also if 'power.disable_depth' is nonzero, but the status was 'active' when it was changing from 0 to 1) or error code on failure, where -EAGAIN means it may be safe to attempt to resume the device again in future, but 'power.runtime_error' should be checked additionally, and -EACCES means that the callback could not be run, because 'power.disable_depth' was different from 0 `int pm_runtime_resume_and_get(struct device *dev);` Loading
drivers/base/core.c +1 −2 Original line number Diff line number Diff line Loading @@ -485,8 +485,7 @@ static void device_link_release_fn(struct work_struct *work) /* Ensure that all references to the link object have been dropped. */ device_link_synchronize_removal(); while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put(link->supplier); pm_runtime_release_supplier(link, true); put_device(link->consumer); put_device(link->supplier); Loading
drivers/base/power/runtime.c +55 −31 Original line number Diff line number Diff line Loading @@ -305,19 +305,40 @@ static int rpm_get_suppliers(struct device *dev) return 0; } /** * pm_runtime_release_supplier - Drop references to device link's supplier. * @link: Target device link. * @check_idle: Whether or not to check if the supplier device is idle. * * Drop all runtime PM references associated with @link to its supplier device * and if @check_idle is set, check if that device is idle (and so it can be * suspended). */ void pm_runtime_release_supplier(struct device_link *link, bool check_idle) { struct device *supplier = link->supplier; /* * The additional power.usage_count check is a safety net in case * the rpm_active refcount becomes saturated, in which case * refcount_dec_not_one() would return true forever, but it is not * strictly necessary. */ while (refcount_dec_not_one(&link->rpm_active) && atomic_read(&supplier->power.usage_count) > 0) pm_runtime_put_noidle(supplier); if (check_idle) pm_request_idle(supplier); } static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend) { struct device_link *link; list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, device_links_read_lock_held()) { while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put_noidle(link->supplier); if (try_to_suspend) pm_request_idle(link->supplier); } device_links_read_lock_held()) pm_runtime_release_supplier(link, try_to_suspend); } static void rpm_put_suppliers(struct device *dev) Loading Loading @@ -742,13 +763,15 @@ static int rpm_resume(struct device *dev, int rpmflags) trace_rpm_resume_rcuidle(dev, rpmflags); repeat: if (dev->power.runtime_error) if (dev->power.runtime_error) { retval = -EINVAL; else if (dev->power.disable_depth == 1 && dev->power.is_suspended && dev->power.runtime_status == RPM_ACTIVE) } else if (dev->power.disable_depth > 0) { if (dev->power.runtime_status == RPM_ACTIVE && dev->power.last_status == RPM_ACTIVE) retval = 1; else if (dev->power.disable_depth > 0) else retval = -EACCES; } if (retval) goto out; Loading Loading @@ -1410,8 +1433,10 @@ void __pm_runtime_disable(struct device *dev, bool check_resume) /* Update time accounting before disabling PM-runtime. */ update_pm_runtime_accounting(dev); if (!dev->power.disable_depth++) if (!dev->power.disable_depth++) { __pm_runtime_barrier(dev); dev->power.last_status = dev->power.runtime_status; } out: spin_unlock_irq(&dev->power.lock); Loading @@ -1428,23 +1453,23 @@ void pm_runtime_enable(struct device *dev) spin_lock_irqsave(&dev->power.lock, flags); if (dev->power.disable_depth > 0) { dev->power.disable_depth--; /* About to enable runtime pm, set accounting_timestamp to now */ if (!dev->power.disable_depth) dev->power.accounting_timestamp = ktime_get_mono_fast_ns(); } else { if (!dev->power.disable_depth) { dev_warn(dev, "Unbalanced %s!\n", __func__); goto out; } WARN(!dev->power.disable_depth && dev->power.runtime_status == RPM_SUSPENDED && if (--dev->power.disable_depth > 0) goto out; dev->power.last_status = RPM_INVALID; dev->power.accounting_timestamp = ktime_get_mono_fast_ns(); if (dev->power.runtime_status == RPM_SUSPENDED && !dev->power.ignore_children && atomic_read(&dev->power.child_count) > 0, "Enabling runtime PM for inactive device (%s) with active children\n", dev_name(dev)); atomic_read(&dev->power.child_count) > 0) dev_warn(dev, "Enabling runtime PM for inactive device with active children\n"); out: spin_unlock_irqrestore(&dev->power.lock, flags); } EXPORT_SYMBOL_GPL(pm_runtime_enable); Loading Loading @@ -1640,6 +1665,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend); void pm_runtime_init(struct device *dev) { dev->power.runtime_status = RPM_SUSPENDED; dev->power.last_status = RPM_INVALID; dev->power.idle_notification = false; dev->power.disable_depth = 1; Loading Loading @@ -1772,9 +1798,7 @@ void pm_runtime_drop_link(struct device_link *link) return; pm_runtime_drop_link_count(link->consumer); while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put(link->supplier); pm_runtime_release_supplier(link, true); } static bool pm_runtime_need_not_resume(struct device *dev) Loading
drivers/mmc/host/jz4740_mmc.c +4 −4 Original line number Diff line number Diff line Loading @@ -1103,17 +1103,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev) return 0; } static int __maybe_unused jz4740_mmc_suspend(struct device *dev) static int jz4740_mmc_suspend(struct device *dev) { return pinctrl_pm_select_sleep_state(dev); } static int __maybe_unused jz4740_mmc_resume(struct device *dev) static int jz4740_mmc_resume(struct device *dev) { return pinctrl_select_default_state(dev); } static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, jz4740_mmc_resume); static struct platform_driver jz4740_mmc_driver = { Loading @@ -1123,7 +1123,7 @@ static struct platform_driver jz4740_mmc_driver = { .name = "jz4740-mmc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(jz4740_mmc_of_match), .pm = pm_ptr(&jz4740_mmc_pm_ops), .pm = pm_sleep_ptr(&jz4740_mmc_pm_ops), }, }; Loading
drivers/mmc/host/mxcmmc.c +2 −4 Original line number Diff line number Diff line Loading @@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev) return 0; } #ifdef CONFIG_PM_SLEEP static int mxcmci_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); Loading @@ -1210,9 +1209,8 @@ static int mxcmci_resume(struct device *dev) return ret; } #endif static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, Loading @@ -1220,7 +1218,7 @@ static struct platform_driver mxcmci_driver = { .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &mxcmci_pm_ops, .pm = pm_sleep_ptr(&mxcmci_pm_ops), .of_match_table = mxcmci_of_match, } }; Loading