From patchwork Wed Jun 8 10:25:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 9164173 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 8045560832 for ; Wed, 8 Jun 2016 10:28:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7263F28345 for ; Wed, 8 Jun 2016 10:28:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 676842835E; Wed, 8 Jun 2016 10:28:15 +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=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DB42B28345 for ; Wed, 8 Jun 2016 10:28:14 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1bAah5-0004nV-BP; Wed, 08 Jun 2016 10:26:39 +0000 Received: from mailout4.w1.samsung.com ([210.118.77.14]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1bAagt-0004ch-Ti for linux-arm-kernel@lists.infradead.org; Wed, 08 Jun 2016 10:26:29 +0000 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O8G006KN7NFMUA0@mailout4.w1.samsung.com> for linux-arm-kernel@lists.infradead.org; Wed, 08 Jun 2016 11:26:03 +0100 (BST) X-AuditID: cbfec7f4-f796c6d000001486-83-5757f2bbaf00 Received: from eusync2.samsung.com ( [203.254.199.212]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id D9.4C.05254.BB2F7575; Wed, 8 Jun 2016 11:26:03 +0100 (BST) Received: from amdc1339.digital.local ([106.116.147.30]) by eusync2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O8G00JJJ7NAQH70@eusync2.samsung.com>; Wed, 08 Jun 2016 11:26:03 +0100 (BST) From: Marek Szyprowski To: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/3] PM / Runtime: Add notifiers for device runtime PM events Date: Wed, 08 Jun 2016 12:25:54 +0200 Message-id: <1465381556-2230-2-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.2 In-reply-to: <1465381556-2230-1-git-send-email-m.szyprowski@samsung.com> References: <1465381556-2230-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrPLMWRmVeSWpSXmKPExsVy+t/xK7q7P4WHG8w4rGixccZ6VotJ9yew WCzYb23ROXsDu8XrF4YW/Y9fM1tsenyN1eLyrjlsFp97jzBazDi/j8li7ZG77BZnTl9itTi+ NtyB1+PJwXlMHptWdbJ53Lm2h81j85J6j8k3ljN6bLnazuLRt2UVo8fnTXIBHFFcNimpOZll qUX6dglcGd+bHjMX/HCrOH/nJ3sD42zrLkZODgkBE4nXWw+wQ9hiEhfurWfrYuTiEBJYyigx f/l+ZginiUni6cyTYFVsAoYSXW+7wKpEBFYySmzbsw+silngNJPE5xUr2ECqhAV8JW7dXMsK YrMIqEqcfXKWEcTmFXCXWLF7ATPEPjmJ/y9XMIHYnAIeEi8mTgfrFQKqubd5FssERt4FjAyr GEVTS5MLipPScw31ihNzi0vz0vWS83M3MUKC9csOxsXHrA4xCnAwKvHwKhiGhwuxJpYVV+Ye YpTgYFYS4a38CBTiTUmsrEotyo8vKs1JLT7EKM3BoiTOO3fX+xAhgfTEktTs1NSC1CKYLBMH p1QDo8YslvPJPuoqcx/uee6lraYWpX9K7G/+gkcXVZcX5dx5u6WYPfCw8vudoXnH63zPPKs0 bpO//+7q4a4ZUdcinH8YHBCdM/3pLjmWzvgfthferNSvXtUTcdt/9Zncc8zOTfozeARfft7z kc1N5t/tqa1Z8a13GP4vvP/GxHqKwv+ber8frs3d/liJpTgj0VCLuag4EQAaFsdsUgIAAA== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160608_032628_150144_0F8D5246 X-CRM114-Status: GOOD ( 23.15 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz , Joerg Roedel , "Rafael J. Wysocki" , Ulf Hansson , Inki Dae , Kukjin Kim , Marek Szyprowski MIME-Version: 1.0 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: Krzysztof Kozlowski Allow drivers registering for certain runtime PM events of other devices. Some drivers in power domain are more or less coupled. When one driver is suspending (thus leading to power domain being also turned off) the other might have to perform some necessary steps. For example Exynos IOMMU has to save its context. Based on previous work of Sylwester Nawrocki . Signed-off-by: Krzysztof Kozlowski Signed-off-by: Marek Szyprowski --- drivers/base/power/generic_ops.c | 9 +++++++ drivers/base/power/power.h | 6 +++++ drivers/base/power/runtime.c | 34 +++++++++++++++++++++++++-- include/linux/pm.h | 2 ++ include/linux/pm_runtime.h | 51 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 07c3c4a9522d..f0838229b781 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -10,6 +10,7 @@ #include #include #include +#include "power.h" #ifdef CONFIG_PM /** @@ -25,8 +26,12 @@ int pm_generic_runtime_suspend(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int ret; + pm_runtime_notifier_call(dev, RPM_EVENT_SUSPEND_PRE); + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0; + pm_runtime_notifier_call(dev, RPM_EVENT_SUSPEND_POST); + return ret; } EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); @@ -44,8 +49,12 @@ int pm_generic_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int ret; + pm_runtime_notifier_call(dev, RPM_EVENT_RESUME_PRE); + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0; + pm_runtime_notifier_call(dev, RPM_EVENT_RESUME_POST); + return ret; } EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 50e30e7b059d..30b6319ce96c 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -1,4 +1,5 @@ #include +#include static inline void device_pm_init_common(struct device *dev) { @@ -20,6 +21,7 @@ static inline void pm_runtime_early_init(struct device *dev) extern void pm_runtime_init(struct device *dev); extern void pm_runtime_reinit(struct device *dev); extern void pm_runtime_remove(struct device *dev); +extern int pm_runtime_notifier_call(struct device *dev, enum rpm_event event); struct wake_irq { struct device *dev; @@ -87,6 +89,10 @@ static inline void pm_runtime_early_init(struct device *dev) static inline void pm_runtime_init(struct device *dev) {} static inline void pm_runtime_reinit(struct device *dev) {} static inline void pm_runtime_remove(struct device *dev) {} +static inline pm_runtime_notifier_call(struct device *dev, enum rpm_event event) +{ + return 0; +} static inline int dpm_sysfs_add(struct device *dev) { return 0; } static inline void dpm_sysfs_remove(struct device *dev) {} diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index b74690418504..3a5637ca8400 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -227,6 +227,27 @@ void pm_runtime_set_memalloc_noio(struct device *dev, bool enable) } EXPORT_SYMBOL_GPL(pm_runtime_set_memalloc_noio); +int pm_runtime_notifier_call(struct device *dev, enum rpm_event event) +{ + return atomic_notifier_call_chain(&dev->power.runtime_notifier, + event, dev); +} + +int pm_runtime_register_notifier(struct device *dev, struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&dev->power.runtime_notifier, + nb); +} +EXPORT_SYMBOL_GPL(pm_runtime_register_notifier); + +int pm_runtime_unregister_notifier(struct device *dev, + struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&dev->power.runtime_notifier, + nb); +} +EXPORT_SYMBOL_GPL(pm_runtime_unregister_notifier); + /** * rpm_check_suspend_allowed - Test whether a device may be suspended. * @dev: Device to test. @@ -1174,6 +1195,7 @@ void __pm_runtime_disable(struct device *dev, bool check_resume) goto out; } + pm_runtime_notifier_call(dev, RPM_EVENT_DISABLE_PRE); /* * Wake up the device if there's a resume request pending, because that * means there probably is some I/O to process and disabling runtime PM @@ -1195,6 +1217,7 @@ void __pm_runtime_disable(struct device *dev, bool check_resume) if (!dev->power.disable_depth++) __pm_runtime_barrier(dev); + pm_runtime_notifier_call(dev, RPM_EVENT_DISABLE_POST); out: spin_unlock_irq(&dev->power.lock); } @@ -1210,10 +1233,16 @@ void pm_runtime_enable(struct device *dev) spin_lock_irqsave(&dev->power.lock, flags); - if (dev->power.disable_depth > 0) + if (dev->power.disable_depth > 0) { + if (dev->power.disable_depth == 1) + pm_runtime_notifier_call(dev, RPM_EVENT_ENABLE_PRE); dev->power.disable_depth--; - else + } else { dev_warn(dev, "Unbalanced %s!\n", __func__); + } + + if (dev->power.disable_depth == 0) + pm_runtime_notifier_call(dev, RPM_EVENT_ENABLE_POST); spin_unlock_irqrestore(&dev->power.lock, flags); } @@ -1411,6 +1440,7 @@ void pm_runtime_init(struct device *dev) (unsigned long)dev); init_waitqueue_head(&dev->power.wait_queue); + ATOMIC_INIT_NOTIFIER_HEAD(&dev->power.runtime_notifier); } /** diff --git a/include/linux/pm.h b/include/linux/pm.h index 06eb353182ab..bdf6eaaf62ec 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -27,6 +27,7 @@ #include #include #include +#include /* * Callbacks for platform drivers to implement. @@ -604,6 +605,7 @@ struct dev_pm_info { unsigned long active_jiffies; unsigned long suspended_jiffies; unsigned long accounting_timestamp; + struct atomic_notifier_head runtime_notifier; #endif struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ void (*set_latency_tolerance)(struct device *, s32); diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 2e14d2667b6c..82d41a6a6f5c 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -23,6 +23,43 @@ usage_count */ #define RPM_AUTO 0x08 /* Use autosuspend_delay */ +/** + * Runtime PM notifier events. + * + * TODO: RPM_EVENT_SUSPEND/RPM_EVENT_RESUME are supported + * currently only with generic power domains. They won't be executed + * in other cases. Fix this. + * + * RPM_EVENT_SUSPEND_PRE Before calling device suspend callback + * and before turning domain off + * RPM_EVENT_SUSPEND_POST After suspending device and before turning + * domain off + * + * RPM_EVENT_RESUME_PRE Before calling device resume callback + * but after turning domain on + * RPM_EVENT_RESUME_POST After resuming device + * + * RPM_EVENT_ENABLE_PRE Before effectively enabling runtime PM + * (the pm_runtime_enable() call must undo the + * last pm_runtime_disable() call) + * RPM_EVENT_ENABLE_POST After effectively enabling runtime PM + * + * RPM_EVENT_DISABLE_PRE Before effectively disabling runtime PM + * (the first pm_runtime_disable() call) + * RPM_EVENT_DISABLE_POST After effectively disabling runtime PM + */ +enum rpm_event { + RPM_EVENT_SUSPEND_PRE, + RPM_EVENT_SUSPEND_POST, + RPM_EVENT_RESUME_PRE, + RPM_EVENT_RESUME_POST, + RPM_EVENT_ENABLE_PRE, + RPM_EVENT_ENABLE_POST, + RPM_EVENT_DISABLE_PRE, + RPM_EVENT_DISABLE_POST, + RPM_EVENT_NUM, +}; + #ifdef CONFIG_PM extern struct workqueue_struct *pm_wq; @@ -55,6 +92,10 @@ extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev); extern void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns); extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable); +extern int pm_runtime_register_notifier(struct device *dev, + struct notifier_block *nb); +extern int pm_runtime_unregister_notifier(struct device *dev, + struct notifier_block *nb); static inline void pm_suspend_ignore_children(struct device *dev, bool enable) { @@ -186,6 +227,16 @@ 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 int pm_runtime_register_notifier(struct device *dev, + struct notifier_block *nb) +{ + return -ENOSYS; +} +static innline int pm_runtime_unregister_notifier(struct device *dev, + struct notifier_block *nb) +{ + return 0; +}; #endif /* !CONFIG_PM */