From patchwork Fri Nov 15 11:40:45 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 3187821 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DD492C045B for ; Fri, 15 Nov 2013 11:41:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1CD8F2097E for ; Fri, 15 Nov 2013 11:41:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2197B20979 for ; Fri, 15 Nov 2013 11:41:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755226Ab3KOLlA (ORCPT ); Fri, 15 Nov 2013 06:41:00 -0500 Received: from mail-la0-f44.google.com ([209.85.215.44]:63322 "EHLO mail-la0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754203Ab3KOLkz (ORCPT ); Fri, 15 Nov 2013 06:40:55 -0500 Received: by mail-la0-f44.google.com with SMTP id ep20so2704464lab.31 for ; Fri, 15 Nov 2013 03:40: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:from:to:cc:subject:date:message-id:in-reply-to :references; bh=IehM4EkuEF64nUDsKwfd6Wm7QNR09q1DKoZT6PpdO3g=; b=eDQZZ48cBeaMFtV1zOwOlP1GLFOWS/AvCWoqAKQTMiDstjEgudpTUfdKbE9iSX+R1Y OKqIv8m3MQELJqofkrkqRkDHllA+tIwfUTEOR3LpzZUUtRGS6VSiD6L64NLJP/Apl8MU 6CXqHKYvml9YMSeMqPdKY4l0A/Xe/8Tn4Xz2uTm4OUJxqJwNzW+0Dslsd9+sB+kYSO1e M7lakmEV2pwmCDDYafD8jKYd4SYZUuVb+1YZREFU/a8CPfwIESWRPXaQApB0c2rxVCei C4/sFN6wNTuT+EURaLSDWdhuOYOlPYA8nWEeegUCPGJi9fdM5kY17Z4asU+Q4BJduFtn jlYQ== X-Gm-Message-State: ALoCoQllVBrmcz2CI8cX3MUwy0tB63icQP9BDyTMkRh+TyTCuYWweoFAyaXsUZuEn3Y3KScEtJnr X-Received: by 10.152.140.7 with SMTP id rc7mr4057129lab.12.1384515654247; Fri, 15 Nov 2013 03:40:54 -0800 (PST) Received: from linaro-ulf.lan (90-231-160-185-no158.tbcn.telia.com. [90.231.160.185]) by mx.google.com with ESMTPSA id l10sm1875552lbh.13.2013.11.15.03.40.52 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 15 Nov 2013 03:40:53 -0800 (PST) From: Ulf Hansson To: "Rafael J. Wysocki" , Len Brown , Pavel Machek , linux-pm@vger.kernel.org Cc: Greg Kroah-Hartman , linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, Ulf Hansson , Kevin Hilman , Alan Stern Subject: [RFC PATCH 2/2] PM / Runtime: Allow devices to become inactive during system suspend Date: Fri, 15 Nov 2013 12:40:45 +0100 Message-Id: <1384515645-8696-2-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1384515645-8696-1-git-send-email-ulf.hansson@linaro.org> References: <1384515645-8696-1-git-send-email-ulf.hansson@linaro.org> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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 The PM core was unconditionally preventing devices from being runtime suspended during system suspend. The reason is that we don't want asynchronous runtime suspends to happen during system suspend and thus race with the system suspend process, which some drivers and buses are not able to handle. However, for drivers that don't have issues with the races above, are somewhat suffering from the constraints this cause and then need to inactivate their devices outside the runtime PM control during system suspend. In other words, those implements .suspend|suspend_late callbacks to handle this. To simplify for these drivers, we add new runtime PM API, pm_runtime_no_prevent_suspend(), which drivers typically should call from their probe routines to tell PM core that it must not prevent runtime suspend during system suspend. Additonally the PM core will in this case instead invode the pm_runtime_idle just before it shall disable runtime PM in suspend_late. Drivers making use if this feature are then able to trigger runtime suspend with for example a pm_runtime_put_sync from their .suspend callbacks. Additionally, for drivers that are able to cope with only runtime PM callbacks, these can rely on the PM core to trigger a runtime suspend (if the runtime PM usage count doesn't prevent it) to inactivate their devices during system suspend. Cc: Kevin Hilman Cc: Alan Stern Signed-off-by: Ulf Hansson --- Some discussion started recently while I posted below patch: [RFC PATCH] PM / Runtime: Allow to inactivate devices during system suspend After some thinking I decided to cook another RFC, that might be better material for discussion. If we decide to go in this direction, the doc obviously needs some update as well, which is not a part of this RFC yet. --- drivers/base/power/main.c | 13 ++++++++++--- drivers/base/power/runtime.c | 1 + include/linux/pm.h | 1 + include/linux/pm_runtime.h | 13 +++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2a1b06a..838ebb6 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -832,7 +832,10 @@ static void device_complete(struct device *dev, pm_message_t state) device_unlock(dev); - pm_runtime_put(dev); + if (pm_runtime_suspend_prevented(dev)) + pm_runtime_put(dev); + else + pm_request_idle(dev); } /** @@ -1004,6 +1007,9 @@ static int device_suspend_late(struct device *dev, pm_message_t state) pm_callback_t callback = NULL; char *info = NULL; + if (!pm_runtime_suspend_prevented(dev)) + pm_runtime_idle(dev); + __pm_runtime_disable(dev, false); if (dev->power.syscore) @@ -1318,7 +1324,8 @@ static int device_prepare(struct device *dev, pm_message_t state) * block runtime suspend here, during the prepare phase, and allow * it again during the complete phase. */ - pm_runtime_get_noresume(dev); + if (pm_runtime_suspend_prevented(dev)) + pm_runtime_get_noresume(dev); device_lock(dev); @@ -1350,7 +1357,7 @@ static int device_prepare(struct device *dev, pm_message_t state) device_unlock(dev); - if (error) + if (error && pm_runtime_suspend_prevented(dev)) pm_runtime_put(dev); return error; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 72e00e6..bdac1e2 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1373,6 +1373,7 @@ void pm_runtime_init(struct device *dev) atomic_set(&dev->power.child_count, 0); pm_suspend_ignore_children(dev, false); dev->power.runtime_auto = true; + dev->power.prevent_suspend = true; dev->power.request_pending = false; dev->power.request = RPM_REQ_NONE; diff --git a/include/linux/pm.h b/include/linux/pm.h index a224c7f..98ef412 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -551,6 +551,7 @@ struct dev_pm_info { unsigned int use_autosuspend:1; unsigned int timer_autosuspends:1; unsigned int memalloc_noio:1; + unsigned int prevent_suspend:1; enum rpm_request request; enum rpm_status runtime_status; int runtime_error; diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 6fa7cea..2b72e30 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -106,6 +106,16 @@ static inline void pm_runtime_mark_last_busy(struct device *dev) ACCESS_ONCE(dev->power.last_busy) = jiffies; } +static inline void pm_runtime_no_prevent_suspend(struct device *dev) +{ + dev->power.prevent_suspend = false; +} + +static inline bool pm_runtime_suspend_prevented(struct device *dev) +{ + return dev->power.prevent_suspend; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int __pm_runtime_idle(struct device *dev, int rpmflags) @@ -157,6 +167,9 @@ static inline unsigned long pm_runtime_autosuspend_expiration( struct device *dev) { return 0; } static inline void pm_runtime_set_memalloc_noio(struct device *dev, bool enable){} +static inline void pm_runtime_no_prevent_suspend(struct device *dev) {} +static inline bool pm_runtime_suspend_prevented(struct device *dev) + { return false; } #endif /* !CONFIG_PM_RUNTIME */