linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: ulf.hansson@linaro.org (Ulf Hansson)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 6/8] PM / ACPI: Enable the runtime PM centric approach for system sleep
Date: Tue, 29 Aug 2017 16:56:48 +0200	[thread overview]
Message-ID: <1504018610-10822-7-git-send-email-ulf.hansson@linaro.org> (raw)
In-Reply-To: <1504018610-10822-1-git-send-email-ulf.hansson@linaro.org>

This change enables the ACPI PM domain to cope with drivers that deploys
the runtime PM centric path for system sleep.

Currently the ACPI PM domain supports the direct_complete path, which
offers some nice optimizations from PM point of view during system sleep.
However, the runtime PM centric path have some additional optimizations
that this change enables for the ACPI PM domain. Let's walk through them.

*)
The runtime PM centric path, doesn't require the device to be runtime
suspended during system suspend, when later during system resume trying to
avoid to bring it back into full power. That is the case for the
direct_complete path. This further avoids wasting power during system
resume, but should also decrease the time it takes to resume the device.

**)
When the runtime PM centric path is used, the PM core does not skip calling
any system sleep callbacks for the device, which is the case in the
direct_complete path. Based on that knowledge and relying on the driver to
do the right thing, the ACPI PM domain may avoid to always runtime resume
the device in the device_suspend() phase.

***)
In the runtime PM centric path, the device may remain runtime PM enabled
until the device_suspend_late() phase, instead of as in the direct_complete
path, in the device_suspend() phase. This is convenient if the device needs
to be runtime resumed sometime during the device_suspend() phase.

To deploy the runtime PM centric approach for the ACPI PM domain, and make
it benefit from the above optimizations, the follow changes are made.

First, the ACPI PM domain's runtime PM callbacks may be called when runtime
PM has been disabled for the device. This serves as an indication to
understand when they are running in the system sleep sequence, instead of
in the regular runtime PM path. For these cases, make the ACPI PM domain to
execute the same operations as normally being run, when the
->suspend_late() and the ->resume_early() callbacks are invoked.

Second, the ACPI PM domain's ->suspend_late() callback, shall not execute
the regular operations to put the device into low power state, when the
runtime PM centric path is used. Calling pm_generic_suspend_late() is
sufficient. Vice verse applies to the ACPI PM domain's ->resume_early()
callback.

Third, in the ACPI PM domain's ->suspend|freeze() callbacks, let's avoid
runtime resuming the device in case the runtime PM centric path is used,
unless there are ACPI PM domain specific reasons to not.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---

Changes in v3:
	- Convert to use the PM core flag, is_rpm_sleep flag.
	- Fold in changes from patch v2 7/9, which means avoiding to runtime
	resume the device in the ACPI PM domain's ->suspend|freeze() callbacks.
	- Updated changelog to reflect new changes.

---
 drivers/acpi/acpi_lpss.c | 56 ++++++++++++++++++++++++++++++---------------
 drivers/acpi/device_pm.c | 59 ++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 87 insertions(+), 28 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index e726173..2e34f69 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -732,7 +732,7 @@ static int acpi_lpss_suspend_late(struct device *dev)
 	int ret;
 
 	ret = pm_generic_suspend_late(dev);
-	if (ret)
+	if (ret || dev_pm_is_rpm_sleep(dev))
 		return ret;
 
 	return lpss_suspend_late(dev);
