From patchwork Tue Aug 29 00:59:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rafael J. Wysocki" X-Patchwork-Id: 9926635 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 9D90560380 for ; Tue, 29 Aug 2017 01:10:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8F58128818 for ; Tue, 29 Aug 2017 01:10:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8D6CA28827; Tue, 29 Aug 2017 01:10:52 +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=-2.6 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EF6DC28818 for ; Tue, 29 Aug 2017 01:10:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=2S/AUPw0auRPkInaDsqxm5QOMleCifCgco6YrxMVZ54=; b=sSjgHymR4Xnalc tOOtvnys8oqNRMgH5TSx1V3h8JXBxqj0b4mHIMw5oT1EybyIMituGqzbvUfQp686tRBBsls9i5fXF ov90CZSeYgADEGhq3xed55NXfULu0hUeVzmwPb0Yke6uZKnvJp4StMG1Vwqr99q6fOPzYK9d4UMZA lSuPTS7nQJHGopyAYZGzenbPGl4FYixlQp/jdopnSKrht0gNZzEyVpIfZPhZlGrdsmeWK7mQDSFlu DUemJsE262LYcdtqxBS0FtMss/iCPYDOTJ3KwGPKlFquQjSaP72fmQnut2sNWtXfKJJZjK/vMTqhz zXD+VBAtRDZZgJ5BC4cg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dmV3F-0007du-1E; Tue, 29 Aug 2017 01:10:45 +0000 Received: from cloudserver094114.home.net.pl ([79.96.170.134]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dmV2v-0006CC-2X for linux-arm-kernel@lists.infradead.org; Tue, 29 Aug 2017 01:10:27 +0000 Received: from 79.184.253.199.ipv4.supernova.orange.pl (79.184.253.199) (HELO aspire.rjw.lan) by serwer1319399.home.pl (79.96.170.134) with SMTP (IdeaSmtpServer 0.82) id 582c821e495364af; Tue, 29 Aug 2017 03:10:00 +0200 From: "Rafael J. Wysocki" To: Ulf Hansson Subject: [PATCH 2/3] PM / ACPI: Use SAFE_SUSPEND in the generic ACPI PM domain Date: Tue, 29 Aug 2017 02:59:08 +0200 Message-ID: <3064581.Sjxxt4B3vR@aspire.rjw.lan> In-Reply-To: <4245176.X6JjkhnUAM@aspire.rjw.lan> References: <1503499329-28834-1-git-send-email-ulf.hansson@linaro.org> <4245176.X6JjkhnUAM@aspire.rjw.lan> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170828_181025_371850_ED808BE6 X-CRM114-Status: GOOD ( 16.66 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jisheng Zhang , Guodong Xu , linux-pm@vger.kernel.org, Wolfram Sang , Greg Kroah-Hartman , Kevin Hilman , linux-i2c@vger.kernel.org, linux-acpi@vger.kernel.org, Jarkko Nikula , Haojian Zhuang , John Stultz , Andy Shevchenko , Mika Westerberg , Sumit Semwal , linux-arm-kernel@lists.infradead.org, Len Brown Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Rafael J. Wysocki Subject: [PATCH] PM / ACPI: Use SAFE_SUSPEND in the generic ACPI PM domain Make the generic ACPI PM domain and the ACPI LPSS driver take the SAFE_SUSPEND driver flag into consideration when deciding whether or not to runtime resume devices during system suspend. Namely, if the flag is set, acpi_subsys_suspend() will not attempt to runtime resume the device unless acpi_subsys_prepare() has found that the power state of the device has to be updated. Accordingly, acpi_subsys_suspend_late(), acpi_subsys_resume_late(), acpi_lpss_suspend_late(), and acpi_lpss_resume_late() will only try to update the power state of the device and its wakeup settings if the device has been runtime resumed beforehand. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 20 ++++++---- drivers/acpi/device_pm.c | 90 ++++++++++++++++++++++++++++++++++++----------- include/acpi/acpi_bus.h | 1 3 files changed, 84 insertions(+), 27 deletions(-) Index: linux-pm/include/acpi/acpi_bus.h =================================================================== --- linux-pm.orig/include/acpi/acpi_bus.h +++ linux-pm/include/acpi/acpi_bus.h @@ -287,6 +287,7 @@ struct acpi_device_power { int state; /* Current state */ struct acpi_device_power_flags flags; struct acpi_device_power_state states[ACPI_D_STATE_COUNT]; /* Power states (D0-D3Cold) */ + bool update_state; }; /* Performance Management */ Index: linux-pm/drivers/acpi/device_pm.c =================================================================== --- linux-pm.orig/drivers/acpi/device_pm.c +++ linux-pm/drivers/acpi/device_pm.c @@ -899,6 +899,7 @@ int acpi_dev_runtime_resume(struct devic error = acpi_dev_pm_full_power(adev); acpi_device_wakeup_disable(adev); + adev->power.update_state = true; return error; } EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume); @@ -989,33 +990,47 @@ int acpi_dev_resume_early(struct device } EXPORT_SYMBOL_GPL(acpi_dev_resume_early); -/** - * acpi_subsys_prepare - Prepare device for system transition to a sleep state. - * @dev: Device to prepare. - */ -int acpi_subsys_prepare(struct device *dev) +static bool acpi_dev_state_update_needed(struct device *dev) { struct acpi_device *adev = ACPI_COMPANION(dev); u32 sys_target; int ret, state; - ret = pm_generic_prepare(dev); - if (ret < 0) - return ret; + if (!pm_runtime_suspended(dev)) + return true; - if (!adev || !pm_runtime_suspended(dev) - || device_may_wakeup(dev) != !!adev->wakeup.prepare_count) - return 0; + if (device_may_wakeup(dev) != !!adev->wakeup.prepare_count) + return true; sys_target = acpi_target_system_state(); if (sys_target == ACPI_STATE_S0) - return 1; + return false; if (adev->power.flags.dsw_present) - return 0; + return true; ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state); - return !ret && state == adev->power.state; + if (ret) + return true; + + return state != adev->power.state; +} + +/** + * acpi_subsys_prepare - Prepare device for system transition to a sleep state. + * @dev: Device to prepare. + */ +int acpi_subsys_prepare(struct device *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + int ret; + + ret = pm_generic_prepare(dev); + if (ret < 0 || !adev) + return ret; + + adev->power.update_state = acpi_dev_state_update_needed(dev); + return !adev->power.update_state; } EXPORT_SYMBOL_GPL(acpi_subsys_prepare); @@ -1024,11 +1039,30 @@ EXPORT_SYMBOL_GPL(acpi_subsys_prepare); * @dev: Device to handle. * * Follow PCI and resume devices suspended at run time before running their - * system suspend callbacks. + * system suspend callbacks, unless the DPM_FLAG_SAFE_SUSPEND driver flag is + * set for them. */ int acpi_subsys_suspend(struct device *dev) { - pm_runtime_resume(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); + bool resume = !(dev->power.driver_flags & DPM_FLAG_SAFE_SUSPEND); + + if (adev) { + /* The device may have resumed in the meantime. */ + if (pm_runtime_suspended(dev)) { + resume = resume || adev->power.update_state; + } else { + /* + * Work around a super-theoretical race between runtime + * resume and acpi_dev_state_update_needed(). + */ + adev->power.update_state = true; + resume = false; + } + } + if (resume) + pm_runtime_resume(dev); + return pm_generic_suspend(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_suspend); @@ -1042,8 +1076,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; + + ret = pm_generic_suspend_late(dev); + if (ret) + return ret; + + if (adev && adev->power.update_state) + return acpi_dev_suspend_late(dev); + + return 0; } EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); @@ -1057,8 +1100,15 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_la */ int acpi_subsys_resume_early(struct device *dev) { - int ret = acpi_dev_resume_early(dev); - return ret ? ret : pm_generic_resume_early(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (adev && adev->power.update_state) { + int ret = acpi_dev_resume_early(dev); + if (ret) + return ret; + } + + return pm_generic_resume_early(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); Index: linux-pm/drivers/acpi/acpi_lpss.c =================================================================== --- linux-pm.orig/drivers/acpi/acpi_lpss.c +++ linux-pm/drivers/acpi/acpi_lpss.c @@ -719,7 +719,8 @@ static void acpi_lpss_dismiss(struct dev #ifdef CONFIG_PM_SLEEP static int acpi_lpss_suspend_late(struct device *dev) { - struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + struct acpi_device *adev = ACPI_COMPANION(dev); + struct lpss_private_data *pdata = acpi_driver_data(adev); int ret; ret = pm_generic_suspend_late(dev); @@ -729,17 +730,22 @@ static int acpi_lpss_suspend_late(struct if (pdata->dev_desc->flags & LPSS_SAVE_CTX) acpi_lpss_save_ctx(dev, pdata); - return acpi_dev_suspend_late(dev); + if (adev->power.update_state) + return acpi_dev_suspend_late(dev); + + return 0; } static int acpi_lpss_resume_early(struct device *dev) { - struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); - int ret; + struct acpi_device *adev = ACPI_COMPANION(dev); + struct lpss_private_data *pdata = acpi_driver_data(adev); - ret = acpi_dev_resume_early(dev); - if (ret) - return ret; + if (adev->power.update_state) { + int ret = acpi_dev_resume_early(dev); + if (ret) + return ret; + } acpi_lpss_d3_to_d0_delay(pdata);