From patchwork Wed May 11 05:18:24 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: MyungJoo Ham X-Patchwork-Id: 775832 Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [140.211.169.13]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p4B5QvVo005256 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Wed, 11 May 2011 05:27:18 GMT Received: from daredevil.linux-foundation.org (localhost [127.0.0.1]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p4B5OJnP011930; Tue, 10 May 2011 22:24:49 -0700 Received: from mailout2.samsung.com (mailout2.samsung.com [203.254.224.25]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p4B5ITJ5011541 for ; Tue, 10 May 2011 22:18:32 -0700 Received: from epcpsbgm1.samsung.com (mailout2.samsung.com [203.254.224.25]) by mailout2.samsung.com (Oracle Communications Messaging Exchange Server 7u4-19.01 64bit (built Sep 7 2010)) with ESMTP id <0LL00038CMPTFZ50@mailout2.samsung.com> for linux-pm@lists.linux-foundation.org; Wed, 11 May 2011 14:18:26 +0900 (KST) X-AuditID: cbfee61a-b7c84ae000006ee6-ba-4dca1c22d1ff Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (MMPCPMTA) with SMTP id 6C.E5.28390.22C1ACD4; Wed, 11 May 2011 14:18:26 +0900 (KST) Received: from TNRNDGASPAPP1.tn.corp.samsungelectronics.net ([165.213.149.150]) by mmp2.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004)) with ESMTPA id <0LL0008THMQQJO@mmp2.samsung.com> for linux-pm@lists.linux-foundation.org; Wed, 11 May 2011 14:18:26 +0900 (KST) Received: from localhost.localdomain ([165.213.219.116]) by TNRNDGASPAPP1.tn.corp.samsungelectronics.net with Microsoft SMTPSVC(6.0.3790.4675); Wed, 11 May 2011 14:18:25 +0900 Date: Wed, 11 May 2011 14:18:24 +0900 From: MyungJoo Ham To: linux-pm@lists.linux-foundation.org Message-id: <1305091105-27173-1-git-send-email-myungjoo.ham@samsung.com> X-Mailer: git-send-email 1.7.4.1 X-OriginalArrivalTime: 11 May 2011 05:18:25.0817 (UTC) FILETIME=[DADC9090:01CC0F9A] X-Brightmail-Tracker: AAAAAA== Received-SPF: pass (localhost is always allowed.) X-Spam-Status: No, hits=-12.169 required=5 tests=AWL, BAYES_00, OSDL_HEADER_SUBJECT_BRACKETED, SAMSUNG_WEBMAIL_OSDL X-Spam-Checker-Version: SpamAssassin 3.2.4-osdl_revision__1.47__ X-MIMEDefang-Filter: lf$Revision: 1.188 $ X-Scanned-By: MIMEDefang 2.63 on 140.211.169.21 Cc: Len Brown , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, kyungmin.park@samsung.com Subject: [linux-pm] [RFC PATCH v3 1/2] PM / Core: suspend_again callback for suspend_ops. X-BeenThere: linux-pm@lists.linux-foundation.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux power management List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-pm-bounces@lists.linux-foundation.org Errors-To: linux-pm-bounces@lists.linux-foundation.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Wed, 11 May 2011 05:27:18 +0000 (UTC) A system or a device may need to control suspend/wakeup events. It may want to wakeup the system after a predefined amount of time or at a predefined event decided while entering suspend for polling or delayed work. Then, it may want to enter suspend again if its predefined wakeup condition is the only wakeup reason and there is no outstanding events; thus, it does not wakeup the userspace unnecessary or unnecessary devices and keeps suspended as long as possible (saving the power). Enabling a system to wakeup after a specified time can be easily achieved by using RTC. However, to enter suspend again immediately without invoking userland and unrelated devices, we need additional features in the suspend framework. Such need comes from: 1. Monitoring a critical device status without interrupts that can wakeup the system. (in-suspend polling) An example is ambient temperature monitoring that needs to shut down the system or a specific device function if it is too hot or cold. The temperature of a specific device may be needed to be monitored as well; e.g., a charger monitors battery temperature in order to stop charging if overheated. 2. Execute critical "delayed work" at suspend. A driver or a system/board may have a delayed work (or any similar things) that it wants to execute at the requested time. For example, some chargers want to check the battery voltage some time (e.g., 30 seconds) after the battery is fully charged and the charger has stopped. Then, the charger restarts charging if the voltage has dropped more than a threshold, which is smaller than "restart-charger" voltage, which is a threshold to restart charging regardless of the time passed. This patch allows to add "suspend_again" callback at struct platform_suspend_ops and let the "suspend_again" callback return true if the system is required to enter suspend again after the current instance of wakeup. Device-wise suspend_again implemented at dev_pm_ops or syscore is not done because: a) suspend_again feature is usually under platform-wise decision and controls the behavior of the whole platform and b) There are very limited devices related to the usage cases of suspend_again; chargers and temperature sensors are mentioned so far. With suspend_again callback registered at struct platform_suspend_ops suspend_ops in kernel/power/suspend.c with suspend_set_ops by the platform, the suspend framework tries to enter suspend again by looping suspend_enter() if suspend_again has returned true and there has been no errors in the suspending sequence or pending wakeups (by pm_wakeup_pending). Tested at Exynos4-NURI. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park --- Changed from v2: - moved (again) from dev_pm_ops to suspend_ops - settled suspend_again point at around suspend_enter(). Changes from v1: - moved from syscore to dev_pm_ops - added generic ops for subsystems. - cleaned up suspend_again code at kernel/power/suspend. --- include/linux/suspend.h | 8 ++++++++ kernel/power/suspend.c | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 5a89e36..caf5e97 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -92,6 +92,13 @@ typedef int __bitwise suspend_state_t; * @enter() and @wake(), even if any of them fails. It is executed after * a failing @prepare. * + * @suspend_again: Returns whether the system should suspend again (true) or + * not (false). If the platform wants to poll sensors or execute some + * code during suspended without invoking userspace and most of devices, + * suspend_again callback is the place assuming that periodic-wakeup or + * alarm-wakeup is already setup. This allows to execute some codes while + * being kept suspended in the view of userland and devices. + * * @end: Called by the PM core right after resuming devices, to indicate to * the platform that the system has returned to the working state or * the transition to the sleep state has been aborted. @@ -113,6 +120,7 @@ struct platform_suspend_ops { int (*enter)(suspend_state_t state); void (*wake)(void); void (*finish)(void); + bool (*suspend_again)(void); void (*end)(void); void (*recover)(void); }; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 08515b4..e655f43 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -128,10 +128,12 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) /** * suspend_enter - enter the desired system sleep state. * @state: state to enter + * @pm_wkup_pending: indicates that the power transition in progress + * should be aborted. * * This function should be called after devices have been suspended. */ -static int suspend_enter(suspend_state_t state) +static int suspend_enter(suspend_state_t state, bool *pm_wkup_pending) { int error; @@ -167,7 +169,8 @@ static int suspend_enter(suspend_state_t state) if (!error) error = syscore_suspend(); if (!error) { - if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { + *pm_wkup_pending = pm_wakeup_pending(); + if (!(suspend_test(TEST_CORE) || *pm_wkup_pending)) { error = suspend_ops->enter(state); events_check_enabled = false; } @@ -202,6 +205,7 @@ static int suspend_enter(suspend_state_t state) int suspend_devices_and_enter(suspend_state_t state) { int error; + bool pm_wkup_pending = false; if (!suspend_ops) return -ENOSYS; @@ -224,7 +228,10 @@ int suspend_devices_and_enter(suspend_state_t state) if (suspend_test(TEST_DEVICES)) goto Recover_platform; - error = suspend_enter(state); + do { + error = suspend_enter(state, &pm_wkup_pending); + } while (suspend_ops->suspend_again && suspend_ops->suspend_again() && + !error && !pm_wkup_pending); Resume_devices: suspend_test_start();