Loading Documentation/power/runtime_pm.txt +12 −7 Original line number Diff line number Diff line Loading @@ -43,13 +43,18 @@ struct dev_pm_ops { ... }; The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are executed by the PM core for either the device type, or the class (if the device type's struct dev_pm_ops object does not exist), or the bus type (if the device type's and class' struct dev_pm_ops objects do not exist) of the given device (this allows device types to override callbacks provided by bus types or classes if necessary). The bus type, device type and class callbacks are referred to as subsystem-level callbacks in what follows. The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are executed by the PM core for either the power domain, or the device type (if the device power domain's struct dev_pm_ops does not exist), or the class (if the device power domain's and type's struct dev_pm_ops object does not exist), or the bus type (if the device power domain's, type's and class' struct dev_pm_ops objects do not exist) of the given device, so the priority order of callbacks from high to low is that power domain callbacks, device type callbacks, class callbacks and bus type callbacks, and the high priority one will take precedence over low priority one. The bus type, device type and class callbacks are referred to as subsystem-level callbacks in what follows, and generally speaking, the power domain callbacks are used for representing power domains within a SoC. By default, the callbacks are always invoked in process context with interrupts enabled. However, subsystems can use the pm_runtime_irq_safe() helper function Loading drivers/base/power/runtime.c +18 −15 Original line number Diff line number Diff line Loading @@ -286,14 +286,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) * @dev: Device to suspend. * @rpmflags: Flag bits. * * Check if the device's runtime PM status allows it to be suspended. If * another suspend has been started earlier, either return immediately or wait * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags. Cancel a * pending idle notification. If the RPM_ASYNC flag is set then queue a * suspend request; otherwise run the ->runtime_suspend() callback directly. * If a deferred resume was requested while the callback was running then carry * it out; otherwise send an idle notification for the device (if the suspend * failed) or for its parent (if the suspend succeeded). * Check if the device's runtime PM status allows it to be suspended. * Cancel a pending idle notification, autosuspend or suspend. If * another suspend has been started earlier, either return immediately * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC * flags. If the RPM_ASYNC flag is set then queue a suspend request; * otherwise run the ->runtime_suspend() callback directly. When * ->runtime_suspend succeeded, if a deferred resume was requested while * the callback was running then carry it out, otherwise send an idle * notification for its parent (if the suspend succeeded and both * ignore_children of parent->power and irq_safe of dev->power are not set). * * This function must be called under dev->power.lock with interrupts disabled. */ Loading Loading @@ -418,7 +420,9 @@ static int rpm_suspend(struct device *dev, int rpmflags) dev->power.runtime_error = 0; else pm_runtime_cancel_pending(dev); } else { wake_up_all(&dev->power.wait_queue); goto out; } no_callback: __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_deactivate_timer(dev); Loading @@ -427,7 +431,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) parent = dev->parent; atomic_add_unless(&parent->power.child_count, -1, 0); } } wake_up_all(&dev->power.wait_queue); if (dev->power.deferred_resume) { Loading Loading
Documentation/power/runtime_pm.txt +12 −7 Original line number Diff line number Diff line Loading @@ -43,13 +43,18 @@ struct dev_pm_ops { ... }; The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are executed by the PM core for either the device type, or the class (if the device type's struct dev_pm_ops object does not exist), or the bus type (if the device type's and class' struct dev_pm_ops objects do not exist) of the given device (this allows device types to override callbacks provided by bus types or classes if necessary). The bus type, device type and class callbacks are referred to as subsystem-level callbacks in what follows. The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are executed by the PM core for either the power domain, or the device type (if the device power domain's struct dev_pm_ops does not exist), or the class (if the device power domain's and type's struct dev_pm_ops object does not exist), or the bus type (if the device power domain's, type's and class' struct dev_pm_ops objects do not exist) of the given device, so the priority order of callbacks from high to low is that power domain callbacks, device type callbacks, class callbacks and bus type callbacks, and the high priority one will take precedence over low priority one. The bus type, device type and class callbacks are referred to as subsystem-level callbacks in what follows, and generally speaking, the power domain callbacks are used for representing power domains within a SoC. By default, the callbacks are always invoked in process context with interrupts enabled. However, subsystems can use the pm_runtime_irq_safe() helper function Loading
drivers/base/power/runtime.c +18 −15 Original line number Diff line number Diff line Loading @@ -286,14 +286,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) * @dev: Device to suspend. * @rpmflags: Flag bits. * * Check if the device's runtime PM status allows it to be suspended. If * another suspend has been started earlier, either return immediately or wait * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags. Cancel a * pending idle notification. If the RPM_ASYNC flag is set then queue a * suspend request; otherwise run the ->runtime_suspend() callback directly. * If a deferred resume was requested while the callback was running then carry * it out; otherwise send an idle notification for the device (if the suspend * failed) or for its parent (if the suspend succeeded). * Check if the device's runtime PM status allows it to be suspended. * Cancel a pending idle notification, autosuspend or suspend. If * another suspend has been started earlier, either return immediately * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC * flags. If the RPM_ASYNC flag is set then queue a suspend request; * otherwise run the ->runtime_suspend() callback directly. When * ->runtime_suspend succeeded, if a deferred resume was requested while * the callback was running then carry it out, otherwise send an idle * notification for its parent (if the suspend succeeded and both * ignore_children of parent->power and irq_safe of dev->power are not set). * * This function must be called under dev->power.lock with interrupts disabled. */ Loading Loading @@ -418,7 +420,9 @@ static int rpm_suspend(struct device *dev, int rpmflags) dev->power.runtime_error = 0; else pm_runtime_cancel_pending(dev); } else { wake_up_all(&dev->power.wait_queue); goto out; } no_callback: __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_deactivate_timer(dev); Loading @@ -427,7 +431,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) parent = dev->parent; atomic_add_unless(&parent->power.child_count, -1, 0); } } wake_up_all(&dev->power.wait_queue); if (dev->power.deferred_resume) { Loading