[PATCH v1] PM: runtime: Unify error handling during suspend and resume

From: Rafael J. Wysocki
Date: Thu Feb 20 2025 - 15:19:37 EST


From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>

There is a confusing difference in error handling between rpm_suspend()
and rpm_resume() related to the special way in which the -EAGAIN and
-EBUSY error values are treated by the former. Also, converting
-EACCES coming from the callback to an I/O error, which it quite likely
is not, may confuse runtime PM users a bit.

To address the above, modify rpm_callback() to convert -EACCES coming
from the driver to -EAGAIN and to set power.runtime_error only if the
return value is not -EAGAIN or -EBUSY.

This will cause the error handling in rpm_resume() and rpm_suspend() to
work consistently, so drop the no longer needed -EAGAIN or -EBUSY
special case from the latter and make it retry autosuspend if
power.runtime_error is unset.

Link: https://lore.kernel.org/linux-pm/20220620144231.GA23345@xxxxxxxx/
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
---
drivers/base/power/runtime.c | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)

--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -448,8 +448,13 @@
retval = __rpm_callback(cb, dev);
}

- dev->power.runtime_error = retval;
- return retval != -EACCES ? retval : -EIO;
+ if (retval == -EACCES)
+ retval = -EAGAIN;
+
+ if (retval != -EAGAIN && retval != -EBUSY)
+ dev->power.runtime_error = retval;
+
+ return retval;
}

/**
@@ -725,21 +730,18 @@
dev->power.deferred_resume = false;
wake_up_all(&dev->power.wait_queue);

- if (retval == -EAGAIN || retval == -EBUSY) {
- dev->power.runtime_error = 0;
+ /*
+ * On transient errors, if the callback routine failed an autosuspend,
+ * and if the last_busy time has been updated so that there is a new
+ * autosuspend expiration time, automatically reschedule another
+ * autosuspend.
+ */
+ if (!dev->power.runtime_error && (rpmflags & RPM_AUTO) &&
+ pm_runtime_autosuspend_expiration(dev) != 0)
+ goto repeat;
+
+ pm_runtime_cancel_pending(dev);

- /*
- * If the callback routine failed an autosuspend, and
- * if the last_busy time has been updated so that there
- * is a new autosuspend expiration time, automatically
- * reschedule another autosuspend.
- */
- if ((rpmflags & RPM_AUTO) &&
- pm_runtime_autosuspend_expiration(dev) != 0)
- goto repeat;
- } else {
- pm_runtime_cancel_pending(dev);
- }
goto out;
}