power.no_suspend

[RFC][PATCH 0/3] PM: Mechanism to avoid resuming runtime-suspended devices during system suspend

第一个:

引进了power.no_suspend这个变量,设备设置这个变量可以保持在suspend状态。

在系统整体休眠的时候,子系统知道设备保持在supend状态,告诉PM改变设备的prepare回调,用来指示设备已经进入supend不需要进行resume操作。

如果prepare返回积极的一个数值,PM设置no_suspend,再后来的流程中将不会调用到设备的suspend函数。

然而,父节点通常还是需要resume,因为他们的子节点需要进行suspend。这样PM将清理no_suspend(除非父节点设置了ignore_children)。


第二个:

runtime PM加入了一个函数,在prepare时帮忙检查设备是否进入runtime suspend状态。

第三个:

实现子系统的ACPI PM


 drivers/base/power/main.c |   38 ++++++++++++++++++++++++++------------
 include/linux/pm.h        |    1 +
 2 files changed, 27 insertions(+), 12 deletions(-)

Index: linux-pm/drivers/base/power/main.c
===================================================================
--- linux-pm.orig/drivers/base/power/main.c
+++ linux-pm/drivers/base/power/main.c
@@ -918,7 +918,7 @@ static int device_suspend_noirq(struct d
        pm_callback_t callback = NULL;
        char *info = NULL;

-       if (dev->power.syscore)
+       if (dev->power.syscore || dev->power.no_suspend)
                return 0;

        if (dev->pm_domain) {
@@ -1006,7 +1006,7 @@ static int device_suspend_late(struct de

        __pm_runtime_disable(dev, false);

-       if (dev->power.syscore)
+       if (dev->power.syscore || dev->power.no_suspend)
                return 0;

        if (dev->pm_domain) {
@@ -1143,8 +1143,10 @@ static int __device_suspend(struct devic
         * for it, this is equivalent to the device signaling wakeup, so the
         * system suspend operation should be aborted.
         */
-       if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
+       if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
                pm_wakeup_event(dev, 0);
+               dev->power.no_suspend = false;
+       }

        if (pm_wakeup_pending()) {
                async_error = -EBUSY;
@@ -1157,6 +1159,9 @@ static int __device_suspend(struct devic
        dpm_watchdog_set(&wd, dev);
        device_lock(dev);

+       if (dev->power.no_suspend)
+               goto End;
+
        if (dev->pm_domain) {
                info = "power domain ";
                callback = pm_op(&dev->pm_domain->ops, state);
@@ -1205,9 +1210,13 @@ static int __device_suspend(struct devic
  End:
        if (!error) {
                dev->power.is_suspended = true;
-               if (dev->power.wakeup_path
-                   && dev->parent && !dev->parent->power.ignore_children)
-                       dev->parent->power.wakeup_path = true;
+               if (dev->parent && !dev->parent->power.ignore_children) {
+                       if (dev->power.wakeup_path)
+                               dev->parent->power.wakeup_path = true;
+
+                       if (!dev->power.no_suspend)
+                               dev->parent->power.no_suspend = false;
+               }
        }

        device_unlock(dev);
@@ -1307,7 +1316,7 @@ static int device_prepare(struct device
 {
        int (*callback)(struct device *) = NULL;
        char *info = NULL;
-       int error = 0;
+       int ret = 0;

        if (dev->power.syscore)
                return 0;
@@ -1323,6 +1332,7 @@ static int device_prepare(struct device
        device_lock(dev);

        dev->power.wakeup_path = device_may_wakeup(dev);
+       dev->power.no_suspend = false;

        if (dev->pm_domain) {
                info = "preparing power domain ";
@@ -1344,16 +1354,20 @@ static int device_prepare(struct device
        }

        if (callback) {
-               error = callback(dev);
-               suspend_report_result(callback, error);
+               ret = callback(dev);
+               suspend_report_result(callback, ret);
        }

        device_unlock(dev);

-       if (error)
+       if (ret < 0) {
                pm_runtime_put(dev);
+       } else if (ret > 0) {
+               dev->power.no_suspend = true;
+               ret = 0;
+       }

-       return error;
+       return ret;
 }

 /**
@@ -1422,7 +1436,7 @@ EXPORT_SYMBOL_GPL(dpm_suspend_start);

 void __suspend_report_result(const char *function, void *fn, int ret)
 {
-       if (ret)
+       if (ret < 0)
                printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
 }
 EXPORT_SYMBOL_GPL(__suspend_report_result);
Index: linux-pm/include/linux/pm.h
===================================================================
--- linux-pm.orig/include/linux/pm.h
+++ linux-pm/include/linux/pm.h
@@ -544,6 +544,7 @@ struct dev_pm_info {
        bool                    is_suspended:1; /* Ditto */
        bool                    ignore_children:1;
        bool                    early_init:1;   /* Owned by the PM core */
+       bool                    no_suspend:1;
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;




---
 drivers/base/power/runtime.c |   28 ++++++++++++++++++++++++++++
 include/linux/pm_runtime.h   |    2 ++
 2 files changed, 30 insertions(+)

Index: linux-pm/include/linux/pm_runtime.h
===================================================================
--- linux-pm.orig/include/linux/pm_runtime.h
+++ linux-pm/include/linux/pm_runtime.h
@@ -53,6 +53,7 @@ extern unsigned long pm_runtime_autosusp
 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 bool pm_runtime_enabled_and_suspended(struct device *dev);

 static inline bool pm_children_suspended(struct device *dev)
 {
@@ -161,6 +162,7 @@ static inline unsigned long pm_runtime_a
                                struct device *dev) { return 0; }
 static inline void pm_runtime_set_memalloc_noio(struct device *dev,
                                                bool enable){}
+static inline bool pm_runtime_enabled_and_suspended(struct device *dev) { return false };

 #endif /* !CONFIG_PM_RUNTIME */

Index: linux-pm/drivers/base/power/runtime.c
===================================================================
--- linux-pm.orig/drivers/base/power/runtime.c
+++ linux-pm/drivers/base/power/runtime.c
@@ -1194,6 +1194,34 @@ void pm_runtime_enable(struct device *de
 EXPORT_SYMBOL_GPL(pm_runtime_enable);

 /**
+ * pm_runtime_enabled_and_suspended - Check runtime PM status of a device.
+ * @dev: Device to handle.
+ *
+ * This routine is to be executed during system suspend only, after
+ * device_prepare() has been executed for @dev.
+ *
+ * Return false if runtime PM is disabled for the device.  Otherwise, wait
+ * for pending transitions to complete and check the runtime PM status of the
+ * device after that.  Return true if it is RPM_SUSPENDED.
+ */
+bool pm_runtime_enabled_and_suspended(struct device *dev)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&dev->power.lock, flags);
+       if (dev->power.disable_depth) {
+               ret = false;
+       } else {
+               __pm_runtime_barrier(dev);
+               ret = pm_runtime_status_suspended(dev);
+       }
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_enabled_and_suspended);
+
+/**
  * pm_runtime_forbid - Block runtime PM of a device.
  * @dev: Device to handle.
  *

--

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值