diff mbox series

[v2,22/34] media: iris: introduce instance states

Message ID 1702899149-21321-23-git-send-email-quic_dikshita@quicinc.com
State New
Headers show
Series Qualcomm video encoder and decoder driver | expand

Commit Message

Dikshita Agarwal Dec. 18, 2023, 11:32 a.m. UTC
Introduce different states for instances. State transitions
are defined, based on which they would be allowed/rejected/ignored.

IRIS_INST_OPEN - 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_CLOSE - video instance is closed.
IRIS_INST_ERROR - error state.

                   |
                   v
            -------------
  +---------|    OPEN   |---------  +
  |         -------------           |
  |            ^    ^               |
  |           /      \              |
  |          /        \             |
  |         v          v            |
  |    -----------    -----------   |
  |   |   INPUT         OUTPUT  |   |
  |---| STREAMING     STREAMING |---|
  |    -----------    -----------   |
  |        ^            ^           |
  |         \          /            |
  |          \        /             |
  |           v      v              |
  |         -------------           |
  |--------|  STREAMING |-----------|
  |         -------------           |
  |               |                 |
  |               |                 |
  |               v                 |
  |          -----------            |
  +-------->|   CLOSE   |<----------+
  |          -----------            |
  |               |                 |
  |               |                 |
  |               v                 |
  |          ----------             |
  +-------->|   ERROR  |<-----------+
             ----------

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
---
 .../platform/qcom/vcodec/iris/iris_instance.h      |  2 +
 .../media/platform/qcom/vcodec/iris/iris_state.c   | 86 ++++++++++++++++++++++
 .../media/platform/qcom/vcodec/iris/iris_state.h   | 22 ++++++
 drivers/media/platform/qcom/vcodec/iris/iris_vb2.c |  3 +
 .../media/platform/qcom/vcodec/iris/iris_vidc.c    |  5 ++
 5 files changed, 118 insertions(+)
diff mbox series

Patch

diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
index 5d4c856..275efa8 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h
@@ -37,6 +37,7 @@ 
  * @codec: codec type
  * @buffers: structure of buffer info
  * @fw_min_count: minimnum count of buffers needed by fw
