From patchwork Wed Aug 23 14:42:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 110852 Delivered-To: patches@linaro.org Received: by 10.37.128.210 with SMTP id c18csp7031520ybm; Wed, 23 Aug 2017 07:42:26 -0700 (PDT) X-Received: by 10.25.42.82 with SMTP id f79mr1122054lfl.227.1503499346005; Wed, 23 Aug 2017 07:42:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503499346; cv=none; d=google.com; s=arc-20160816; b=h4RfKJXnFgwAzxLoO2jSw3w917ywXgBrMOVmFmx0qx8MsmUapEzHu84uVj1nJ/ZEDV TJNaKr4Qo55kzhv4pcxKjoQ4Tjq5qJCgLeAMIpM9vahijF58TZZSyLuPgll5V47YeTD3 4t53KorHMCiaAxUCDIqcz07/4MtAEu5UXuXCl0FoiYBc5SDgYbZyvQ17xRDnswnd0jqj Orsxux4lrW06mHOiG1Pv1mUhEkUPyCUznzRlQQ8CkT2pqtBMtL0F/QqTCtEMFH2VBIT/ GY8lpZessBI4WEDLTXIb7PNQCjNr/ZHct6tf/TnWMroTPGSrN1qIhyn1K3FN/TTMAk7U Wk3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=PlFC+LU83C6zTn+hEArZERKbVHODo8R4ush0GyoM5I4=; b=Nvi1yln6RSq9i80/M9zIwKxDhIe6qgz15096+Q5MDw8kMjbdE2MReTsUrsPqjzKHaQ ldQ/skwpCufCvuAAJOipM8xibjlAQCBAjxVMx63wgwdWeQdCVM73VqCekCh3LhMdGUYa C1D+xjBSHpdSmjA3QM2f5g0Sx3LVgBTUSlz/Drx9HIiTpfb093q337IsLfTgZcQbQP1d j/n+Pn3c2V9xOdQOl8PzQU0vcWOsQGNmfgaYd/IJMEFlWg0VyM+OPVdD7ftSBRRArKIZ m6h7d3No8Ww8BCsbYvhSin9RiooVg0xHJr746wncrbF/j97rR/XOq5MLhqRFP6iKUdhZ MUcg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LYGMg/RH; spf=pass (google.com: domain of ulf.hansson@linaro.org designates 2a00:1450:4010:c07::231 as permitted sender) smtp.mailfrom=ulf.hansson@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-lf0-x231.google.com (mail-lf0-x231.google.com. [2a00:1450:4010:c07::231]) by mx.google.com with ESMTPS id 10si801694ljc.168.2017.08.23.07.42.25 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 Aug 2017 07:42:25 -0700 (PDT) Received-SPF: pass (google.com: domain of ulf.hansson@linaro.org designates 2a00:1450:4010:c07::231 as permitted sender) client-ip=2a00:1450:4010:c07::231; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LYGMg/RH; spf=pass (google.com: domain of ulf.hansson@linaro.org designates 2a00:1450:4010:c07::231 as permitted sender) smtp.mailfrom=ulf.hansson@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: by mail-lf0-x231.google.com with SMTP id f7so1389179lfg.4 for ; Wed, 23 Aug 2017 07:42:25 -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=PlFC+LU83C6zTn+hEArZERKbVHODo8R4ush0GyoM5I4=; b=LYGMg/RHHGU+Akm2msQXYAh4T0r+IEhYoYNsebPPXUyO/ZO+Ss1udjI5C2Q5EKtCfL LI6iIYnZVFIFs9bclbKwjt6rIBGPosZf8XCVp15qGFrlfu3I6vLe4U9vMDNehyhYpMEy LONg9AUU3VC2ko9xKzvYkhJT31pW/Y0Gtiq84= 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=PlFC+LU83C6zTn+hEArZERKbVHODo8R4ush0GyoM5I4=; b=W++H/Wl4vBwoVYIcvprWiI9shobb+LRSRtryWUNX/JLwtGvS7BJyYjHDEd/HaSPffh hKKogXL/sRuc+CL0bpDBw4e1+hA4A+mr/b5KJaVhnXQlV3AxBzrYBZJM0a53HQ0vpYWs IWZFDxhkTAezTZcmPlEDnu5cdsYyag9ZGbLgQgIC2eH/LV7IZC2LmuEbrV0MsB5NrFxV LiPY9CJvXu2lxqFV2JyytK7HvOz9pZtMJ+5AGhQVosJNnJG/MTlqnx+WjfhqdPxFMksM 6LCyrT+eGqPHvkK1hJHrRLsI08BR7ZYGbeDvEuUkB9Ku726bZt9zdbCvNsKwqR1fEmnL 33vg== X-Gm-Message-State: AHYfb5h/CypJIIhszoschF3NU2ThA3wYQQo1SYalIvFiOtU7wBfOYHdK frcYaepUvhuhcm/YKJg= X-Received: by 10.46.21.71 with SMTP id 7mr1191744ljv.74.1503499345482; Wed, 23 Aug 2017 07:42:25 -0700 (PDT) Return-Path: Received: from localhost.localdomain (h-158-174-22-67.NA.cust.bahnhof.se. [158.174.22.67]) by smtp.gmail.com with ESMTPSA id c89sm287593lfb.78.2017.08.23.07.42.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 23 Aug 2017 07:42:24 -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 , linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org, Ulf Hansson Subject: [PATCH v2 6/9] PM / ACPI: Enable the runtime PM centric approach for system sleep Date: Wed, 23 Aug 2017 16:42:06 +0200 Message-Id: <1503499329-28834-7-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1503499329-28834-1-git-send-email-ulf.hansson@linaro.org> References: <1503499329-28834-1-git-send-email-ulf.hansson@linaro.org> This change extends the interpretation of the ACPI's no_direct_complete flag to be used to enable the so called runtime PM centric approach, for devices being attached to the ACPI PM domain. The principle behind the runtime PM centric approach is to re-use the runtime PM callbacks to implement system sleep for drivers/subsystems. Moreover, using the runtime PM centric approach gives an optimized behaviour around avoiding to wake up a device from its low power state during system sleep, unless really needed. To deploy the runtime PM centric approach for a subsystem/driver, the following adaptations needs to be made. First, the runtime PM callbacks may be called when runtime PM has been disabled for the device. This serves as an indication for the callbacks to understand they are running in the system sleep sequence, instead of in the regular runtime PM path. In some cases, a callback needs to take different actions depending in what path it is being executed in, as is the case for the ACPI PM domain. In particular for the ACPI PM domain's ->runtime_suspend|resume() callbacks, when those finds runtime PM being disabled for the device, it instead executes the same operations as normally being run when ->suspend_late() and ->resume_early() callbacks are invoked during system sleep. Second, at the PM domain level, it is expected that the driver for the device makes use of pm_runtime_force_suspend|resume(), to re-use the runtime PM callbacks to put the device into low power state and to wake it up when needed during system sleep. For the ACPI PM domain's ->suspend_late() and ->resume_early() callbacks, it means bypassing the operations putting the device into low power state and the operations that wakes it up. Instead it shall invoke only the lower level ->suspend_late() and ->resume_early() callbacks for the driver, if present. Signed-off-by: Ulf Hansson --- Changes in v2: - Rebased. - Updated header for acpi_enable|disable_no_direct_complete(). --- drivers/acpi/acpi_lpss.c | 58 +++++++++++++++++++++++++++++++--------------- drivers/acpi/device_pm.c | 60 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 93 insertions(+), 25 deletions(-) -- 2.7.4 diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index e726173..f0d1141 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -729,10 +729,11 @@ static int lpss_suspend_late(struct device *dev) static int acpi_lpss_suspend_late(struct device *dev) { + struct acpi_device *adev = ACPI_COMPANION(dev); int ret; ret = pm_generic_suspend_late(dev); - if (ret) + if (ret || adev->power.no_direct_complete) return ret; return lpss_suspend_late(dev); @@ -757,13 +758,23 @@ static int lpss_resume_early(struct device *dev) static int acpi_lpss_resume_early(struct device *dev) { - int ret; + struct acpi_device *adev = ACPI_COMPANION(dev); + int ret = 0; - ret = lpss_resume_early(dev); - if (ret) - return ret; + if (!adev->power.no_direct_complete) + 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 +872,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 +896,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 f7bf596..b595968 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,17 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend); */ int acpi_subsys_runtime_resume(struct device *dev) { - int ret = acpi_dev_runtime_resume(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); + int ret = 0; + + if (!adev) + return 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); @@ -939,6 +956,10 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); * Per default the ACPI PM domain tries to use the direct_complete path for its * devices during system sleep. This function allows a user, typically a driver * during probe, to disable the direct_complete path from being used by ACPI. + * Moreover, the ACPI PM domain expects and depends on that such driver deploys + * the runtime PM centric path for system sleep. In other words, the driver must + * make use of the pm_runtime_force_suspend|resume() helpers when implementing + * system sleep. */ void acpi_dev_disable_direct_complete(struct device *dev) { @@ -1072,13 +1093,21 @@ EXPORT_SYMBOL_GPL(acpi_subsys_prepare); */ void acpi_subsys_complete(struct device *dev) { + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (!adev) + return; + pm_generic_complete(dev); /* * If the device had been runtime-suspended before the system went into * 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. + * now, resume it in case the firmware powered it up. Also resume it in + * case no_direct_complete is set for the device, to be sure the device + * are managed correctly when firmware has powered it up. */ - if (dev->power.direct_complete && pm_resume_via_firmware()) + if ((dev->power.direct_complete || adev->power.no_direct_complete) && + pm_resume_via_firmware()) pm_request_resume(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_complete); @@ -1106,8 +1135,17 @@ 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); + struct acpi_device *adev = ACPI_COMPANION(dev); + int ret; + + if (!adev) + return 0; + + ret = pm_generic_suspend_late(dev); + if (ret || adev->power.no_direct_complete) + return ret; + + return acpi_dev_suspend_late(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); @@ -1121,7 +1159,15 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); */ int acpi_subsys_resume_early(struct device *dev) { - int ret = acpi_dev_resume_early(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); + int ret = 0; + + if (!adev) + return 0; + + if (!adev->power.no_direct_complete) + ret = acpi_dev_resume_early(dev); + return ret ? ret : pm_generic_resume_early(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);