]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
accel/ivpu: Fix error handling in recovery/reset
authorJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Wed, 29 Jan 2025 12:40:09 +0000 (13:40 +0100)
committerJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Mon, 3 Feb 2025 08:59:18 +0000 (09:59 +0100)
Disable runtime PM for the duration of reset/recovery so it is possible
to set the correct runtime PM state depending on the outcome of the
`ivpu_resume()`. Don’t suspend or reset the HW if the NPU is suspended
when the reset/recovery is requested. Also, move common reset/recovery
code to separate functions for better code readability.

Fixes: 27d19268cf39 ("accel/ivpu: Improve recovery and reset support")
Cc: stable@vger.kernel.org # v6.8+
Reviewed-by: Maciej Falkowski <maciej.falkowski@linux.intel.com>
Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250129124009.1039982-4-jacek.lawrynowicz@linux.intel.com
drivers/accel/ivpu/ivpu_pm.c

index c3774d2221326137329542eede6250c34ef51875..8b2b050cc41a98b4ba090bc10ba0b176e5961f69 100644 (file)
@@ -115,41 +115,57 @@ err_power_down:
        return ret;
 }
 
-static void ivpu_pm_recovery_work(struct work_struct *work)
+static void ivpu_pm_reset_begin(struct ivpu_device *vdev)
 {
-       struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, recovery_work);
-       struct ivpu_device *vdev = pm->vdev;
-       char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL};
-       int ret;
-
-       ivpu_err(vdev, "Recovering the NPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter));
-
-       ret = pm_runtime_resume_and_get(vdev->drm.dev);
-       if (ret)
-               ivpu_err(vdev, "Failed to resume NPU: %d\n", ret);
-
-       ivpu_jsm_state_dump(vdev);
-       ivpu_dev_coredump(vdev);
+       pm_runtime_disable(vdev->drm.dev);
 
        atomic_inc(&vdev->pm->reset_counter);
        atomic_set(&vdev->pm->reset_pending, 1);
        down_write(&vdev->pm->reset_lock);
+}
+
+static void ivpu_pm_reset_complete(struct ivpu_device *vdev)
+{
+       int ret;
 
-       ivpu_suspend(vdev);
        ivpu_pm_prepare_cold_boot(vdev);
        ivpu_jobs_abort_all(vdev);
        ivpu_ms_cleanup_all(vdev);
 
        ret = ivpu_resume(vdev);
-       if (ret)
+       if (ret) {
                ivpu_err(vdev, "Failed to resume NPU: %d\n", ret);
+               pm_runtime_set_suspended(vdev->drm.dev);
+       } else {
+               pm_runtime_set_active(vdev->drm.dev);
+       }
 
        up_write(&vdev->pm->reset_lock);
        atomic_set(&vdev->pm->reset_pending, 0);
 
-       kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
        pm_runtime_mark_last_busy(vdev->drm.dev);
-       pm_runtime_put_autosuspend(vdev->drm.dev);
+       pm_runtime_enable(vdev->drm.dev);
+}
+
+static void ivpu_pm_recovery_work(struct work_struct *work)
+{
+       struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, recovery_work);
+       struct ivpu_device *vdev = pm->vdev;
+       char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL};
+
+       ivpu_err(vdev, "Recovering the NPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter));
+
+       ivpu_pm_reset_begin(vdev);
+
+       if (!pm_runtime_status_suspended(vdev->drm.dev)) {
+               ivpu_jsm_state_dump(vdev);
+               ivpu_dev_coredump(vdev);
+               ivpu_suspend(vdev);
+       }
+
+       ivpu_pm_reset_complete(vdev);
+
+       kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
 }
 
 void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason)
@@ -328,16 +344,13 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev)
        struct ivpu_device *vdev = pci_get_drvdata(pdev);
 
        ivpu_dbg(vdev, PM, "Pre-reset..\n");
-       atomic_inc(&vdev->pm->reset_counter);
-       atomic_set(&vdev->pm->reset_pending, 1);
 
-       pm_runtime_get_sync(vdev->drm.dev);
-       down_write(&vdev->pm->reset_lock);
-       ivpu_prepare_for_reset(vdev);
-       ivpu_hw_reset(vdev);
-       ivpu_pm_prepare_cold_boot(vdev);
-       ivpu_jobs_abort_all(vdev);
-       ivpu_ms_cleanup_all(vdev);
+       ivpu_pm_reset_begin(vdev);
+
+       if (!pm_runtime_status_suspended(vdev->drm.dev)) {
+               ivpu_prepare_for_reset(vdev);
+               ivpu_hw_reset(vdev);
+       }
 
        ivpu_dbg(vdev, PM, "Pre-reset done.\n");
 }
@@ -345,18 +358,12 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev)
 void ivpu_pm_reset_done_cb(struct pci_dev *pdev)
 {
        struct ivpu_device *vdev = pci_get_drvdata(pdev);
-       int ret;
 
        ivpu_dbg(vdev, PM, "Post-reset..\n");
-       ret = ivpu_resume(vdev);
-       if (ret)
-               ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret);
-       up_write(&vdev->pm->reset_lock);
-       atomic_set(&vdev->pm->reset_pending, 0);
-       ivpu_dbg(vdev, PM, "Post-reset done.\n");
 
-       pm_runtime_mark_last_busy(vdev->drm.dev);
-       pm_runtime_put_autosuspend(vdev->drm.dev);
+       ivpu_pm_reset_complete(vdev);
+
+       ivpu_dbg(vdev, PM, "Post-reset done.\n");
 }
 
 void ivpu_pm_init(struct ivpu_device *vdev)