accel/ivpu: Fix error handling in recovery/reset
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: 27d19268cf
("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
This commit is contained in:
parent
f2bc2afe34
commit
41a2d8286c
1 changed files with 43 additions and 36 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue