]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
PM: runtime: Drop runtime PM references to supplier on link removal
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 21 Oct 2020 19:12:15 +0000 (21:12 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 10 Nov 2020 11:37:34 +0000 (12:37 +0100)
commit e0e398e204634db8fb71bd89cf2f6e3e5bd09b51 upstream.

While removing a device link, drop the supplier device's runtime PM
usage counter as many times as needed to drop all of the runtime PM
references to it from the consumer in addition to dropping the
consumer's link count.

Fixes: baa8809f6097 ("PM / runtime: Optimize the use of device links")
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: 5.1+ <stable@vger.kernel.org> # 5.1+
Tested-by: Xiang Chen <chenxiang66@hisilicon.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/core.c
drivers/base/power/runtime.c
include/linux/pm_runtime.h

index 0fde3e9e63ee330d6b99eef315b8812af783d83d..ddfbd62d8bfc2f44eb935820b6c4bd9b1520f45b 100644 (file)
@@ -454,8 +454,7 @@ static void __device_link_del(struct kref *kref)
        dev_dbg(link->consumer, "Dropping the link to %s\n",
                dev_name(link->supplier));
 
-       if (link->flags & DL_FLAG_PM_RUNTIME)
-               pm_runtime_drop_link(link->consumer);
+       pm_runtime_drop_link(link);
 
        list_del_rcu(&link->s_node);
        list_del_rcu(&link->c_node);
@@ -469,8 +468,7 @@ static void __device_link_del(struct kref *kref)
        dev_info(link->consumer, "Dropping the link to %s\n",
                 dev_name(link->supplier));
 
-       if (link->flags & DL_FLAG_PM_RUNTIME)
-               pm_runtime_drop_link(link->consumer);
+       pm_runtime_drop_link(link);
 
        list_del(&link->s_node);
        list_del(&link->c_node);
index 4244e22e4b403f7679d0958a15d9663e16b9d7c8..159e9c6e16c2d66d2e1cdf20271c75917ad288a8 100644 (file)
@@ -1702,7 +1702,7 @@ void pm_runtime_new_link(struct device *dev)
        spin_unlock_irq(&dev->power.lock);
 }
 
-void pm_runtime_drop_link(struct device *dev)
+static void pm_runtime_drop_link_count(struct device *dev)
 {
        spin_lock_irq(&dev->power.lock);
        WARN_ON(dev->power.links_count == 0);
@@ -1710,6 +1710,25 @@ void pm_runtime_drop_link(struct device *dev)
        spin_unlock_irq(&dev->power.lock);
 }
 
+/**
+ * pm_runtime_drop_link - Prepare for device link removal.
+ * @link: Device link going away.
+ *
+ * Drop the link count of the consumer end of @link and decrement the supplier
+ * device's runtime PM usage counter as many times as needed to drop all of the
+ * PM runtime reference to it from the consumer.
+ */
+void pm_runtime_drop_link(struct device_link *link)
+{
+       if (!(link->flags & DL_FLAG_PM_RUNTIME))
+               return;
+
+       pm_runtime_drop_link_count(link->consumer);
+
+       while (refcount_dec_not_one(&link->rpm_active))
+               pm_runtime_put(link->supplier);
+}
+
 static bool pm_runtime_need_not_resume(struct device *dev)
 {
        return atomic_read(&dev->power.usage_count) <= 1 &&
index 22af69d237a65dce64406e7992191c0e6de38709..d805fb1ae880cade0ec00889ff28e1739ebd8ccd 100644 (file)
@@ -58,7 +58,7 @@ extern void pm_runtime_clean_up_links(struct device *dev);
 extern void pm_runtime_get_suppliers(struct device *dev);
 extern void pm_runtime_put_suppliers(struct device *dev);
 extern void pm_runtime_new_link(struct device *dev);
-extern void pm_runtime_drop_link(struct device *dev);
+extern void pm_runtime_drop_link(struct device_link *link);
 
 static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
 {
@@ -177,7 +177,7 @@ static inline void pm_runtime_clean_up_links(struct device *dev) {}
 static inline void pm_runtime_get_suppliers(struct device *dev) {}
 static inline void pm_runtime_put_suppliers(struct device *dev) {}
 static inline void pm_runtime_new_link(struct device *dev) {}
-static inline void pm_runtime_drop_link(struct device *dev) {}
+static inline void pm_runtime_drop_link(struct device_link *link) {}
 
 #endif /* !CONFIG_PM */