aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-18 09:31:49 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-26 19:20:59 -0500
commit0d4b54c6fee87ff60b0bc1007ca487449698468d (patch)
treed9874b3425fc3e411eec30659aa062f5a22ea855
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
PM / core: Add LEAVE_SUSPENDED driver flag
Define and document a new driver flag, DPM_FLAG_LEAVE_SUSPENDED, to instruct the PM core and middle-layer (bus type, PM domain, etc.) code that it is desirable to leave the device in runtime suspend after system-wide transitions to the working state (for example, the device may be slow to resume and it may be better to avoid resuming it right away). Generally, the middle-layer code involved in the handling of the device is expected to indicate to the PM core whether or not the device may be left in suspend with the help of the device's power.may_skip_resume status bit. That has to happen in the "noirq" phase of the preceding system suspend (or analogous) transition. The middle layer is then responsible for handling the device as appropriate in its "noirq" resume callback which is executed regardless of whether or not the device may be left suspended, but the other resume callbacks (except for ->complete) will be skipped automatically by the core if the device really can be left in suspend. The additional power.must_resume status bit introduced for the implementation of this mechanisn is used internally by the PM core to track the requirement to resume the device (which may depend on its children etc). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--Documentation/driver-api/pm/devices.rst27
-rw-r--r--drivers/base/power/main.c73
-rw-r--r--include/linux/pm.h16
3 files changed, 105 insertions, 11 deletions
diff --git a/Documentation/driver-api/pm/devices.rst b/Documentation/driver-api/pm/devices.rst
index 53c1b0b06da5..b0fe63c91f8d 100644
--- a/Documentation/driver-api/pm/devices.rst
+++ b/Documentation/driver-api/pm/devices.rst
@@ -788,6 +788,29 @@ must reflect the "active" status for runtime PM in that case.
788 788
789During system-wide resume from a sleep state it's easiest to put devices into 789During system-wide resume from a sleep state it's easiest to put devices into
790the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`. 790the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`.
791Refer to that document for more information regarding this particular issue as 791[Refer to that document for more information regarding this particular issue as
792well as for information on the device runtime power management framework in 792well as for information on the device runtime power management framework in
793general. 793general.]
794
795However, it often is desirable to leave devices in suspend after system
796transitions to the working state, especially if those devices had been in
797runtime suspend before the preceding system-wide suspend (or analogous)
798transition. Device drivers can use the ``DPM_FLAG_LEAVE_SUSPENDED`` flag to
799indicate to the PM core (and middle-layer code) that they prefer the specific
800devices handled by them to be left suspended and they have no problems with
801skipping their system-wide resume callbacks for this reason. Whether or not the
802devices will actually be left in suspend may depend on their state before the
803given system suspend-resume cycle and on the type of the system transition under
804way. In particular, devices are not left suspended if that transition is a
805restore from hibernation, as device states are not guaranteed to be reflected
806by the information stored in the hibernation image in that case.
807
808The middle-layer code involved in the handling of the device is expected to
809indicate to the PM core if the device may be left in suspend by setting its
810:c:member:`power.may_skip_resume` status bit which is checked by the PM core
811during the "noirq" phase of the preceding system-wide suspend (or analogous)
812transition. The middle layer is then responsible for handling the device as
813appropriate in its "noirq" resume callback, which is executed regardless of
814whether or not the device is left suspended, but the other resume callbacks
815(except for ``->complete``) will be skipped automatically by the PM core if the
816device really can be left in suspend.
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index db2f04415927..73ec6796d9e1 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -526,6 +526,18 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
526/*------------------------- Resume routines -------------------------*/ 526/*------------------------- Resume routines -------------------------*/
527 527
528/** 528/**
529 * dev_pm_may_skip_resume - System-wide device resume optimization check.
530 * @dev: Target device.
531 *
532 * Checks whether or not the device may be left in suspend after a system-wide
533 * transition to the working state.
534 */
535bool dev_pm_may_skip_resume(struct device *dev)
536{
537 return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE;
538}
539
540/**
529 * device_resume_noirq - Execute a "noirq resume" callback for given device. 541 * device_resume_noirq - Execute a "noirq resume" callback for given device.
530 * @dev: Device to handle. 542 * @dev: Device to handle.
531 * @state: PM transition of the system being carried out. 543 * @state: PM transition of the system being carried out.
@@ -573,6 +585,19 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
573 error = dpm_run_callback(callback, dev, state, info); 585 error = dpm_run_callback(callback, dev, state, info);
574 dev->power.is_noirq_suspended = false; 586 dev->power.is_noirq_suspended = false;
575 587
588 if (dev_pm_may_skip_resume(dev)) {
589 /*
590 * The device is going to be left in suspend, but it might not
591 * have been in runtime suspend before the system suspended, so
592 * its runtime PM status needs to be updated to avoid confusing
593 * the runtime PM framework when runtime PM is enabled for the
594 * device again.
595 */
596 pm_runtime_set_suspended(dev);
597 dev->power.is_late_suspended = false;
598 dev->power.is_suspended = false;
599 }
600
576 Out: 601 Out:
577 complete_all(&dev->power.completion); 602 complete_all(&dev->power.completion);
578 TRACE_RESUME(error); 603 TRACE_RESUME(error);
@@ -1074,6 +1099,22 @@ static pm_message_t resume_event(pm_message_t sleep_state)
1074 return PMSG_ON; 1099 return PMSG_ON;
1075} 1100}
1076 1101
1102static void dpm_superior_set_must_resume(struct device *dev)
1103{
1104 struct device_link *link;
1105 int idx;
1106
1107 if (dev->parent)
1108 dev->parent->power.must_resume = true;
1109
1110 idx = device_links_read_lock();
1111
1112 list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
1113 link->supplier->power.must_resume = true;
1114
1115 device_links_read_unlock(idx);
1116}
1117
1077/** 1118/**
1078 * __device_suspend_noirq - Execute a "noirq suspend" callback for given device. 1119 * __device_suspend_noirq - Execute a "noirq suspend" callback for given device.
1079 * @dev: Device to handle. 1120 * @dev: Device to handle.
@@ -1125,10 +1166,28 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
1125 } 1166 }
1126 1167
1127 error = dpm_run_callback(callback, dev, state, info); 1168 error = dpm_run_callback(callback, dev, state, info);
1128 if (!error) 1169 if (error) {
1129 dev->power.is_noirq_suspended = true;
1130 else
1131 async_error = error; 1170 async_error = error;
1171 goto Complete;
1172 }
1173
1174 dev->power.is_noirq_suspended = true;
1175
1176 if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) {
1177 /*
1178 * The only safe strategy here is to require that if the device
1179 * may not be left in suspend, resume callbacks must be invoked
1180 * for it.
1181 */
1182 dev->power.must_resume = dev->power.must_resume ||
1183 !dev->power.may_skip_resume ||
1184 atomic_read(&dev->power.usage_count) > 1;
1185 } else {
1186 dev->power.must_resume = true;
1187 }
1188
1189 if (dev->power.must_resume)
1190 dpm_superior_set_must_resume(dev);
1132 1191
1133Complete: 1192Complete:
1134 complete_all(&dev->power.completion); 1193 complete_all(&dev->power.completion);
@@ -1485,6 +1544,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1485 dev->power.direct_complete = false; 1544 dev->power.direct_complete = false;
1486 } 1545 }
1487 1546
1547 dev->power.may_skip_resume = false;
1548 dev->power.must_resume = false;
1549
1488 dpm_watchdog_set(&wd, dev); 1550 dpm_watchdog_set(&wd, dev);
1489 device_lock(dev); 1551 device_lock(dev);
1490 1552
@@ -1650,8 +1712,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
1650 if (dev->power.syscore) 1712 if (dev->power.syscore)
1651 return 0; 1713 return 0;
1652 1714
1653 WARN_ON(dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) && 1715 WARN_ON(!pm_runtime_enabled(dev) &&
1654 !pm_runtime_enabled(dev)); 1716 dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
1717 DPM_FLAG_LEAVE_SUSPENDED));
1655 1718
1656 /* 1719 /*
1657 * If a device's parent goes into runtime suspend at the wrong time, 1720 * If a device's parent goes into runtime suspend at the wrong time,
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 65d39115f06d..b5a40b713e9e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -556,9 +556,10 @@ struct pm_subsys_data {
556 * These flags can be set by device drivers at the probe time. They need not be 556 * These flags can be set by device drivers at the probe time. They need not be
557 * cleared by the drivers as the driver core will take care of that. 557 * cleared by the drivers as the driver core will take care of that.
558 * 558 *
559 * NEVER_SKIP: Do not skip system suspend/resume callbacks for the device. 559 * NEVER_SKIP: Do not skip all system suspend/resume callbacks for the device.
560 * SMART_PREPARE: Check the return value of the driver's ->prepare callback. 560 * SMART_PREPARE: Check the return value of the driver's ->prepare callback.
561 * SMART_SUSPEND: No need to resume the device from runtime suspend. 561 * SMART_SUSPEND: No need to resume the device from runtime suspend.
562 * LEAVE_SUSPENDED: Avoid resuming the device during system resume if possible.
562 * 563 *
563 * Setting SMART_PREPARE instructs bus types and PM domains which may want 564 * Setting SMART_PREPARE instructs bus types and PM domains which may want
564 * system suspend/resume callbacks to be skipped for the device to return 0 from 565 * system suspend/resume callbacks to be skipped for the device to return 0 from
@@ -572,10 +573,14 @@ struct pm_subsys_data {
572 * necessary from the driver's perspective. It also may cause them to skip 573 * necessary from the driver's perspective. It also may cause them to skip
573 * invocations of the ->suspend_late and ->suspend_noirq callbacks provided by 574 * invocations of the ->suspend_late and ->suspend_noirq callbacks provided by
574 * the driver if they decide to leave the device in runtime suspend. 575 * the driver if they decide to leave the device in runtime suspend.
576 *
577 * Setting LEAVE_SUSPENDED informs the PM core and middle-layer code that the
578 * driver prefers the device to be left in suspend after system resume.
575 */ 579 */
576#define DPM_FLAG_NEVER_SKIP BIT(0) 580#define DPM_FLAG_NEVER_SKIP BIT(0)
577#define DPM_FLAG_SMART_PREPARE BIT(1) 581#define DPM_FLAG_SMART_PREPARE BIT(1)
578#define DPM_FLAG_SMART_SUSPEND BIT(2) 582#define DPM_FLAG_SMART_SUSPEND BIT(2)
583#define DPM_FLAG_LEAVE_SUSPENDED BIT(3)
579 584
580struct dev_pm_info { 585struct dev_pm_info {
581 pm_message_t power_state; 586 pm_message_t power_state;
@@ -597,6 +602,8 @@ struct dev_pm_info {
597 bool wakeup_path:1; 602 bool wakeup_path:1;
598 bool syscore:1; 603 bool syscore:1;
599 bool no_pm_callbacks:1; /* Owned by the PM core */ 604 bool no_pm_callbacks:1; /* Owned by the PM core */
605 unsigned int must_resume:1; /* Owned by the PM core */
606 unsigned int may_skip_resume:1; /* Set by subsystems */
600#else 607#else
601 unsigned int should_wakeup:1; 608 unsigned int should_wakeup:1;
602#endif 609#endif
@@ -765,6 +772,7 @@ extern int pm_generic_poweroff_late(struct device *dev);
765extern int pm_generic_poweroff(struct device *dev); 772extern int pm_generic_poweroff(struct device *dev);
766extern void pm_generic_complete(struct device *dev); 773extern void pm_generic_complete(struct device *dev);
767 774
775extern bool dev_pm_may_skip_resume(struct device *dev);
768extern bool dev_pm_smart_suspend_and_suspended(struct device *dev); 776extern bool dev_pm_smart_suspend_and_suspended(struct device *dev);
769 777
770#else /* !CONFIG_PM_SLEEP */ 778#else /* !CONFIG_PM_SLEEP */