Skip to contentSkip to conversation

PM / Runtime: rpm_suspend() and rpm_resume() fixes

PATCH In review Rafael J. Wysocki 2 participants 9 messages Aug 14, 2012 – Aug 15, 2012

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover PM / Runtime: rpm_suspend() and rpm_resume() fixes

Hi,

The following three patches fix minor issues in rpm_suspend() and rpm_resume(). They are on top of the current linux-next branch of the linux-pm.git tree, but they should apply to the mainline too.

[1/3] - Fix rpm_resume() return value for power.no_callbacks set and active
parent.
[2/3] - Move the clearing of power.deferred_resume in rpm_suspend() to a better
place.
[3/3] - Check the PM QoS setting before doing the first power.no_callbacks check.

Thanks,
Rafael

#1 lore raw

PATCH 1/3 PM / Runtime: Fix rpm_resume() return value for power.no_callbacks set

For devices whose power.no_callbacks flag is set, rpm_resume() should return 1 if the device's parent is already active, so that the callers of pm_runtime_get() don't think that they have to wait for the device to resume (asynchronously) in that case (the core won't queue up an asynchronous resume in that case, so there's nothing to wait for anyway).

Modify the code accordingly (and make sure that an idle notification will be queued up on success, even if 1 is to be returned).

---
 drivers/base/power/runtime.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/base/power/runtime.c +2 -1
Index: linux/drivers/base/power/runtime.c
===================================================================
@@ -584,6 +584,7 @@ static int rpm_resume(struct device *dev
 		    || dev->parent->power.runtime_status == RPM_ACTIVE) {
 			atomic_inc(&dev->parent->power.child_count);
 			spin_unlock(&dev->parent->power.lock);
+			retval = 1;
 			goto no_callback;	/* Assume success. */
 		}
 		spin_unlock(&dev->parent->power.lock);
@@ -664,7 +665,7 @@ static int rpm_resume(struct device *dev
 	}
 	wake_up_all(&dev->power.wait_queue);
 
-	if (!retval)
+	if (retval >= 0)
 		rpm_idle(dev, RPM_ASYNC);
 
  out:
Acked-by on v1 1/3
#2 lore raw

Re: [PATCH 1/3] PM / Runtime: Fix rpm_resume() return value for power.no_callbacks set

Quoted 29 lines · Rafael J. Wysocki

For devices whose power.no_callbacks flag is set, rpm_resume() should return 1 if the device's parent is already active, so that the callers of pm_runtime_get() don't think that they have to wait for the device to resume (asynchronously) in that case (the core won't queue up an asynchronous resume in that case, so there's nothing to wait for anyway).

Modify the code accordingly (and make sure that an idle notification will be queued up on success, even if 1 is to be returned).

---
 drivers/base/power/runtime.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux/drivers/base/power/runtime.c
===================================================================

drivers/base/power/runtime.c +1 -0
@@ -584,6 +584,7 @@ static int rpm_resume(struct device *dev
 		    || dev->parent->power.runtime_status == RPM_ACTIVE) {
 			atomic_inc(&dev->parent->power.child_count);
 			spin_unlock(&dev->parent->power.lock);
+			retval = 1;
 			goto no_callback;	/* Assume success. */
 		}
 		spin_unlock(&dev->parent->power.lock);

