Browse Source

PM / runtime: Drop children check from __pm_runtime_set_status()

The check for "active" children in __pm_runtime_set_status(), when
trying to set the parent device status to "suspended", doesn't
really make sense, because in fact it is not invalid to set the
status of a device with runtime PM disabled to "suspended" in any
case.  It is invalid to enable runtime PM for a device with its
status set to "suspended" while its child_count reference counter
is nonzero, but the check in __pm_runtime_set_status() doesn't
really cover that situation.

For this reason, drop the children check from __pm_runtime_set_status()
and add a check against child_count reference counters of "suspended"
devices to pm_runtime_enable().

Fixes: a8636c89648a (PM / Runtime: Don't allow to suspend a device with an active child)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Johan Hovold <johan@kernel.org>
Rafael J. Wysocki 7 years ago
parent
commit
f8817f61e8
2 changed files with 12 additions and 22 deletions
  1. 1 2
      Documentation/power/runtime_pm.txt
  2. 11 20
      drivers/base/power/runtime.c

+ 1 - 2
Documentation/power/runtime_pm.txt

@@ -435,8 +435,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       PM status to 'suspended' and update its parent's counter of 'active'
       PM status to 'suspended' and update its parent's counter of 'active'
       children as appropriate (it is only valid to use this function if
       children as appropriate (it is only valid to use this function if
       'power.runtime_error' is set or 'power.disable_depth' is greater than
       'power.runtime_error' is set or 'power.disable_depth' is greater than
-      zero); it will fail and return an error code if the device has a child
-      which is active and the 'power.ignore_children' flag is unset
+      zero)
 
 
   bool pm_runtime_active(struct device *dev);
   bool pm_runtime_active(struct device *dev);
     - return true if the device's runtime PM status is 'active' or its
     - return true if the device's runtime PM status is 'active' or its

+ 11 - 20
drivers/base/power/runtime.c

@@ -1101,29 +1101,13 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	if (dev->power.runtime_status == status)
+	if (dev->power.runtime_status == status || !parent)
 		goto out_set;
 		goto out_set;
 
 
 	if (status == RPM_SUSPENDED) {
 	if (status == RPM_SUSPENDED) {
-		/*
-		 * It is invalid to suspend a device with an active child,
-		 * unless it has been set to ignore its children.
-		 */
-		if (!dev->power.ignore_children &&
-			atomic_read(&dev->power.child_count)) {
-			dev_err(dev, "runtime PM trying to suspend device but active child\n");
-			error = -EBUSY;
-			goto out;
-		}
-
-		if (parent) {
-			atomic_add_unless(&parent->power.child_count, -1, 0);
-			notify_parent = !parent->power.ignore_children;
-		}
-		goto out_set;
-	}
-
-	if (parent) {
+		atomic_add_unless(&parent->power.child_count, -1, 0);
+		notify_parent = !parent->power.ignore_children;
+	} else {
 		spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
 		spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
 
 
 		/*
 		/*
@@ -1307,6 +1291,13 @@ void pm_runtime_enable(struct device *dev)
 	else
 	else
 		dev_warn(dev, "Unbalanced %s!\n", __func__);
 		dev_warn(dev, "Unbalanced %s!\n", __func__);
 
 
+	WARN(!dev->power.disable_depth &&
+	     dev->power.runtime_status == RPM_SUSPENDED &&
+	     !dev->power.ignore_children &&
+	     atomic_read(&dev->power.child_count) > 0,
+	     "Enabling runtime PM for inactive device (%s) with active children\n",
+	     dev_name(dev));
+
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 }
 }
 EXPORT_SYMBOL_GPL(pm_runtime_enable);
 EXPORT_SYMBOL_GPL(pm_runtime_enable);