From patchwork Tue Aug 29 14:56:48 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 9927611 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 898006022E for ; Tue, 29 Aug 2017 14:57:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7979428980 for ; Tue, 29 Aug 2017 14:57:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6E3B828987; Tue, 29 Aug 2017 14:57:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3CAA28980 for ; Tue, 29 Aug 2017 14:57:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754671AbdH2O5Z (ORCPT ); Tue, 29 Aug 2017 10:57:25 -0400 Received: from mail-lf0-f54.google.com ([209.85.215.54]:36135 "EHLO mail-lf0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754676AbdH2O5M (ORCPT ); Tue, 29 Aug 2017 10:57:12 -0400 Received: by mail-lf0-f54.google.com with SMTP id z12so14370896lfd.3 for ; Tue, 29 Aug 2017 07:57:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8jrgc/IfGCMNNVG6RujufZsFpV26gsYCNTzrZZAH2L4=; b=KLZcXQUMH0ZdlLmvFgQYyCQ49ecr9blyUkiwvpKM8mjDpHCY2GoUOOVO3+Yu0oeZlz muu5dasMhdfkbWYTrFo2YJISL5zr9i+WYX5ODcesC14QMHB9wOMA33N75LdPRM7JOSM0 4nuIpPyKO/aWaiZM3IvRxWPm8ot5n0TOXvhzc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8jrgc/IfGCMNNVG6RujufZsFpV26gsYCNTzrZZAH2L4=; b=kZ0C6qMIE9VRv20uKetZmKyGPU5w6czZtmgU5QhX1wk9oO8d3P6omMp1jTrzLyDOP8 AQSvJdC/falhBaAZxHlwy7pfSXulxy7LVsp3iZgPTr5k5vNrJlJiqZLBHjhY670uuEzr +sOUb11kz/3gxoX72DtqguTb5TCSk5QdfuPpbjcbFm2rrEeUSF0ZelpCj22DCs3tsFUA V8SR9adwrf5LnOUUKrXu+LwlkHhH/gG7iChC9kL13NtvQPKyiLS+U0KuIXBEuyW3/ymN d8+ke2VUKUlpZYAmyKvXIK6a9wII1pMGZy7FD/XNiEasR73hrFCMFCfENwnoWBDClkZo V2oQ== X-Gm-Message-State: AHYfb5jJSGiXgme1t3K0A0F71WcXOE5hTaD104iPlhuIsokMOE7XOrYn N7BZd8R7tLd8fI6tdT+huQ== X-Received: by 10.25.216.89 with SMTP id p86mr208017lfg.27.1504018630869; Tue, 29 Aug 2017 07:57:10 -0700 (PDT) Received: from localhost.localdomain (h-158-174-22-67.NA.cust.bahnhof.se. [158.174.22.67]) by smtp.gmail.com with ESMTPSA id y23sm652454ljd.19.2017.08.29.07.57.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 29 Aug 2017 07:57:10 -0700 (PDT) From: Ulf Hansson To: Wolfram Sang , "Rafael J . Wysocki" , Len Brown , linux-acpi@vger.kernel.org, linux-pm@vger.kernel.org Cc: Kevin Hilman , Jarkko Nikula , Andy Shevchenko , Mika Westerberg , Jisheng Zhang , John Stultz , Guodong Xu , Sumit Semwal , Haojian Zhuang , Johannes Stezenbach , linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org, Ulf Hansson 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 Message-Id: <1504018610-10822-7-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1504018610-10822-1-git-send-email-ulf.hansson@linaro.org> References: <1504018610-10822-1-git-send-email-ulf.hansson@linaro.org> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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);