On 14/10/2024 11:07, Dikshita Agarwal wrote: > In stream on, send HFI_CMD_START on capture and > output planes to start the processing on respective planes. > > During stream off, send HFI_CMD_STOP to firmware which is > a synchronous command. After the response is received from > firmware, the session is closed on firmware. > > Introduce different states for instance and state transitions. > > IRIS_INST_INIT - video instance is opened. > IRIS_INST_INPUT_STREAMING - stream on is completed on output plane. > IRIS_INST_OUTPUT_STREAMING - stream on is completed on capture > plane. > IRIS_INST_STREAMING - stream on is completed on both output and > capture planes. > IRIS_INST_DEINIT - video instance is closed. > IRIS_INST_ERROR - error state. > > | > v > ------------- > +---------| INIT |--------- + > | ------------- | > | ^ ^ | > | / \ | > | / \ | > | v v | > | ----------- ----------- | > | | INPUT OUTPUT | | > |---| STREAMING STREAMING |---| > | ----------- ----------- | > | ^ ^ | > | \ / | > | \ / | > | v v | > | ------------- | > |--------| STREAMING |-----------| > | ------------- | > | | | > | | | > | v | > | ----------- | > +-------->| DEINIT |<----------+ > | ----------- | > | | | > | | | > | v | > | ---------- | > +-------->| ERROR |<-----------+ > ----------. > > Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx> > --- > drivers/media/platform/qcom/iris/Makefile | 1 + > drivers/media/platform/qcom/iris/iris_hfi_common.h | 2 + > .../platform/qcom/iris/iris_hfi_gen1_command.c | 82 +++++++++++++++- > .../platform/qcom/iris/iris_hfi_gen1_defines.h | 24 +++++ > .../platform/qcom/iris/iris_hfi_gen1_response.c | 39 +++++++- > .../platform/qcom/iris/iris_hfi_gen2_command.c | 61 ++++++++++++ > .../platform/qcom/iris/iris_hfi_gen2_defines.h | 2 + > .../platform/qcom/iris/iris_hfi_gen2_response.c | 32 ++++++- > drivers/media/platform/qcom/iris/iris_instance.h | 4 + > drivers/media/platform/qcom/iris/iris_state.c | 104 +++++++++++++++++++++ > drivers/media/platform/qcom/iris/iris_state.h | 58 ++++++++++++ > drivers/media/platform/qcom/iris/iris_utils.c | 11 ++- > drivers/media/platform/qcom/iris/iris_utils.h | 2 +- > drivers/media/platform/qcom/iris/iris_vb2.c | 70 ++++++++++++++ > drivers/media/platform/qcom/iris/iris_vb2.h | 3 + > drivers/media/platform/qcom/iris/iris_vdec.c | 75 +++++++++++++++ > drivers/media/platform/qcom/iris/iris_vdec.h | 3 + > drivers/media/platform/qcom/iris/iris_vidc.c | 32 ++++++- > 18 files changed, 593 insertions(+), 12 deletions(-) > <snip> > diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c > index f89891e52fde..75c1364709d1 100644 > --- a/drivers/media/platform/qcom/iris/iris_vb2.c > +++ b/drivers/media/platform/qcom/iris/iris_vb2.c > @@ -6,6 +6,7 @@ > #include "iris_buffer.h" > #include "iris_instance.h" > #include "iris_vb2.h" > +#include "iris_vdec.h" > #include "iris_vpu_buffer.h" > > int iris_vb2_queue_setup(struct vb2_queue *q, > @@ -22,6 +23,10 @@ int iris_vb2_queue_setup(struct vb2_queue *q, > inst = vb2_get_drv_priv(q); > > mutex_lock(&inst->lock); > + if (inst->state == IRIS_INST_ERROR) { > + ret = -EBUSY; > + goto unlock; > + } > > core = inst->core; > f = V4L2_TYPE_IS_OUTPUT(q->type) ? inst->fmt_src : inst->fmt_dst; > @@ -49,6 +54,10 @@ int iris_vb2_queue_setup(struct vb2_queue *q, > dev_err(core->dev, "session open failed\n"); > goto unlock; > } > + > + ret = iris_inst_change_state(inst, IRIS_INST_INIT); > + if (ret) > + goto unlock; > } > > buffers = &inst->buffers[buffer_type]; > @@ -75,3 +84,64 @@ int iris_vb2_queue_setup(struct vb2_queue *q, > > return ret; > } > + > +int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) > +{ > + struct iris_inst *inst; > + int ret = 0; > + > + inst = vb2_get_drv_priv(q); > + > + if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT) > + return 0; > + > + mutex_lock(&inst->lock); > + if (inst->state == IRIS_INST_ERROR) { > + ret = -EBUSY; If an error occurs during start_streaming, then all queued buffers must be returned to vb2 in state VB2_BUF_STATE_QUEUED. > + goto error; > + } > + > + if (!V4L2_TYPE_IS_OUTPUT(q->type) && > + !V4L2_TYPE_IS_CAPTURE(q->type)) { > + ret = -EINVAL; > + goto error; > + } > + > + if (V4L2_TYPE_IS_OUTPUT(q->type)) > + ret = iris_vdec_streamon_input(inst); > + else if (V4L2_TYPE_IS_CAPTURE(q->type)) > + ret = iris_vdec_streamon_output(inst); > + if (ret) > + goto error; > + > + mutex_unlock(&inst->lock); > + > + return ret; > + > +error: > + iris_inst_change_state(inst, IRIS_INST_ERROR); > + mutex_unlock(&inst->lock); > + > + return ret; > +} > + > +void iris_vb2_stop_streaming(struct vb2_queue *q) > +{ > + struct iris_inst *inst; > + > + inst = vb2_get_drv_priv(q); > + > + if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT) > + return; > + > + mutex_lock(&inst->lock); > + > + if (!V4L2_TYPE_IS_OUTPUT(q->type) && > + !V4L2_TYPE_IS_CAPTURE(q->type)) > + goto exit; > + > + iris_vdec_session_streamoff(inst, q->type); > + > +exit: stop_streaming must return all queued buffers to vb2 in state VB2_BUF_STATE_ERROR. > + mutex_unlock(&inst->lock); > +} > diff --git a/drivers/media/platform/qcom/iris/iris_vb2.h b/drivers/media/platform/qcom/iris/iris_vb2.h > index 78157a97b86e..bc3bb830c2ba 100644 > --- a/drivers/media/platform/qcom/iris/iris_vb2.h > +++ b/drivers/media/platform/qcom/iris/iris_vb2.h > @@ -9,4 +9,7 @@ > int iris_vb2_queue_setup(struct vb2_queue *q, > unsigned int *num_buffers, unsigned int *num_planes, > unsigned int sizes[], struct device *alloc_devs[]); > +int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count); > +void iris_vb2_stop_streaming(struct vb2_queue *q); > + > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c > index 66a54771b9e8..44372e2811c3 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.c > +++ b/drivers/media/platform/qcom/iris/iris_vdec.c > @@ -241,3 +241,78 @@ int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_su > > return ret; > } > + > +static void iris_vdec_kill_session(struct iris_inst *inst) > +{ > + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; > + > + if (!inst->session_id) > + return; > + > + hfi_ops->session_close(inst); > + iris_inst_change_state(inst, IRIS_INST_ERROR); > +} > + > +void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) > +{ > + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; > + int ret; > + > + ret = hfi_ops->session_stop(inst, plane); > + if (ret) > + goto error; > + > + ret = iris_inst_state_change_streamoff(inst, plane); > + if (ret) > + goto error; > + > + return; > + > +error: > + iris_vdec_kill_session(inst); > +} > + > +static int iris_vdec_process_streamon_input(struct iris_inst *inst) > +{ > + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; > + int ret; > + > + ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); > + if (ret) > + return ret; > + > + return iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); > +} > + > +int iris_vdec_streamon_input(struct iris_inst *inst) > +{ > + return iris_vdec_process_streamon_input(inst); > +} > + > +static int iris_vdec_process_streamon_output(struct iris_inst *inst) > +{ > + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; > + int ret; > + > + ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); > + if (ret) > + return ret; > + > + return iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); > +} > + > +int iris_vdec_streamon_output(struct iris_inst *inst) > +{ > + int ret; > + > + ret = iris_vdec_process_streamon_output(inst); > + if (ret) > + goto error; > + > + return ret; > + > +error: > + iris_vdec_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); > + > + return ret; > +} > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h > index d7b8a0ad6fa8..b3299164f823 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.h > +++ b/drivers/media/platform/qcom/iris/iris_vdec.h > @@ -14,5 +14,8 @@ 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); > int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); > int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); > +int iris_vdec_streamon_input(struct iris_inst *inst); > +int iris_vdec_streamon_output(struct iris_inst *inst); > +void iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); > > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c > index 60ee05b67f86..615f57bfaddc 100644 > --- a/drivers/media/platform/qcom/iris/iris_vidc.c > +++ b/drivers/media/platform/qcom/iris/iris_vidc.c > @@ -142,10 +142,12 @@ int iris_open(struct file *filp) > > inst->core = core; > inst->session_id = hash32_ptr(inst); > + inst->state = IRIS_INST_DEINIT; > > mutex_init(&inst->lock); > mutex_init(&inst->ctx_q_lock); > init_completion(&inst->completion); > + init_completion(&inst->flush_completion); > > iris_v4l2_fh_init(inst); > > @@ -191,6 +193,9 @@ static void iris_session_close(struct iris_inst *inst) > bool wait_for_response = true; > int ret; > > + if (inst->state == IRIS_INST_DEINIT) > + return; > + > reinit_completion(&inst->completion); > > ret = hfi_ops->session_close(inst); > @@ -198,7 +203,7 @@ static void iris_session_close(struct iris_inst *inst) > wait_for_response = false; > > if (wait_for_response) > - iris_wait_for_session_response(inst); > + iris_wait_for_session_response(inst, false); > } > > int iris_close(struct file *filp) > @@ -211,6 +216,7 @@ int iris_close(struct file *filp) > mutex_lock(&inst->lock); > iris_vdec_inst_deinit(inst); > iris_session_close(inst); > + iris_inst_change_state(inst, IRIS_INST_DEINIT); > iris_v4l2_fh_deinit(inst); > iris_remove_session(inst); > mutex_unlock(&inst->lock); > @@ -238,7 +244,14 @@ static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_form > int ret; > > mutex_lock(&inst->lock); > + if (inst->state == IRIS_INST_ERROR) { > + ret = -EBUSY; > + goto unlock; > + } Why this check? You should be able to try a format at any time. > + > ret = iris_vdec_try_fmt(inst, f); > + > +unlock: > mutex_unlock(&inst->lock); > > return ret; > @@ -250,7 +263,14 @@ static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format > int ret; > > mutex_lock(&inst->lock); > + if (inst->state == IRIS_INST_ERROR) { > + ret = -EBUSY; > + goto unlock; > + } > + > ret = iris_vdec_s_fmt(inst, f); > + > +unlock: > mutex_unlock(&inst->lock); > > return ret; > @@ -262,6 +282,11 @@ static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format > int ret = 0; > > mutex_lock(&inst->lock); > + if (inst->state == IRIS_INST_ERROR) { > + ret = -EBUSY; > + goto unlock; > + } Same question, this should be fine at any time. > + > if (V4L2_TYPE_IS_OUTPUT(f->type)) > memcpy(f, inst->fmt_src, sizeof(*f)); > else if (V4L2_TYPE_IS_CAPTURE(f->type)) > @@ -269,6 +294,7 @@ static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format > else > ret = -EINVAL; > > +unlock: > mutex_unlock(&inst->lock); > > return ret; > @@ -402,6 +428,8 @@ static struct v4l2_file_operations iris_v4l2_file_ops = { > > static const struct vb2_ops iris_vb2_ops = { > .queue_setup = iris_vb2_queue_setup, > + .start_streaming = iris_vb2_start_streaming, > + .stop_streaming = iris_vb2_stop_streaming, > }; > > static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { > @@ -421,6 +449,8 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { > .vidioc_g_selection = iris_g_selection, > .vidioc_subscribe_event = iris_subscribe_event, > .vidioc_unsubscribe_event = iris_unsubscribe_event, > + .vidioc_streamon = v4l2_m2m_ioctl_streamon, > + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, > }; > > void iris_init_ops(struct iris_core *core) >