On 10/23/2024 4:32 PM, Hans Verkuil wrote: > On 14/10/2024 11:07, Dikshita Agarwal wrote: >> Initialize ctrl handler by reading platform specific firmware >> capabilities. Capabilities are features supported by a >> specific platform (SOC). Each capability is defined with >> min, max, range, default value and corresponding HFI. >> Implement s_ctrl and g_volatile_ctrl ctrl ops. >> >> Co-developed-by: Vedang Nagar <quic_vnagar@xxxxxxxxxxx> >> Signed-off-by: Vedang Nagar <quic_vnagar@xxxxxxxxxxx> >> Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx> >> --- >> drivers/media/platform/qcom/iris/Makefile | 1 + >> drivers/media/platform/qcom/iris/iris_core.h | 2 + >> drivers/media/platform/qcom/iris/iris_ctrls.c | 186 +++++++++++++++++++++ >> drivers/media/platform/qcom/iris/iris_ctrls.h | 17 ++ >> .../platform/qcom/iris/iris_hfi_gen2_defines.h | 2 + >> drivers/media/platform/qcom/iris/iris_instance.h | 4 + >> .../platform/qcom/iris/iris_platform_common.h | 29 ++++ >> .../platform/qcom/iris/iris_platform_sm8550.c | 47 ++++++ >> drivers/media/platform/qcom/iris/iris_probe.c | 3 + >> drivers/media/platform/qcom/iris/iris_vdec.c | 9 +- >> drivers/media/platform/qcom/iris/iris_vdec.h | 2 +- >> drivers/media/platform/qcom/iris/iris_vidc.c | 9 +- >> 12 files changed, 308 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile >> index 48ab264b7906..f685d76c2f79 100644 >> --- a/drivers/media/platform/qcom/iris/Makefile >> +++ b/drivers/media/platform/qcom/iris/Makefile >> @@ -1,5 +1,6 @@ >> iris-objs += iris_buffer.o \ >> iris_core.o \ >> + iris_ctrls.o \ >> iris_firmware.o \ >> iris_hfi_common.o \ >> iris_hfi_gen1_command.o \ >> diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h >> index 578166d196f6..70e0dbc7c457 100644 >> --- a/drivers/media/platform/qcom/iris/iris_core.h >> +++ b/drivers/media/platform/qcom/iris/iris_core.h >> @@ -63,6 +63,7 @@ struct icc_info { >> * @intr_status: interrupt status >> * @sys_error_handler: a delayed work for handling system fatal error >> * @instances: a list_head of all instances >> + * @inst_fw_caps: an array of supported instance capabilities >> */ >> >> struct iris_core { >> @@ -101,6 +102,7 @@ struct iris_core { >> u32 intr_status; >> struct delayed_work sys_error_handler; >> struct list_head instances; >> + struct platform_inst_fw_cap inst_fw_caps[INST_FW_CAP_MAX]; >> }; >> >> int iris_core_init(struct iris_core *core); >> diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c >> new file mode 100644 >> index 000000000000..4b991145dbad >> --- /dev/null >> +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c >> @@ -0,0 +1,186 @@ >> +// SPDX-License-Identifier: GPL-2.0-only >> +/* >> + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. >> + */ >> + >> +#include <media/v4l2-mem2mem.h> >> +#include "iris_ctrls.h" >> +#include "iris_instance.h" >> + >> +static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) >> +{ >> + return cap_id >= 1 && cap_id < INST_FW_CAP_MAX; >> +} >> + >> +static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) >> +{ >> + switch (id) { >> + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: >> + return PROFILE; >> + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: >> + return LEVEL; >> + default: >> + return INST_FW_CAP_MAX; >> + } >> +} >> + >> +static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) >> +{ >> + if (!iris_valid_cap_id(cap_id)) >> + return 0; >> + >> + switch (cap_id) { >> + case PROFILE: >> + return V4L2_CID_MPEG_VIDEO_H264_PROFILE; >> + case LEVEL: >> + return V4L2_CID_MPEG_VIDEO_H264_LEVEL; >> + default: >> + return 0; >> + } >> +} >> + >> +static int iris_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) >> +{ >> + struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); >> + enum platform_inst_fw_cap_type cap_id; >> + >> + switch (ctrl->id) { >> + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: >> + ctrl->val = inst->buffers[BUF_OUTPUT].min_count; >> + break; >> + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: >> + ctrl->val = inst->buffers[BUF_INPUT].min_count; >> + break; > > This is NOT volatile. It is just a regular read-only control. If the min_count > changes, then just call v4l2_ctrl_s_ctrl for it in the driver to update the > value of this control. > >> + default: >> + cap_id = iris_get_cap_id(ctrl->id); >> + if (iris_valid_cap_id(cap_id)) >> + ctrl->val = inst->fw_caps[cap_id].value; > > Looking at this code, this is almost certainly not volatile either. > I.e. whenever the driver updates inst->fw_caps[cap_id].value, it can > update this control at the same time. > > A volatile control typically reads from the hardware register that is > automatically modified by the hardware. An example is the gain value if > the hardware is in autogain mode and changes the gain value autonomously. > Sure, will remove iris_vdec_op_g_volatile_ctrl and update the value fro thesse controls as per your suggestions. >> + else >> + return -EINVAL; >> + } >> + >> + return 0; >> +} >> + >> +static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) >> +{ >> + struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); >> + enum platform_inst_fw_cap_type cap_id; >> + struct platform_inst_fw_cap *cap; >> + struct vb2_queue *q; >> + >> + cap = &inst->fw_caps[0]; >> + cap_id = iris_get_cap_id(ctrl->id); >> + if (!iris_valid_cap_id(cap_id)) >> + return -EINVAL; >> + >> + q = v4l2_m2m_get_src_vq(inst->m2m_ctx); >> + if (vb2_is_streaming(q) && >> + (!(inst->fw_caps[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED))) >> + return -EINVAL; >> + >> + cap[cap_id].flags |= CAP_FLAG_CLIENT_SET; >> + >> + inst->fw_caps[cap_id].value = ctrl->val; >> + >> + return 0; >> +} >> + >> +static const struct v4l2_ctrl_ops iris_ctrl_ops = { >> + .s_ctrl = iris_vdec_op_s_ctrl, >> + .g_volatile_ctrl = iris_vdec_op_g_volatile_ctrl, > > So g_volatile_ctrl isn't needed. > Sure. >> +}; >> + >> +int iris_ctrls_init(struct iris_inst *inst) >> +{ >> + struct platform_inst_fw_cap *cap = &inst->fw_caps[0]; >> + u32 num_ctrls = 0, ctrl_idx = 0, idx = 0; >> + u32 v4l2_id; >> + int ret; >> + >> + for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { >> + if (iris_get_v4l2_id(cap[idx].cap_id)) >> + num_ctrls++; >> + } >> + if (!num_ctrls) >> + return -EINVAL; >> + >> + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls); >> + if (ret) >> + return ret; >> + >> + for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { >> + struct v4l2_ctrl *ctrl; >> + >> + v4l2_id = iris_get_v4l2_id(cap[idx].cap_id); >> + if (!v4l2_id) >> + continue; >> + >> + if (ctrl_idx >= num_ctrls) { >> + ret = -EINVAL; >> + goto error; >> + } >> + >> + if (cap[idx].flags & CAP_FLAG_MENU) { >> + ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, >> + &iris_ctrl_ops, >> + v4l2_id, >> + cap[idx].max, >> + ~(cap[idx].step_or_mask), >> + cap[idx].value); >> + } else { >> + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, >> + &iris_ctrl_ops, >> + v4l2_id, >> + cap[idx].min, >> + cap[idx].max, >> + cap[idx].step_or_mask, >> + cap[idx].value); >> + } >> + if (!ctrl) { >> + ret = -EINVAL; >> + goto error; >> + } >> + >> + ret = inst->ctrl_handler.error; >> + if (ret) >> + goto error; > > Move this out of the loop, you can check the result at the end. > Ok. >> + >> + if ((cap[idx].flags & CAP_FLAG_VOLATILE) || >> + (ctrl->id == V4L2_CID_MIN_BUFFERS_FOR_CAPTURE || >> + ctrl->id == V4L2_CID_MIN_BUFFERS_FOR_OUTPUT)) >> + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; >> + >> + ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; > > Do you really need this? It certainly does not make sense for > V4L2_CID_MIN_BUFFERS_FOR_CAPTURE/OUTPUT. > > If a control needs this, then set it in cap[idx].flags and don't add > it for all. It is rarely needed. > Checked it more, and seems it's not needed if above controls shouldn't be treated as volatile contrils, so will remove this. Thanks, Dikshita >> + ctrl_idx++; >> + } >> + >> + return 0; >> +error: >> + v4l2_ctrl_handler_free(&inst->ctrl_handler); >> + >> + return ret; >> +} >> + >> +void iris_session_init_caps(struct iris_core *core) >> +{ >> + struct platform_inst_fw_cap *caps; >> + u32 i, num_cap, cap_id; >> + >> + caps = core->iris_platform_data->inst_fw_caps; >> + num_cap = core->iris_platform_data->inst_fw_caps_size; >> + >> + for (i = 0; i < num_cap; i++) { >> + cap_id = caps[i].cap_id; >> + if (!iris_valid_cap_id(cap_id)) >> + continue; >> + >> + core->inst_fw_caps[cap_id].cap_id = caps[i].cap_id; >> + core->inst_fw_caps[cap_id].min = caps[i].min; >> + core->inst_fw_caps[cap_id].max = caps[i].max; >> + core->inst_fw_caps[cap_id].step_or_mask = caps[i].step_or_mask; >> + core->inst_fw_caps[cap_id].value = caps[i].value; >> + core->inst_fw_caps[cap_id].flags = caps[i].flags; >> + core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; >> + } >> +} >> diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h >> new file mode 100644 >> index 000000000000..3e4dd46e7a26 >> --- /dev/null >> +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h >> @@ -0,0 +1,17 @@ >> +/* SPDX-License-Identifier: GPL-2.0-only */ >> +/* >> + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. >> + */ >> + >> +#ifndef _IRIS_CTRLS_H_ >> +#define _IRIS_CTRLS_H_ >> + >> +#include "iris_platform_common.h" >> + >> +struct iris_core; >> +struct iris_inst; >> + >> +int iris_ctrls_init(struct iris_inst *inst); >> +void iris_session_init_caps(struct iris_core *core); >> + >> +#endif >> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h >> index 18cc9365ab75..457ab1887793 100644 >> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h >> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h >> @@ -28,6 +28,8 @@ >> #define HFI_PROP_UBWC_BANK_SWZL_LEVEL3 0x03000008 >> #define HFI_PROP_UBWC_BANK_SPREADING 0x03000009 >> #define HFI_PROP_CODEC 0x03000100 >> +#define HFI_PROP_PROFILE 0x03000107 >> +#define HFI_PROP_LEVEL 0x03000108 >> #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 >> #define HFI_PROP_END 0x03FFFFFF >> >> diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h >> index d28b8fd7ec2f..43ced6ece289 100644 >> --- a/drivers/media/platform/qcom/iris/iris_instance.h >> +++ b/drivers/media/platform/qcom/iris/iris_instance.h >> @@ -23,8 +23,10 @@ >> * @fh: reference of v4l2 file handler >> * @fmt_src: structure of v4l2_format for source >> * @fmt_dst: structure of v4l2_format for destination >> + * @ctrl_handler: reference of v4l2 ctrl handler >> * @crop: structure of crop info >> * @completions: structure of signal completions >> + * @fw_caps: array of supported instance firmware capabilities >> * @buffers: array of different iris buffers >> * @fw_min_count: minimnum count of buffers needed by fw >> * @once_per_session_set: boolean to set once per session property >> @@ -42,8 +44,10 @@ struct iris_inst { >> struct v4l2_fh fh; >> struct v4l2_format *fmt_src; >> struct v4l2_format *fmt_dst; >> + struct v4l2_ctrl_handler ctrl_handler; >> struct iris_hfi_rect_desc crop; >> struct completion completion; >> + struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; >> struct iris_buffers buffers[BUF_TYPE_MAX]; >> u32 fw_min_count; >> bool once_per_session_set; >> diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h >> index 54a2d723797b..c45928a6c4fe 100644 >> --- a/drivers/media/platform/qcom/iris/iris_platform_common.h >> +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h >> @@ -49,6 +49,33 @@ struct platform_inst_caps { >> u32 max_frame_height; >> u32 max_mbpf; >> }; >> + >> +enum platform_inst_fw_cap_type { >> + PROFILE = 1, >> + LEVEL, >> + INST_FW_CAP_MAX, >> +}; >> + >> +enum platform_inst_fw_cap_flags { >> + CAP_FLAG_DYNAMIC_ALLOWED = BIT(0), >> + CAP_FLAG_MENU = BIT(1), >> + CAP_FLAG_INPUT_PORT = BIT(2), >> + CAP_FLAG_OUTPUT_PORT = BIT(3), >> + CAP_FLAG_CLIENT_SET = BIT(4), >> + CAP_FLAG_BITMASK = BIT(5), >> + CAP_FLAG_VOLATILE = BIT(6), >> +}; >> + >> +struct platform_inst_fw_cap { >> + enum platform_inst_fw_cap_type cap_id; >> + s64 min; >> + s64 max; >> + s64 step_or_mask; >> + s64 value; >> + u32 hfi_id; >> + enum platform_inst_fw_cap_flags flags; >> +}; >> + >> struct iris_core_power { >> u64 clk_freq; >> u64 icc_bw; >> @@ -79,6 +106,8 @@ struct iris_platform_data { >> const char *fwname; >> u32 pas_id; >> struct platform_inst_caps *inst_caps; >> + struct platform_inst_fw_cap *inst_fw_caps; >> + u32 inst_fw_caps_size; >> struct tz_cp_config *tz_cp_config_data; >> u32 core_arch; >> u32 hw_response_timeout; >> diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c >> index 37c0130d7059..7e3703adb5b3 100644 >> --- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c >> +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c >> @@ -5,11 +5,56 @@ >> >> #include "iris_core.h" >> #include "iris_hfi_gen2.h" >> +#include "iris_hfi_gen2_defines.h" >> #include "iris_platform_common.h" >> #include "iris_vpu_common.h" >> >> #define VIDEO_ARCH_LX 1 >> >> +static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { >> + { >> + .cap_id = PROFILE, >> + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, >> + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, >> + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | >> + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | >> + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | >> + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | >> + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), >> + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, >> + .hfi_id = HFI_PROP_PROFILE, >> + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, >> + }, >> + { >> + .cap_id = LEVEL, >> + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, >> + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, >> + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | >> + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), >> + .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, >> + .hfi_id = HFI_PROP_LEVEL, >> + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, >> + }, >> +}; >> + >> static struct platform_inst_caps platform_inst_cap_sm8550 = { >> .min_frame_width = 96, >> .max_frame_width = 8192, >> @@ -77,6 +122,8 @@ struct iris_platform_data sm8550_data = { >> .fwname = "qcom/vpu/vpu30_p4.mbn", >> .pas_id = IRIS_PAS_ID, >> .inst_caps = &platform_inst_cap_sm8550, >> + .inst_fw_caps = inst_fw_cap_sm8550, >> + .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), >> .tz_cp_config_data = &tz_cp_config_sm8550, >> .core_arch = VIDEO_ARCH_LX, >> .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, >> diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c >> index 15463a07ae59..86ef2e5c488e 100644 >> --- a/drivers/media/platform/qcom/iris/iris_probe.c >> +++ b/drivers/media/platform/qcom/iris/iris_probe.c >> @@ -12,6 +12,7 @@ >> #include <linux/reset.h> >> >> #include "iris_core.h" >> +#include "iris_ctrls.h" >> #include "iris_vidc.h" >> >> static int iris_init_icc(struct iris_core *core) >> @@ -237,6 +238,8 @@ static int iris_probe(struct platform_device *pdev) >> if (ret) >> return ret; >> >> + iris_session_init_caps(core); >> + >> ret = v4l2_device_register(dev, &core->v4l2_dev); >> if (ret) >> return ret; >> diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c >> index c4eeba5ed6da..66a54771b9e8 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vdec.c >> +++ b/drivers/media/platform/qcom/iris/iris_vdec.c >> @@ -7,6 +7,7 @@ >> #include <media/v4l2-mem2mem.h> >> >> #include "iris_buffer.h" >> +#include "iris_ctrls.h" >> #include "iris_instance.h" >> #include "iris_vdec.h" >> #include "iris_vpu_buffer.h" >> @@ -16,8 +17,9 @@ >> #define DEFAULT_CODEC_ALIGNMENT 16 >> #define MAX_EVENTS 30 >> >> -void iris_vdec_inst_init(struct iris_inst *inst) >> +int iris_vdec_inst_init(struct iris_inst *inst) >> { >> + struct iris_core *core = inst->core; >> struct v4l2_format *f; >> >> inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); >> @@ -54,6 +56,11 @@ void iris_vdec_inst_init(struct iris_inst *inst) >> inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); >> inst->buffers[BUF_OUTPUT].actual_count = inst->buffers[BUF_OUTPUT].min_count; >> inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; >> + >> + memcpy(&inst->fw_caps[0], &core->inst_fw_caps[0], >> + INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); >> + >> + return iris_ctrls_init(inst); >> } >> >> void iris_vdec_inst_deinit(struct iris_inst *inst) >> diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h >> index 707fff34bf4d..d7b8a0ad6fa8 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vdec.h >> +++ b/drivers/media/platform/qcom/iris/iris_vdec.h >> @@ -8,7 +8,7 @@ >> >> struct iris_inst; >> >> -void iris_vdec_inst_init(struct iris_inst *inst); >> +int iris_vdec_inst_init(struct iris_inst *inst); >> void iris_vdec_inst_deinit(struct iris_inst *inst); >> int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); >> int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); >> diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c >> index 8068c06c1f11..93d2be118a81 100644 >> --- a/drivers/media/platform/qcom/iris/iris_vidc.c >> +++ b/drivers/media/platform/qcom/iris/iris_vidc.c >> @@ -22,12 +22,14 @@ >> static void iris_v4l2_fh_init(struct iris_inst *inst) >> { >> v4l2_fh_init(&inst->fh, inst->core->vdev_dec); >> + inst->fh.ctrl_handler = &inst->ctrl_handler; >> v4l2_fh_add(&inst->fh); >> } >> >> static void iris_v4l2_fh_deinit(struct iris_inst *inst) >> { >> v4l2_fh_del(&inst->fh); >> + inst->fh.ctrl_handler = NULL; >> v4l2_fh_exit(&inst->fh); >> } >> >> @@ -159,7 +161,9 @@ int iris_open(struct file *filp) >> goto fail_m2m_release; >> } >> >> - iris_vdec_inst_init(inst); >> + ret = iris_vdec_inst_init(inst); >> + if (ret) >> + goto fail_m2m_ctx_release; >> >> iris_add_session(inst); >> >> @@ -168,6 +172,8 @@ int iris_open(struct file *filp) >> >> return 0; >> >> +fail_m2m_ctx_release: >> + v4l2_m2m_ctx_release(inst->m2m_ctx); >> fail_m2m_release: >> v4l2_m2m_release(inst->m2m_dev); >> fail_v4l2_fh_deinit: >> @@ -199,6 +205,7 @@ int iris_close(struct file *filp) >> { >> struct iris_inst *inst = iris_get_inst(filp, NULL); >> >> + v4l2_ctrl_handler_free(&inst->ctrl_handler); >> v4l2_m2m_ctx_release(inst->m2m_ctx); >> v4l2_m2m_release(inst->m2m_dev); >> mutex_lock(&inst->lock); >> >