On Thu Jul 30 14:14:04 2026 +0000, Yifei Gao wrote:
> isp4sd_pwron_and_init() holds ops_mutex via guard(mutex) and, on any
> init failure, jumps to err_deinit and calls isp4sd_pwroff_and_deinit().
> That helper takes the same ops_mutex, re-acquiring a non-recursive mutex
> already held by the current thread, so any init failure deadlocks.
> 
> Unwind the error path in stages instead, releasing only what each
> failure point acquired. This also avoids the issues that an
> unconditional teardown would hit at the earlier failures, such as a
> runtime-PM underflow from pm_runtime_resume_and_get() and MMIO access
> while the device is unpowered.
> 
> Fixes: 4e5e7a7ddb4a ("media: platform: amd: isp4 subdev and firmware loading 
> handling added")
> Assisted-by: Claude:claude-opus-4-8 smatch
> Signed-off-by: Yifei Gao <[email protected]>
> Reviewed-by: Bin Du <[email protected]>
> Signed-off-by: Sakari Ailus <[email protected]>

Patch committed.

Thanks,
Sakari Ailus

 drivers/media/platform/amd/isp4/isp4_subdev.c | 28 +++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

---

diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.c 
b/drivers/media/platform/amd/isp4/isp4_subdev.c
index 2a8bc1207843..6716ab9c128a 100644
--- a/drivers/media/platform/amd/isp4/isp4_subdev.c
+++ b/drivers/media/platform/amd/isp4/isp4_subdev.c
@@ -687,7 +687,7 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd)
                if (ret) {
                        dev_err(dev, "fail to power on isp_subdev ret %d\n",
                                ret);
-                       goto err_deinit;
+                       goto err_module_disable;
                }
 
                /* ISPPG ISP Power Status */
@@ -697,7 +697,7 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd)
                        dev_err(dev,
                                "fail to set performance state %u, ret %d\n",
                                perf_state, ret);
-                       goto err_deinit;
+                       goto err_power_off;
                }
 
                ispif->status = ISP4IF_STATUS_PWR_ON;
@@ -709,12 +709,12 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd)
        ret = isp4if_start(ispif);
        if (ret) {
                dev_err(dev, "fail to start isp_subdev interface\n");
-               goto err_deinit;
+               goto err_perf_restore;
        }
 
        if (isp4sd_start_resp_proc_threads(isp_subdev)) {
                dev_err(dev, "isp_start_resp_proc_threads fail\n");
-               goto err_deinit;
+               goto err_stop_interface;
        }
 
        dev_dbg(dev, "create resp threads ok\n");
@@ -724,8 +724,24 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd)
        isp_subdev->irq_enabled = true;
 
        return 0;
-err_deinit:
-       isp4sd_pwroff_and_deinit(sd);
+
+err_stop_interface:
+       isp4if_stop(ispif);
+err_perf_restore:
+       ret = dev_pm_genpd_set_performance_state(dev, 
ISP4SD_PERFORMANCE_STATE_LOW);
+       if (ret)
+               dev_err(dev, "fail to set performance state %u, ret %d\n",
+                       ISP4SD_PERFORMANCE_STATE_LOW, ret);
+err_power_off:
+       isp4hw_wreg(isp_subdev->mmio, ISP_SOFT_RESET, 0);
+       isp4hw_wreg(isp_subdev->mmio, ISP_POWER_STATUS, 0);
+       ret = pm_runtime_put_sync(dev);
+       if (ret)
+               dev_err(dev, "power off isp_subdev fail %d\n", ret);
+       ispif->status = ISP4IF_STATUS_PWR_OFF;
+err_module_disable:
+       isp4sd_module_enable(isp_subdev, false);
+       msleep(20);
        return -EINVAL;
 }
 
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to