drivers/base/power/runtime.c static int rpm_resume(struct device *dev · line 671

Quoted 8 lines
drivers/base/power/runtime.c +1 -1
@@ -664,7 +665,7 @@ static int rpm_resume(struct device *dev
 	}
 	wake_up_all(&dev->power.wait_queue);
 
-	if (!retval)
+	if (retval >= 0)
 		rpm_idle(dev, RPM_ASYNC);
 
  out:
#3 lore raw

PATCH 2/3 PM / Runtime: Clear power.deferred_resume on success in rpm_suspend()

In reply to Rafael J. Wysocki

The power.deferred_resume can only be set if the runtime PM status of device is RPM_SUSPENDING and it should be cleared after its status has been changed, regardless of whether or not the runtime suspend has been successful. However, it only is cleared on suspend failure, while it may remain set after successful suspend and is happily leaked to rpm_resume() executed in that case.

That shouldn't happen, so if power.deferred_resume is set in rpm_suspend() after the status has been changed to RPM_SUSPENDED, clear it before calling rpm_resume(). Then, it doesn't need to be cleared before changing the status to RPM_SUSPENDING any more, because it's always cleared after the status has been changed to either RPM_SUSPENDED (on success) or RPM_ACTIVE (on failure).

---
 drivers/base/power/runtime.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/base/power/runtime.c +1 -1
Index: linux/drivers/base/power/runtime.c
===================================================================
@@ -388,7 +388,6 @@ static int rpm_suspend(struct device *de
 		goto repeat;
 	}
 
-	dev->power.deferred_resume = false;
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 
@@ -440,6 +439,7 @@ static int rpm_suspend(struct device *de
 	wake_up_all(&dev->power.wait_queue);
 
 	if (dev->power.deferred_resume) {
+		dev->power.deferred_resume = false;
 		rpm_resume(dev, 0);
 		retval = -EAGAIN;
 		goto out;
Acked-by on v1 2/3
#4 lore raw

Re: [PATCH 2/3] PM / Runtime: Clear power.deferred_resume on success in rpm_suspend()

Quoted 33 lines · Rafael J. Wysocki

The power.deferred_resume can only be set if the runtime PM status of device is RPM_SUSPENDING and it should be cleared after its status has been changed, regardless of whether or not the runtime suspend has been successful. However, it only is cleared on suspend failure, while it may remain set after successful suspend and is happily leaked to rpm_resume() executed in that case.

That shouldn't happen, so if power.deferred_resume is set in rpm_suspend() after the status has been changed to RPM_SUSPENDED, clear it before calling rpm_resume(). Then, it doesn't need to be cleared before changing the status to RPM_SUSPENDING any more, because it's always cleared after the status has been changed to either RPM_SUSPENDED (on success) or RPM_ACTIVE (on failure).

---
 drivers/base/power/runtime.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux/drivers/base/power/runtime.c
===================================================================

drivers/base/power/runtime.c +0 -1
@@ -388,7 +388,6 @@ static int rpm_suspend(struct device *de
 		goto repeat;
 	}
 
-	dev->power.deferred_resume = false;
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 

drivers/base/power/runtime.c static int rpm_suspend(struct device *de · line 445

Quoted 7 lines
drivers/base/power/runtime.c +1 -0
@@ -440,6 +439,7 @@ static int rpm_suspend(struct device *de
 	wake_up_all(&dev->power.wait_queue);
 
 	if (dev->power.deferred_resume) {
+		dev->power.deferred_resume = false;
 		rpm_resume(dev, 0);
 		retval = -EAGAIN;
 		goto out;

Basically this comes down to a matter of taste. I tend to use a "lazy" approach, not initializing values until they need to contain a proper value (and not worrying if they contain garbage or wrong values at times when they won't be used).

But of course, this is fine too. With this change, you can also simplify one of the tests in rpm_check_suspend_allowed().

#5 lore raw

PATCH 3/3 PM / Runtime: Check device PM QoS setting before "no callbacks" check

In reply to Rafael J. Wysocki

If __dev_pm_qos_read_value(dev) returns a negative value, rpm_suspend() should return -EPERM for dev even if its power.no_callbacks flag is set. For this to happen, the device's power.no_callbacks flag has to be checked after the PM QoS check, so modify the code accordingly.

---
 drivers/base/power/runtime.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/base/power/runtime.c +6 -6
Index: linux/drivers/base/power/runtime.c
===================================================================
@@ -388,6 +388,12 @@ static int rpm_suspend(struct device *de
 		goto repeat;
 	}
 
+	if (__dev_pm_qos_read_value(dev) < 0) {
+		/* Negative PM QoS constraint means "never suspend". */
+		retval = -EPERM;
+		goto out;
+	}
+
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 
@@ -402,12 +408,6 @@ static int rpm_suspend(struct device *de
 		goto out;
 	}
 
-	if (__dev_pm_qos_read_value(dev) < 0) {
-		/* Negative PM QoS constraint means "never suspend". */
-		retval = -EPERM;
-		goto out;
-	}
-
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
 	if (dev->pm_domain)
#6 lore raw

Re: [PATCH 3/3] PM / Runtime: Check device PM QoS setting before "no callbacks" check

Quoted 32 lines · Rafael J. Wysocki

If __dev_pm_qos_read_value(dev) returns a negative value, rpm_suspend() should return -EPERM for dev even if its power.no_callbacks flag is set. For this to happen, the device's power.no_callbacks flag has to be checked after the PM QoS check, so modify the code accordingly.

---
 drivers/base/power/runtime.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Index: linux/drivers/base/power/runtime.c
===================================================================

drivers/base/power/runtime.c +6 -0
@@ -388,6 +388,12 @@ static int rpm_suspend(struct device *de
 		goto repeat;
 	}
 
+	if (__dev_pm_qos_read_value(dev) < 0) {
+		/* Negative PM QoS constraint means "never suspend". */
+		retval = -EPERM;
+		goto out;
+	}
+
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 
@@ -402,12 +408,6 @@ static int rpm_suspend(struct device *de
 		goto out;
 	}

drivers/base/power/runtime.c static int rpm_suspend(struct device *de · line 413

Quoted 10 lines
drivers/base/power/runtime.c +0 -6
 
-	if (__dev_pm_qos_read_value(dev) < 0) {
-		/* Negative PM QoS constraint means "never suspend". */
-		retval = -EPERM;
-		goto out;
-	}
-
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
 	if (dev->pm_domain)

Wouldn't it be better to move the test into rpm_check_suspend_allowed()? Then it would apply to idle notifications and pm_schedule_suspend().

Alan Stern

#7 lore raw

PATCH 3/3 PM / Runtime: Check device PM QoS setting before "no callbacks" check

Quoted 43 lines · Alan Stern
Quoted 41 lines · Rafael J. Wysocki

If __dev_pm_qos_read_value(dev) returns a negative value, rpm_suspend() should return -EPERM for dev even if its power.no_callbacks flag is set. For this to happen, the device's power.no_callbacks flag has to be checked after the PM QoS check, so modify the code accordingly.

---
 drivers/base/power/runtime.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Index: linux/drivers/base/power/runtime.c
===================================================================

drivers/base/power/runtime.c +6 -6
@@ -388,6 +388,12 @@ static int rpm_suspend(struct device *de
 		goto repeat;
 	}
 
+	if (__dev_pm_qos_read_value(dev) < 0) {
+		/* Negative PM QoS constraint means "never suspend". */
+		retval = -EPERM;
+		goto out;
+	}
+
 	if (dev->power.no_callbacks)
 		goto no_callback;	/* Assume success. */
 
@@ -402,12 +408,6 @@ static int rpm_suspend(struct device *de
 		goto out;
 	}
 
-	if (__dev_pm_qos_read_value(dev) < 0) {
-		/* Negative PM QoS constraint means "never suspend". */
-		retval = -EPERM;
-		goto out;
-	}
-
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
Quoted 5 lines

drivers/base/power/runtime.c static int rpm_suspend(struct device *de · line 413

Quoted 1 line
drivers/base/power/runtime.c +0 -0
 	if (dev->pm_domain)

Wouldn't it be better to move the test into rpm_check_suspend_allowed()? Then it would apply to idle notifications and pm_schedule_suspend().

Yes, that makes sense.

Updated patch is appended.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: PM / Runtime: Check device PM QoS setting before "no callbacks"

If __dev_pm_qos_read_value(dev) returns a negative value, rpm_suspend() should return -EPERM for dev even if its power.no_callbacks flag is set. For this to happen, the device's power.no_callbacks flag has to be checked after the PM QoS check, so move the PM QoS check to rpm_check_suspend_allowed() (this will make it cover idle notifications as well as runtime suspend too).

---
 drivers/base/power/runtime.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/base/power/runtime.c +2 -6
Index: linux/drivers/base/power/runtime.c
===================================================================
@@ -147,6 +147,8 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
+	else if (__dev_pm_qos_read_value(dev) < 0)
+		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
 
@@ -402,12 +404,6 @@ static int rpm_suspend(struct device *de
 		goto out;
 	}
 
-	if (__dev_pm_qos_read_value(dev) < 0) {
-		/* Negative PM QoS constraint means "never suspend". */
-		retval = -EPERM;
-		goto out;
-	}
-
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
 	if (dev->pm_domain)
Acked-by on v1 3/3
#8 lore raw

Re: [Update][PATCH 3/3] PM / Runtime: Check device PM QoS setting before "no callbacks" check

Quoted 31 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>
Subject: PM / Runtime: Check device PM QoS setting before "no callbacks"

If __dev_pm_qos_read_value(dev) returns a negative value, rpm_suspend() should return -EPERM for dev even if its power.no_callbacks flag is set. For this to happen, the device's power.no_callbacks flag has to be checked after the PM QoS check, so move the PM QoS check to rpm_check_suspend_allowed() (this will make it cover idle notifications as well as runtime suspend too).

---
 drivers/base/power/runtime.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

Index: linux/drivers/base/power/runtime.c
===================================================================

drivers/base/power/runtime.c +2 -0
@@ -147,6 +147,8 @@ static int rpm_check_suspend_allowed(str
 	    || (dev->power.request_pending
 			&& dev->power.request == RPM_REQ_RESUME))
 		retval = -EAGAIN;
+	else if (__dev_pm_qos_read_value(dev) < 0)
+		retval = -EPERM;
 	else if (dev->power.runtime_status == RPM_SUSPENDED)
 		retval = 1;
 
@@ -402,12 +404,6 @@ static int rpm_suspend(struct device *de
 		goto out;
 	}

drivers/base/power/runtime.c static int rpm_suspend(struct device *de · line 409

Quoted 10 lines
drivers/base/power/runtime.c +0 -6
 
-	if (__dev_pm_qos_read_value(dev) < 0) {
-		/* Negative PM QoS constraint means "never suspend". */
-		retval = -EPERM;
-		goto out;
-	}
-
 	__update_runtime_status(dev, RPM_SUSPENDING);
 
 	if (dev->pm_domain)