+ * @state: instance state
  */
 
 struct iris_inst {
@@ -60,6 +61,7 @@  struct iris_inst {
 	enum codec_type			codec;
 	struct iris_buffers_info	buffers;
 	u32				fw_min_count;
+	enum iris_inst_state		state;
 };
 
 #endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_state.c b/drivers/media/platform/qcom/vcodec/iris/iris_state.c
index 83bbc6b..9bf79a0 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_state.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_state.c
@@ -69,3 +69,89 @@  int iris_change_core_state(struct iris_core *core,
 
 	return ret;
 }
+
+struct iris_inst_state_change_allow {
+	enum iris_inst_state        from;
+	enum iris_inst_state        to;
+	enum state_change           allow;
+};
+
+static enum state_change iris_allow_inst_state_change(struct iris_inst *inst,
+						      enum iris_inst_state req_state)
+{
+	enum state_change allow = STATE_CHANGE_ALLOW;
+	int cnt;
+	static struct iris_inst_state_change_allow state[] = {
+		/* from, to, allow */
+		{IRIS_INST_OPEN,             IRIS_INST_OPEN,               STATE_CHANGE_IGNORE    },
+		{IRIS_INST_OPEN,             IRIS_INST_INPUT_STREAMING,    STATE_CHANGE_ALLOW     },
+		{IRIS_INST_OPEN,             IRIS_INST_OUTPUT_STREAMING,   STATE_CHANGE_ALLOW     },
+		{IRIS_INST_OPEN,             IRIS_INST_STREAMING,          STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_OPEN,             IRIS_INST_CLOSE,              STATE_CHANGE_ALLOW     },
+		{IRIS_INST_OPEN,             IRIS_INST_ERROR,              STATE_CHANGE_ALLOW     },
+
+		{IRIS_INST_INPUT_STREAMING,  IRIS_INST_OPEN,               STATE_CHANGE_ALLOW     },
+		{IRIS_INST_INPUT_STREAMING,  IRIS_INST_INPUT_STREAMING,    STATE_CHANGE_IGNORE    },
+		{IRIS_INST_INPUT_STREAMING,  IRIS_INST_OUTPUT_STREAMING,   STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_INPUT_STREAMING,  IRIS_INST_STREAMING,          STATE_CHANGE_ALLOW     },
+		{IRIS_INST_INPUT_STREAMING,  IRIS_INST_CLOSE,              STATE_CHANGE_ALLOW     },
+		{IRIS_INST_INPUT_STREAMING,  IRIS_INST_ERROR,              STATE_CHANGE_ALLOW     },
+
+		{IRIS_INST_OUTPUT_STREAMING, IRIS_INST_OPEN,               STATE_CHANGE_ALLOW     },
+		{IRIS_INST_OUTPUT_STREAMING, IRIS_INST_INPUT_STREAMING,    STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_OUTPUT_STREAMING, IRIS_INST_OUTPUT_STREAMING,   STATE_CHANGE_IGNORE    },
+		{IRIS_INST_OUTPUT_STREAMING, IRIS_INST_STREAMING,          STATE_CHANGE_ALLOW     },
+		{IRIS_INST_OUTPUT_STREAMING, IRIS_INST_CLOSE,              STATE_CHANGE_ALLOW     },
+		{IRIS_INST_OUTPUT_STREAMING, IRIS_INST_ERROR,              STATE_CHANGE_ALLOW     },
+
+		{IRIS_INST_STREAMING,        IRIS_INST_OPEN,               STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_STREAMING,        IRIS_INST_INPUT_STREAMING,    STATE_CHANGE_ALLOW     },
+		{IRIS_INST_STREAMING,        IRIS_INST_OUTPUT_STREAMING,   STATE_CHANGE_ALLOW     },
+		{IRIS_INST_STREAMING,        IRIS_INST_STREAMING,          STATE_CHANGE_IGNORE    },
+		{IRIS_INST_STREAMING,        IRIS_INST_CLOSE,              STATE_CHANGE_ALLOW     },
+		{IRIS_INST_STREAMING,        IRIS_INST_ERROR,              STATE_CHANGE_ALLOW     },
+
+		{IRIS_INST_CLOSE,            IRIS_INST_OPEN,               STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_CLOSE,            IRIS_INST_INPUT_STREAMING,    STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_CLOSE,            IRIS_INST_OUTPUT_STREAMING,   STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_CLOSE,            IRIS_INST_STREAMING,          STATE_CHANGE_DISALLOW  },
+		{IRIS_INST_CLOSE,            IRIS_INST_CLOSE,              STATE_CHANGE_IGNORE    },
+		{IRIS_INST_CLOSE,            IRIS_INST_ERROR,              STATE_CHANGE_IGNORE    },
+
+		{IRIS_INST_ERROR,            IRIS_INST_OPEN,               STATE_CHANGE_IGNORE    },
+		{IRIS_INST_ERROR,            IRIS_INST_INPUT_STREAMING,    STATE_CHANGE_IGNORE    },
+		{IRIS_INST_ERROR,            IRIS_INST_OUTPUT_STREAMING,   STATE_CHANGE_IGNORE    },
+		{IRIS_INST_ERROR,            IRIS_INST_STREAMING,          STATE_CHANGE_IGNORE    },
+		{IRIS_INST_ERROR,            IRIS_INST_CLOSE,              STATE_CHANGE_IGNORE    },
+		{IRIS_INST_ERROR,            IRIS_INST_ERROR,              STATE_CHANGE_IGNORE    },
+	};
+
+	for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) {
+		if (state[cnt].from == inst->state && state[cnt].to == req_state) {
+			allow = state[cnt].allow;
+			break;
+		}
+	}
+
+	return allow;
+}
+
+int iris_inst_change_state(struct iris_inst *inst,
+			   enum iris_inst_state request_state)
+{
+	enum state_change allow;
+
+	if (IS_SESSION_ERROR(inst))
+		return 0;
+
+	if (inst->state == request_state)
+		return 0;
+
+	allow = iris_allow_inst_state_change(inst, request_state);
+	if (allow != STATE_CHANGE_ALLOW)
+		return (allow == STATE_CHANGE_DISALLOW ? -EINVAL : 0);
+
+	inst->state = request_state;
+
+	return 0;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_state.h b/drivers/media/platform/qcom/vcodec/iris/iris_state.h
index ee20842..6db95a1 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_state.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_state.h
@@ -7,6 +7,7 @@ 
 #define _IRIS_STATE_H_
 
 struct iris_core;
+struct iris_inst;
 
 enum iris_core_state {
 	IRIS_CORE_DEINIT,
@@ -15,8 +16,29 @@  enum iris_core_state {
 	IRIS_CORE_ERROR,
 };
 
+enum iris_inst_state {
+	IRIS_INST_OPEN,
+	IRIS_INST_INPUT_STREAMING,
+	IRIS_INST_OUTPUT_STREAMING,
+	IRIS_INST_STREAMING,
+	IRIS_INST_CLOSE,
+	IRIS_INST_ERROR,
+};
+
+enum state_change {
+	STATE_CHANGE_ALLOW,
+	STATE_CHANGE_DISALLOW,
+	STATE_CHANGE_IGNORE,
+};
+
+#define IS_SESSION_ERROR(inst) \
+((inst)->state == IRIS_INST_ERROR)
+
 bool core_in_valid_state(struct iris_core *core);
 int iris_change_core_state(struct iris_core *core,
 			   enum iris_core_state request_state);
 
+int iris_inst_change_state(struct iris_inst *inst,
+			   enum iris_inst_state request_state);
+
 #endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vb2.c b/drivers/media/platform/qcom/vcodec/iris/iris_vb2.c
index a57b5fb..8f499a9 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vb2.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vb2.c
@@ -34,6 +34,9 @@  int iris_vb2_queue_setup(struct vb2_queue *q,
 	else
 		f = inst->fmt_dst;
 
+	if (inst->state == IRIS_INST_STREAMING)
+		return -EINVAL;
+
 	if (*num_planes) {
 		if (*num_planes != f->fmt.pix_mp.num_planes ||
 		    sizes[0] < f->fmt.pix_mp.plane_fmt[0].sizeimage)
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c b/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c
index 124333a..68ba75f 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c
@@ -168,6 +168,7 @@  int vidc_open(struct file *filp)
 
 	inst->core = core;
 	inst->session_id = hash32_ptr(inst);
+	iris_inst_change_state(inst, IRIS_INST_OPEN);
 	mutex_init(&inst->ctx_q_lock);
 
 	ret = vidc_add_session(inst);
@@ -244,6 +245,7 @@  int vidc_close(struct file *filp)
 	v4l2_ctrl_handler_free(&inst->ctrl_handler);
 	vdec_inst_deinit(inst);
 	close_session(inst);
+	iris_inst_change_state(inst, IRIS_INST_CLOSE);
 	vidc_vb2_queue_deinit(inst);
 	vidc_v4l2_fh_deinit(inst);
 	vidc_remove_session(inst);
@@ -295,6 +297,9 @@  static __poll_t vidc_poll(struct file *filp, struct poll_table_struct *pt)
 	if (!inst)
 		return EPOLLERR;
 
+	if (IS_SESSION_ERROR(inst))
+		return EPOLLERR;
+
 	poll_wait(filp, &inst->fh.wait, pt);
 	poll_wait(filp, &inst->vb2q_src->done_wq, pt);
 	poll_wait(filp, &inst->vb2q_dst->done_wq, pt);