]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PM: runtime: Unify error handling during suspend and resume
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 25 Feb 2025 17:06:18 +0000 (18:06 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 3 Mar 2025 13:46:19 +0000 (14:46 +0100)
There is a confusing difference in error handling between rpm_suspend()
and rpm_resume() related to the special way in which -EAGAIN and -EBUSY
error values are treated by the former.  Also, converting -EACCES coming
from the callback to I/O error, which it quite likely is not, may
confuse runtime PM users.

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.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/12620037.O9o76ZdvQC@rjwysocki.net
drivers/base/power/runtime.c

index 1714358b541e8a96a815aad27b67b367e0a0ecea..da74e1c69f7a1f6d52539f07f6c6b34b00e0c9d4 100644 (file)
@@ -448,8 +448,19 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
                retval = __rpm_callback(cb, dev);
        }
 
-       dev->power.runtime_error = retval;
-       return retval != -EACCES ? retval : -EIO;
+       /*
+        * Since -EACCES means that runtime PM is disabled for the given device,
+        * it should not be returned by runtime PM callbacks.  If it is returned
+        * nevertheless, assume it to be a transient error and convert it to
+        * -EAGAIN.
+        */
+       if (retval == -EACCES)
+               retval = -EAGAIN;
+
+       if (retval != -EAGAIN && retval != -EBUSY)
+               dev->power.runtime_error = retval;
+
+       return retval;
 }
 
 /**
@@ -725,21 +736,18 @@ static int rpm_suspend(struct device *dev, int rpmflags)
        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;
 }