[PATCH v2 4/4] media: wave5: handle runtime resume failure when closing

From: Jiale Yao

Date: Mon Oct 19 2026 - 04:25:29 EST


The decoder and encoder close paths ignore runtime resume failures and
proceed to firmware commands. If enabling the VPU clocks failed, those
commands access unavailable registers, and the paths later drop a
runtime PM reference that was not acquired.

Returning the resume error directly also prevents release_device() from
calling wave5_cleanup_instance(). The instance has already been removed
from the device list and its mem2mem context released, so its host-side
resources leak.

On a resume failure, skip the firmware command and hardware lock, free
the close-path resources, and return -EIO. This lets release_device()
continue with its common instance cleanup without issuing an unmatched
runtime PM put.

Fixes: 2092b3833487 ("media: chips-media: wave5: Support runtime suspend/resume")
Signed-off-by: Jiale Yao <yaojiale02@xxxxxxx>
---
.../platform/chips-media/wave5/wave5-vpuapi.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
index 4c1842f02c..806901e62d 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
@@ -220,7 +220,11 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
if (!inst->codec_info)
return -EINVAL;

- pm_runtime_resume_and_get(inst->dev->dev);
+ ret = pm_runtime_resume_and_get(inst->dev->dev);
+ if (ret < 0) {
+ ret = -EIO;
+ goto free_resources;
+ }

ret_mutex = mutex_lock_interruptible(&vpu_dev->hw_lock);
if (ret_mutex) {
@@ -259,6 +263,7 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)

dev_dbg(inst->dev->dev, "%s: dec_finish_seq complete\n", __func__);

+free_resources:
wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work);

for (i = 0 ; i < MAX_REG_FRAME; i++) {
@@ -272,6 +277,8 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task);

mutex_destroy(&inst->feed_lock);
+ if (ret == -EIO)
+ return ret;

unlock_and_return:
mutex_unlock(&vpu_dev->hw_lock);
@@ -750,7 +757,11 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
if (!inst->codec_info)
return -EINVAL;

- pm_runtime_resume_and_get(inst->dev->dev);
+ ret = pm_runtime_resume_and_get(inst->dev->dev);
+ if (ret < 0) {
+ ret = -EIO;
+ goto free_resources;
+ }

ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
if (ret) {
@@ -774,6 +785,7 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)

dev_dbg(inst->dev->dev, "%s: enc_finish_seq complete\n", __func__);

+free_resources:
wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work);

if (inst->std == W_HEVC_ENC || inst->std == W_AVC_ENC) {
@@ -784,6 +796,8 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
}

wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task);
+ if (ret == -EIO)
+ return ret;

unlock_and_return:
mutex_unlock(&vpu_dev->hw_lock);
--
2.34.1