From patchwork Mon Jan 12 10:02:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rafael J. Wysocki" X-Patchwork-Id: 5609291 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 1A554C058D for ; Mon, 12 Jan 2015 09:39:51 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B52842026C for ; Mon, 12 Jan 2015 09:39:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0BD0820558 for ; Mon, 12 Jan 2015 09:39:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752322AbbALJjm (ORCPT ); Mon, 12 Jan 2015 04:39:42 -0500 Received: from v094114.home.net.pl ([79.96.170.134]:59106 "HELO v094114.home.net.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752315AbbALJjl (ORCPT ); Mon, 12 Jan 2015 04:39:41 -0500 Received: from 119-224-135-33.callplus.net.nz (119.224.135.33) (HELO vostro.rjw.lan) by serwer1319399.home.pl (79.96.170.134) with SMTP (IdeaSmtpServer v0.80) id 9f591f683e131499; Mon, 12 Jan 2015 10:39:39 +0100 From: "Rafael J. Wysocki" To: Alan Stern Cc: Linux PCI , Linux Kernel Mailing List , Linux PM list , Bjorn Helgaas , Aaron Lu , Mika Westerberg Subject: Re: [RFC][PATCH] PCI / PM: Avoid resuming PCI devices during system suspend Date: Mon, 12 Jan 2015 11:02:03 +0100 Message-ID: <1654338.pQ8g9cpnmS@vostro.rjw.lan> User-Agent: KMail/4.11.5 (Linux/3.16.0-rc5+; KDE/4.11.5; x86_64; ; ) In-Reply-To: References: MIME-Version: 1.0 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Thursday, January 08, 2015 10:51:06 AM Alan Stern wrote: > On Thu, 8 Jan 2015, Rafael J. Wysocki wrote: > > > From: Rafael J. Wysocki > > > > Commit f25c0ae2b4c4 (ACPI / PM: Avoid resuming devices in ACPI PM > > domain during system suspend) modified the ACPI PM domain's system > > suspend callbacks to allow devices attached to it to be left in the > > runtime-suspended state during system suspend so as to optimize > > the suspend process. > > > > This was based on the general mechanism introduced by commit > > aae4518b3124 (PM / sleep: Mechanism to avoid resuming runtime-suspended > > devices unnecessarily). > > > > Extend that approach to PCI devices by modifying the PCI bus type's > > ->prepare callback to return 1 for devices that are runtime-suspended > > when it is being executed and that are in a suitable power state and > > need not be resumed going forward. > > Does this correctly handle PCI devices that aren't included in the ACPI > tables? For example, add-on PCI cards? Well, it would if it took the case when a device was configured for remote wakeup at run time but was not supposed to wakeup the system from sleep into account. That needs to be checked in pci_dev_keep_suspended() rather than in the platform callback to cover all devices. Updated patch follows. Rafael --- From: Rafael J. Wysocki Subject: PCI / PM: Avoid resuming PCI devices during system suspend Commit f25c0ae2b4c4 (ACPI / PM: Avoid resuming devices in ACPI PM domain during system suspend) modified the ACPI PM domain's system suspend callbacks to allow devices attached to it to be left in the runtime-suspended state during system suspend so as to optimize the suspend process. This was based on the general mechanism introduced by commit aae4518b3124 (PM / sleep: Mechanism to avoid resuming runtime-suspended devices unnecessarily). Extend that approach to PCI devices by modifying the PCI bus type's ->prepare callback to return 1 for devices that are runtime-suspended when it is being executed and that are in a suitable power state and need not be resumed going forward. Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-acpi.c | 12 ++++++++++++ drivers/pci/pci-driver.c | 11 ++++++----- drivers/pci/pci.c | 26 ++++++++++++++++++++++++++ drivers/pci/pci.h | 6 ++++++ 4 files changed, 50 insertions(+), 5 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Index: linux-pm/drivers/pci/pci.c =================================================================== --- linux-pm.orig/drivers/pci/pci.c +++ linux-pm/drivers/pci/pci.c @@ -521,6 +521,11 @@ static inline int platform_pci_run_wake( pci_platform_pm->run_wake(dev, enable) : -ENODEV; } +static inline bool platform_pci_need_resume(struct pci_dev *dev) +{ + return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false; +} + /** * pci_raw_set_power_state - Use PCI PM registers to set the power state of * given PCI device @@ -1999,6 +2004,27 @@ bool pci_dev_run_wake(struct pci_dev *de } EXPORT_SYMBOL_GPL(pci_dev_run_wake); +/** + * pci_dev_keep_suspended - Check if the device can stay in the suspended state. + * @pci_dev: Device to check. + * + * Return 'true' if the device is runtime-suspended, it doesn't have to be + * reconfigured due to wakeup settings difference between system and runtime + * suspend and the current power state of it is suitable for the upcoming + * (system) transition. + */ +bool pci_dev_keep_suspended(struct pci_dev *pci_dev) +{ + struct device *dev = &pci_dev->dev; + + if (!pm_runtime_suspended(dev) + || (device_can_wakeup(dev) && !device_may_wakeup(dev)) + || platform_pci_need_resume(pci_dev)) + return false; + + return pci_target_state(dev) == dev->current_state; +} + void pci_config_pm_runtime_get(struct pci_dev *pdev) { struct device *dev = &pdev->dev; Index: linux-pm/drivers/pci/pci.h =================================================================== --- linux-pm.orig/drivers/pci/pci.h +++ linux-pm/drivers/pci/pci.h @@ -50,6 +50,10 @@ int pci_probe_reset_function(struct pci_ * for given device (the device's wake-up capability has to be * enabled by @sleep_wake for this feature to work) * + * @need_resume: returns 'true' if the given device (which is currently + * suspended) needs to be resumed to be configured for system + * wakeup. + * * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */ @@ -59,6 +63,7 @@ struct pci_platform_pm_ops { pci_power_t (*choose_state)(struct pci_dev *dev); int (*sleep_wake)(struct pci_dev *dev, bool enable); int (*run_wake)(struct pci_dev *dev, bool enable); + bool (*need_resume)(struct pci_dev *dev); }; int pci_set_platform_pm(struct pci_platform_pm_ops *ops); @@ -67,6 +72,7 @@ void pci_power_up(struct pci_dev *dev); void pci_disable_enabled_device(struct pci_dev *dev); int pci_finish_runtime_suspend(struct pci_dev *dev); int __pci_pme_wakeup(struct pci_dev *dev, void *ign); +bool pci_dev_keep_suspended(struct pci_dev *dev); void pci_config_pm_runtime_get(struct pci_dev *dev); void pci_config_pm_runtime_put(struct pci_dev *dev); void pci_pm_init(struct pci_dev *dev); Index: linux-pm/drivers/pci/pci-acpi.c =================================================================== --- linux-pm.orig/drivers/pci/pci-acpi.c +++ linux-pm/drivers/pci/pci-acpi.c @@ -501,12 +501,24 @@ static int acpi_pci_run_wake(struct pci_ return 0; } +static bool acpi_pci_need_resume(struct pci_dev *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); + + if (!adev || !acpi_device_power_manageable(adev) + || acpi_target_system_state() == ACPI_STATE_S0) + return false; + + return !!adev->power.flags.dsw_present; +} + static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .sleep_wake = acpi_pci_sleep_wake, .run_wake = acpi_pci_run_wake, + .need_resume = acpi_pci_need_resume, }; void acpi_pci_add_bus(struct pci_bus *bus) Index: linux-pm/drivers/pci/pci-driver.c =================================================================== --- linux-pm.orig/drivers/pci/pci-driver.c +++ linux-pm/drivers/pci/pci-driver.c @@ -653,7 +653,6 @@ static bool pci_has_legacy_pm_support(st static int pci_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; - int error = 0; /* * Devices having power.ignore_children set may still be necessary for @@ -662,10 +661,12 @@ static int pci_pm_prepare(struct device if (dev->power.ignore_children) pm_runtime_resume(dev); - if (drv && drv->pm && drv->pm->prepare) - error = drv->pm->prepare(dev); - - return error; + if (drv && drv->pm && drv->pm->prepare) { + int error = drv->pm->prepare(dev); + if (error) + return error; + } + return pci_dev_keep_suspended(to_pci_dev(dev)); }