From patchwork Thu Feb 13 09:01:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 24579 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f72.google.com (mail-pa0-f72.google.com [209.85.220.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 2C120202B2 for ; Thu, 13 Feb 2014 09:01:54 +0000 (UTC) Received: by mail-pa0-f72.google.com with SMTP id rd3sf23461031pab.11 for ; Thu, 13 Feb 2014 01:01:54 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=hEaMG/Fj0YSzShrNTjk8sI+WM2WOM/cF3nsAyJietLk=; b=ZH7vwEwH0FMcIIEU4YJfnQHrBCDTMnp/EXoeF6TeXKyH34TyiHaMG3liS0QtuGaDCb R47uyLLvfs2zsFXhIeO4RrHqFqktOORI7tIKuG8XBlmPRisbZdc9hrPjN8KNivOaU0uc XH9bfQNzENH6n3W3okLxjUZwNZfpis2ZqqP8AGkSlpVuq5rMrlZZwklAZKV5UNRdXz5N 83Yl2xOIUdu+0i8VW2usYs9u6wrGX96hlmrLew6t2HW/DGROgRQCZqKeMZ4ou7N5fCkH v8PUsqab03I2zuWAKeZc6MmVBpoYkyXgqunOtpG2UhsXRSTVL/MeMxzGty00nKT8S0kg 1G1g== X-Gm-Message-State: ALoCoQlNPip1/wvFmHefRHF1TorsOt/jy1zjcF0jOE8/6wODxb+IzHb9Ea46cGP2Ix5lpXTN2esY X-Received: by 10.66.65.109 with SMTP id w13mr104494pas.21.1392282114310; Thu, 13 Feb 2014 01:01:54 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.51.44 with SMTP id t41ls3361779qga.86.gmail; Thu, 13 Feb 2014 01:01:54 -0800 (PST) X-Received: by 10.52.184.73 with SMTP id es9mr94680vdc.31.1392282114225; Thu, 13 Feb 2014 01:01:54 -0800 (PST) Received: from mail-vc0-f176.google.com (mail-vc0-f176.google.com [209.85.220.176]) by mx.google.com with ESMTPS id sq4si434098vdc.80.2014.02.13.01.01.54 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 13 Feb 2014 01:01:54 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.176 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.176; Received: by mail-vc0-f176.google.com with SMTP id la4so7849436vcb.21 for ; Thu, 13 Feb 2014 01:01:54 -0800 (PST) X-Received: by 10.52.251.232 with SMTP id zn8mr89247vdc.41.1392282114113; Thu, 13 Feb 2014 01:01:54 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp10125vcz; Thu, 13 Feb 2014 01:01:53 -0800 (PST) X-Received: by 10.180.105.65 with SMTP id gk1mr5553687wib.12.1392282112859; Thu, 13 Feb 2014 01:01:52 -0800 (PST) Received: from mail-we0-f180.google.com (mail-we0-f180.google.com [74.125.82.180]) by mx.google.com with ESMTPS id cy3si3231349wib.39.2014.02.13.01.01.52 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 13 Feb 2014 01:01:52 -0800 (PST) Received-SPF: neutral (google.com: 74.125.82.180 is neither permitted nor denied by best guess record for domain of ulf.hansson@linaro.org) client-ip=74.125.82.180; Received: by mail-we0-f180.google.com with SMTP id u57so6991996wes.25 for ; Thu, 13 Feb 2014 01:01:52 -0800 (PST) X-Received: by 10.181.11.169 with SMTP id ej9mr5464206wid.18.1392282112195; Thu, 13 Feb 2014 01:01:52 -0800 (PST) Received: from localhost.localdomain ([85.235.11.236]) by mx.google.com with ESMTPSA id q2sm2898917wjq.0.2014.02.13.01.01.50 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 13 Feb 2014 01:01:51 -0800 (PST) From: Ulf Hansson To: "Rafael J. Wysocki" , Len Brown , Pavel Machek , linux-pm@vger.kernel.org Cc: Ulf Hansson , Kevin Hilman , Alan Stern , Greg Kroah-Hartman , Mark Brown , Russell King , Linus Walleij Subject: [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions Date: Thu, 13 Feb 2014 10:01:48 +0100 Message-Id: <1392282108-2449-1-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 1.7.9.5 X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: ulf.hansson@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.176 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , This patch provides two new runtime PM helper functions which intend to be used from system suspend/resume callbacks, to make sure devices are put into low power state during system suspend and brought back to full power at system resume. The prerequisite is to have all levels of a device's runtime PM callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which means these are available for CONFIG_PM. By using the new runtime PM helper functions especially the two scenarios below will be addressed. 1) The PM core prevents .runtime_suspend callbacks from being invoked during system suspend. That means even for a runtime PM centric subsystem and driver, the device needs to be put into low power state from a system suspend callback. Otherwise it may very well be left in full power state (runtime resumed) while the system is suspended. By using the new helper functions, we make sure to walk the hierarchy of a device's power domain, subsystem and driver. 2) Subsystems and drivers need to cope with all the combinations of CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions smothly addresses this. Cc: Kevin Hilman Cc: Alan Stern Cc: Greg Kroah-Hartman Cc: Mark Brown Cc: Russell King Cc: Linus Walleij Signed-off-by: Ulf Hansson --- Some relevant background to this patch: Recent discussions on linux-pm mailing list regarding a similar patch, but which added similar functionality as pm_generic* functions, which concluded to be dropped. http://marc.info/?t=138556666500004&r=1&w=2 Responses on recent sent patches, which are rejected from subsystem maintainers, while trying to adopt suspend/resume callbacks when using SET_PM_RUNTIME_PM_OPS. http://marc.info/?t=139152977000004&r=1&w=2 http://marc.info/?t=139152958400001&r=1&w=2 --- drivers/base/power/Makefile | 3 +- drivers/base/power/runtime.c | 110 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_runtime.h | 4 ++ 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 2e58ebb..1cb8544 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,6 +1,5 @@ -obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o +obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o -obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 72e00e6..959c478 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -13,6 +13,7 @@ #include #include "power.h" +#ifdef CONFIG_PM_RUNTIME static int rpm_resume(struct device *dev, int rpmflags); static int rpm_suspend(struct device *dev, int rpmflags); @@ -1401,3 +1402,112 @@ void pm_runtime_remove(struct device *dev) if (dev->power.irq_safe && dev->parent) pm_runtime_put(dev->parent); } +#endif + +#ifdef CONFIG_PM +/** + * pm_runtime_force_suspend - Force a device into suspend state if needed. + * @dev: Device to suspend. + * + * Disable runtime PM so we safely can check the device's runtime PM status and + * if it is active, invoke it's .runtime_suspend callback to bring it into + * suspend state. Keep runtime PM disabled to preserve the state unless we + * encounter errors. + * + * Typically this function may be invoked from a system suspend callback to make + * sure the device is put into low power state. + */ +int pm_runtime_force_suspend(struct device *dev) +{ + int (*callback)(struct device *); + int ret = 0; + + pm_runtime_disable(dev); + + /* + * Note that pm_runtime_status_suspended() returns false while + * !CONFIG_PM_RUNTIME, which means the device will be put into low + * power state. + */ + if (pm_runtime_status_suspended(dev)) + return 0; + + if (dev->pm_domain) + callback = dev->pm_domain->ops.runtime_suspend; + else if (dev->type && dev->type->pm) + callback = dev->type->pm->runtime_suspend; + else if (dev->class && dev->class->pm) + callback = dev->class->pm->runtime_suspend; + else if (dev->bus && dev->bus->pm) + callback = dev->bus->pm->runtime_suspend; + else + callback = NULL; + + if (!callback && dev->driver && dev->driver->pm) + callback = dev->driver->pm->runtime_suspend; + + if (!callback) { + ret = -ENOSYS; + goto err; + } + + ret = callback(dev); + if (ret) + goto err; + + pm_runtime_set_suspended(dev); + return 0; +err: + pm_runtime_enable(dev); + return ret; +} +EXPORT_SYMBOL_GPL(pm_runtime_force_suspend); + +/** + * pm_runtime_force_resume - Force a device into resume state. + * @dev: Device to resume. + * + * Prior invoking this function we expect the user to have brought the device + * into low power state by a call to pm_runtime_force_suspend(). Here we reverse + * those actions and brings the device into full power. We update the runtime PM + * status and re-enables runtime PM. + * + * Typically this function may be invoked from a system resume callback to make + * sure the device is put into full power state. + */ +int pm_runtime_force_resume(struct device *dev) +{ + int (*callback)(struct device *); + int ret = 0; + + if (dev->pm_domain) + callback = dev->pm_domain->ops.runtime_resume; + else if (dev->type && dev->type->pm) + callback = dev->type->pm->runtime_resume; + else if (dev->class && dev->class->pm) + callback = dev->class->pm->runtime_resume; + else if (dev->bus && dev->bus->pm) + callback = dev->bus->pm->runtime_resume; + else + callback = NULL; + + if (!callback && dev->driver && dev->driver->pm) + callback = dev->driver->pm->runtime_resume; + + if (!callback) { + ret = -ENOSYS; + goto out; + } + + ret = callback(dev); + if (ret) + goto out; + + pm_runtime_set_active(dev); + pm_runtime_mark_last_busy(dev); +out: + pm_runtime_enable(dev); + return ret; +} +EXPORT_SYMBOL_GPL(pm_runtime_force_resume); +#endif diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 16c9a62..2a5897a 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -26,9 +26,13 @@ #ifdef CONFIG_PM extern int pm_generic_runtime_suspend(struct device *dev); extern int pm_generic_runtime_resume(struct device *dev); +extern int pm_runtime_force_suspend(struct device *dev); +extern int pm_runtime_force_resume(struct device *dev); #else static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } +static inline int pm_runtime_force_suspend(struct device *dev) { return 0; } +static inline int pm_runtime_force_resume(struct device *dev) { return 0; } #endif #ifdef CONFIG_PM_RUNTIME