@@ -757,13 +757,22 @@ static int lpss_resume_early(struct device *dev)
 
 static int acpi_lpss_resume_early(struct device *dev)
 {
-	int ret;
+	int ret = 0;
 
-	ret = lpss_resume_early(dev);
-	if (ret)
-		return ret;
+	if (!dev_pm_is_rpm_sleep(dev))
+		ret = lpss_resume_early(dev);
 
-	return pm_generic_resume_early(dev);
+	return ret ? ret : pm_generic_resume_early(dev);
+}
+#else
+static inline int lpss_suspend_late(struct device *dev)
+{
+	return 0;
+}
+
+static inline int lpss_resume_early(struct device *dev)
+{
+	return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -861,6 +870,9 @@ static int acpi_lpss_runtime_suspend(struct device *dev)
 	if (ret)
 		return ret;
 
+	if (!pm_runtime_enabled(dev))
+		return lpss_suspend_late(dev);
+
 	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
 		acpi_lpss_save_ctx(dev, pdata);
 
@@ -882,21 +894,29 @@ static int acpi_lpss_runtime_resume(struct device *dev)
 	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
 	int ret;
 
-	/*
-	 * This call is kept first to be in symmetry with
-	 * acpi_lpss_runtime_suspend() one.
-	 */
-	if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
-		lpss_iosf_exit_d3_state();
+	if (pm_runtime_enabled(dev)) {
+		/*
+		 * This call is kept first to be in symmetry with
+		 * acpi_lpss_runtime_suspend() one.
+		 */
+		if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON &&
+		    iosf_mbi_available())
+			lpss_iosf_exit_d3_state();
 
-	ret = acpi_dev_runtime_resume(dev);
-	if (ret)
-		return ret;
+		ret = acpi_dev_runtime_resume(dev);
+		if (ret)
+			return ret;
 
-	acpi_lpss_d3_to_d0_delay(pdata);
+		acpi_lpss_d3_to_d0_delay(pdata);
 
-	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
-		acpi_lpss_restore_ctx(dev, pdata);
+		if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+			acpi_lpss_restore_ctx(dev, pdata);
+
+	} else {
+		ret = lpss_resume_early(dev);
+		if (ret)
+			return ret;
+	}
 
 	return pm_generic_runtime_resume(dev);
 }
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 5181057..f5c4d0e 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -913,7 +913,14 @@ EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
 int acpi_subsys_runtime_suspend(struct device *dev)
 {
 	int ret = pm_generic_runtime_suspend(dev);
-	return ret ? ret : acpi_dev_runtime_suspend(dev);
+
+	if (ret)
+		return ret;
+
+	if (!pm_runtime_enabled(dev))
+		return acpi_dev_suspend_late(dev);
+
+	return acpi_dev_runtime_suspend(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend);
 
@@ -926,7 +933,13 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend);
  */
 int acpi_subsys_runtime_resume(struct device *dev)
 {
-	int ret = acpi_dev_runtime_resume(dev);
+	int ret = 0;
+
+	if (!pm_runtime_enabled(dev))
+		ret = acpi_dev_resume_early(dev);
+	else
+		ret = acpi_dev_runtime_resume(dev);
+
 	return ret ? ret : pm_generic_runtime_resume(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
@@ -1023,7 +1036,7 @@ int acpi_subsys_prepare(struct device *dev)
 	if (ret < 0)
 		return ret;
 
-	if (!adev || !pm_runtime_suspended(dev))
+	if (!adev || dev_pm_is_rpm_sleep(dev) || !pm_runtime_suspended(dev))
 		return 0;
 
 	return !acpi_dev_needs_resume(dev, adev);
@@ -1042,7 +1055,8 @@ void acpi_subsys_complete(struct device *dev)
 	 * the sleep state it is going out of and it has never been resumed till
 	 * now, resume it in case the firmware powered it up.
 	 */
-	if (dev->power.direct_complete && pm_resume_via_firmware())
+	if ((dev->power.direct_complete || dev_pm_is_rpm_sleep(dev)) &&
+	    pm_resume_via_firmware())
 		pm_request_resume(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_complete);
@@ -1052,11 +1066,20 @@ EXPORT_SYMBOL_GPL(acpi_subsys_complete);
  * @dev: Device to handle.
  *
  * Follow PCI and resume devices suspended at run time before running their
- * system suspend callbacks.
+ * system suspend callbacks. However, try to avoid it in case the runtime PM
+ * centric path is used for the device and then trust the driver to do the
+ * right thing.
  */
 int acpi_subsys_suspend(struct device *dev)
 {
-	pm_runtime_resume(dev);
+	struct acpi_device *adev = ACPI_COMPANION(dev);
+
+	if (!adev)
+		return 0;
+
+	if (!dev_pm_is_rpm_sleep(dev) || acpi_dev_needs_resume(dev, adev))
+		pm_runtime_resume(dev);
+
 	return pm_generic_suspend(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
@@ -1071,7 +1094,11 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
 int acpi_subsys_suspend_late(struct device *dev)
 {
 	int ret = pm_generic_suspend_late(dev);
-	return ret ? ret : acpi_dev_suspend_late(dev);
+
+	if (ret || dev_pm_is_rpm_sleep(dev))
+		return ret;
+
+	return acpi_dev_suspend_late(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
 
@@ -1085,7 +1112,11 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
  */
 int acpi_subsys_resume_early(struct device *dev)
 {
-	int ret = acpi_dev_resume_early(dev);
+	int ret = 0;
+
+	if (!dev_pm_is_rpm_sleep(dev))
+		ret = acpi_dev_resume_early(dev);
+
 	return ret ? ret : pm_generic_resume_early(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
@@ -1096,13 +1127,21 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
  */
 int acpi_subsys_freeze(struct device *dev)
 {
+	struct acpi_device *adev = ACPI_COMPANION(dev);
+
+	if (!adev)
+		return 0;
+
 	/*
 	 * This used to be done in acpi_subsys_prepare() for all devices and
 	 * some drivers may depend on it, so do it here.  Ideally, however,
 	 * runtime-suspended devices should not be touched during freeze/thaw
-	 * transitions.
+	 * transitions. In case the runtime PM centric path is used, let's try
+	 * to avoid it.
 	 */
-	pm_runtime_resume(dev);
+	if (!dev_pm_is_rpm_sleep(dev) || acpi_dev_needs_resume(dev, adev))
+		pm_runtime_resume(dev);
+
 	return pm_generic_freeze(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
-- 
2.7.4

  parent reply	other threads:[~2017-08-29 14:56 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-29 14:56 [PATCH v3 0/8] PM / ACPI / i2c: Deploy runtime PM centric path for system sleep Ulf Hansson
2017-08-29 14:56 ` [PATCH v3 1/8] PM / Sleep: Make the runtime PM centric path known to the PM core Ulf Hansson
2017-08-29 15:15   ` Rafael J. Wysocki
2017-08-30  7:13     ` Ulf Hansson
2017-08-30 13:37       ` Rafael J. Wysocki
2017-08-31  9:06         ` Ulf Hansson
2017-09-02 14:48           ` Rafael J. Wysocki
2017-08-29 14:56 ` [PATCH v3 2/8] PM / ACPI: Restore acpi_subsys_complete() Ulf Hansson
2017-08-29 14:56 ` [PATCH v3 3/8] PM / Sleep: Remove pm_complete_with_resume_check() Ulf Hansson
2017-08-29 14:56 ` [PATCH v3 4/8] PM / ACPI: Split code validating need for runtime resume in ->prepare() Ulf Hansson
2017-08-29 14:56 ` [PATCH v3 5/8] PM / ACPI: Split acpi_lpss_suspend_late|resume_early() Ulf Hansson
2017-08-29 14:56 ` Ulf Hansson [this message]
2017-08-29 15:27   ` [PATCH v3 6/8] PM / ACPI: Enable the runtime PM centric approach for system sleep Rafael J. Wysocki
2017-09-01  8:27     ` Ulf Hansson
2017-09-02 15:38       ` Rafael J. Wysocki
2017-09-04 13:21         ` Ulf Hansson
2017-09-06  0:02           ` Rafael J. Wysocki
2017-08-29 14:56 ` [PATCH v3 7/8] i2c: designware: Don't resume device in the ->complete() callback Ulf Hansson
2017-08-29 14:56 ` [PATCH v3 8/8] i2c: designware: Deploy the runtime PM centric path for system sleep Ulf Hansson
2017-08-29 20:19 ` [PATCH v3 0/8] PM / ACPI / i2c: Deploy " Rafael J. Wysocki
2017-08-30  9:57   ` Ulf Hansson
2017-08-31  0:17     ` Rafael J. Wysocki
2017-09-01 10:42       ` Ulf Hansson
2017-09-04  0:17         ` Rafael J. Wysocki
2017-09-04  5:46           ` Lukas Wunner
2017-09-04 10:04             ` Rafael J. Wysocki
2017-09-04 12:55           ` Ulf Hansson
2017-09-06  0:52             ` Rafael J. Wysocki
2017-09-06 10:46               ` Rafael J. Wysocki
2017-09-06 13:59                 ` Ulf Hansson
2017-09-06 21:39                   ` Rafael J. Wysocki
2017-09-06 13:54               ` Ulf Hansson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1504018610-10822-7-git-send-email-ulf.hansson@linaro.org \
    --to=ulf.hansson@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).