瀏覽代碼

video: driver: kill session and core deinit support

Add below support
- kill session in case of errors
- core deinit in case of timeout errors
- flush buffers in streamoff
- decide supported colorformats based on
  bitdepth and interlace info
- print level based logs

Change-Id: I45b9b0eae4220a818de23308da8802a9e12ae255
Signed-off-by: Maheshwar Ajja <[email protected]>
Maheshwar Ajja 4 年之前
父節點
當前提交
39e830e7e3

+ 4 - 2
driver/platform/waipio/src/msm_vidc_waipio.c

@@ -934,11 +934,13 @@ static struct msm_platform_inst_capability instance_data_waipio[] = {
 		MSM_VIDC_POWER_SAVE_MODE, 1,
 		MSM_VIDC_MAX_QUALITY_MODE},
 
-	{CODED_FRAMES, DEC, CODECS_ALL, 0, 1, 1, 0,
+	{CODED_FRAMES, DEC, CODECS_ALL,
+		CODED_FRAMES_MBS_ONLY, CODED_FRAMES_ADAPTIVE_FIELDS,
+		1, CODED_FRAMES_MBS_ONLY,
 		0,
 		HFI_PROP_CODED_FRAMES},
 
-	{BIT_DEPTH, DEC, CODECS_ALL, 8 << 16 | 8, 10 << 16 | 10, 1, 8 << 16 | 8,
+	{BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8,
 		0,
 		HFI_PROP_LUMA_CHROMA_BIT_DEPTH},
 

+ 3 - 1
driver/variant/iris2/src/msm_vidc_iris2.c

@@ -367,8 +367,10 @@ static int __watchdog_iris2(struct msm_vidc_core *vidc_core, u32 intr_status)
 		return -EINVAL;
 	}
 
-	if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2)
+	if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2) {
+		d_vpr_e("%s: received watchdog interrupt\n", __func__);
 		rc = 1;
+	}
 
 	return rc;
 }

+ 0 - 1
driver/vidc/inc/msm_vidc_core.h

@@ -57,7 +57,6 @@ struct msm_vidc_core_power {
 enum msm_vidc_core_state {
 	MSM_VIDC_CORE_DEINIT       = 0,
 	MSM_VIDC_CORE_INIT         = 1,
-	MSM_VIDC_CORE_ERROR        = 2,
 };
 
 struct msm_vidc_core {

+ 10 - 5
driver/vidc/inc/msm_vidc_debug.h

@@ -56,11 +56,13 @@ enum vidc_msg_prio {
 
 #define dprintk(__level, sid, __fmt, ...)	\
 	do { \
-		pr_err(VIDC_DBG_TAG __fmt, \
-			"level", \
-			sid, \
-			"codec", \
-			##__VA_ARGS__); \
+		if (msm_vidc_debug & __level) { \
+			pr_err(VIDC_DBG_TAG __fmt, \
+				level_str(__level), \
+				sid, \
+				"codec", \
+				##__VA_ARGS__); \
+		} \
 	} while (0)
 
 #define s_vpr_e(sid, __fmt, ...) dprintk(VIDC_ERR, sid, __fmt, ##__VA_ARGS__)
@@ -99,4 +101,7 @@ enum vidc_msg_prio {
 	do {	if (value)					\
 			d_vpr_e("BugOn");		\
 	} while (0)
+
+const char *level_str(u32 level);
+
 #endif

+ 34 - 3
driver/vidc/inc/msm_vidc_driver.h

@@ -114,7 +114,15 @@ static inline bool is_linear_colorformat(enum msm_vidc_colorformat_type colorfor
 {
 	return colorformat == MSM_VIDC_FMT_NV12 ||
 		colorformat == MSM_VIDC_FMT_NV21 ||
-		colorformat == MSM_VIDC_FMT_P010;
+		colorformat == MSM_VIDC_FMT_P010 ||
+		colorformat == MSM_VIDC_FMT_RGBA8888;
+}
+
+static inline bool is_ubwc_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_NV12C ||
+		colorformat == MSM_VIDC_FMT_TP10C ||
+		colorformat == MSM_VIDC_FMT_RGBA8888C;
 }
 
 static inline bool is_10bit_colorformat(enum msm_vidc_colorformat_type colorformat)
@@ -123,6 +131,15 @@ static inline bool is_10bit_colorformat(enum msm_vidc_colorformat_type colorform
 		colorformat == MSM_VIDC_FMT_TP10C;
 }
 
+static inline bool is_8bit_colorformat(enum msm_vidc_colorformat_type colorformat)
+{
+	return colorformat == MSM_VIDC_FMT_NV12 ||
+		colorformat == MSM_VIDC_FMT_NV12C ||
+		colorformat == MSM_VIDC_FMT_NV21 ||
+		colorformat == MSM_VIDC_FMT_RGBA8888 ||
+		colorformat == MSM_VIDC_FMT_RGBA8888C;
+}
+
 static inline bool is_secondary_output_mode(struct msm_vidc_inst *inst)
 {
 	return false; // TODO: inst->stream_output_mode == HAL_VIDEO_DECODER_SECONDARY;
@@ -161,6 +178,11 @@ static inline bool is_active_session(u64 prev, u64 curr)
 			MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS);
 }
 
+static inline bool is_session_error(struct msm_vidc_inst* inst)
+{
+	return inst->state == MSM_VIDC_ERROR;
+}
+
 void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
 		struct msm_vidc_buffer *vbuf);
 void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst,
@@ -179,7 +201,7 @@ int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type,
 	const char *func);
 const char *state_name(enum msm_vidc_inst_state state);
 int msm_vidc_change_inst_state(struct msm_vidc_inst *inst,
-	enum msm_vidc_inst_state state, const char *func);
+	enum msm_vidc_inst_state request_state, const char *func);
 int msm_vidc_get_input_internal_buffers(struct msm_vidc_inst *inst,
 	enum msm_vidc_buffer_type buffer_type);
 int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst,
@@ -199,9 +221,13 @@ int msm_vidc_session_streamon(struct msm_vidc_inst *inst,
 int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
 		enum msm_vidc_port_type port);
 int msm_vidc_session_close(struct msm_vidc_inst *inst);
+int msm_vidc_kill_session(struct msm_vidc_inst* inst);
 int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst);
+int msm_vidc_change_core_state(struct msm_vidc_core *core,
+	enum msm_vidc_core_state request_state, const char *func);
 int msm_vidc_core_init(struct msm_vidc_core *core);
 int msm_vidc_core_deinit(struct msm_vidc_core *core);
+int msm_vidc_core_timeout(struct msm_vidc_core *core);
 int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
 		struct device *dev, unsigned long iova, int flags, void *data);
 int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
@@ -236,6 +262,8 @@ int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
 int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffer *buffer);
 void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst);
+int msm_vidc_flush_buffers(struct msm_vidc_inst* inst,
+	enum msm_vidc_buffer_type type);
 struct msm_vidc_buffer *get_meta_buffer(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffer *vbuf);
 struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core,
@@ -261,10 +289,13 @@ int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst);
 int msm_vidc_state_change_last_flag(struct msm_vidc_inst *inst);
 int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst);
 int msm_vidc_get_fps(struct msm_vidc_inst *inst);
-int msm_vidc_num_queued_bufs(struct msm_vidc_inst *inst, u32 type);
+int msm_vidc_num_buffers(struct msm_vidc_inst *inst,
+	enum msm_vidc_buffer_type type, enum msm_vidc_buffer_attributes attr);
 void core_lock(struct msm_vidc_core *core, const char *function);
 void core_unlock(struct msm_vidc_core *core, const char *function);
+bool core_lock_check(struct msm_vidc_core *core, const char *function);
 void inst_lock(struct msm_vidc_inst *inst, const char *function);
 void inst_unlock(struct msm_vidc_inst *inst, const char *function);
+bool inst_lock_check(struct msm_vidc_inst *inst, const char *function);
 #endif // _MSM_VIDC_DRIVER_H_
 

+ 4 - 0
driver/vidc/inc/msm_vidc_internal.h

@@ -43,6 +43,10 @@
 #define DEFAULT_BITSTREM_ALIGNMENT  16
 #define H265_BITSTREM_ALIGNMENT     32
 #define DEFAULT_MAX_HOST_BUF_COUNT  32
+#define BIT_DEPTH_8 (8 << 16 | 8)
+#define BIT_DEPTH_10 (10 << 16 | 10)
+#define CODED_FRAMES_MBS_ONLY HFI_BITMASK_FRAME_MBS_ONLY_FLAG
+#define CODED_FRAMES_ADAPTIVE_FIELDS HFI_BITMASK_MB_ADAPTIVE_FRAME_FIELD_FLAG
 
 /* TODO
  * #define MAX_SUPERFRAME_COUNT     32

+ 33 - 2
driver/vidc/src/msm_vdec.c

@@ -1861,6 +1861,34 @@ int msm_vdec_g_param(struct msm_vidc_inst *inst,
 	return 0;
 }
 
+static int msm_vdec_check_colorformat_supported(struct msm_vidc_inst* inst,
+		enum msm_vidc_colorformat_type colorformat)
+{
+	bool supported = true;
+
+	/* do not reject coloformats before streamon */
+	if (!inst->vb2q[INPUT_PORT].streaming)
+		return true;
+
+	/*
+	 * bit_depth 8 bit supports 8 bit colorformats only
+	 * bit_depth 10 bit supports 10 bit colorformats only
+	 * interlace supports ubwc colorformats only
+	 */
+	if (inst->capabilities->cap[BIT_DEPTH].value == BIT_DEPTH_8 &&
+		!is_8bit_colorformat(colorformat))
+		supported = false;
+	if (inst->capabilities->cap[BIT_DEPTH].value == BIT_DEPTH_10 &&
+		!is_10bit_colorformat(colorformat))
+		supported = false;
+	if (inst->capabilities->cap[CODED_FRAMES].value ==
+		CODED_FRAMES_ADAPTIVE_FIELDS &&
+		!is_ubwc_colorformat(colorformat))
+		supported = false;
+
+	return supported;
+}
+
 int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
 {
 	int rc = 0;
@@ -1900,8 +1928,11 @@ int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
 			if (idx > 31)
 				break;
 			if (formats & BIT(i)) {
-				array[idx] = formats & BIT(i);
-				idx++;
+				if (msm_vdec_check_colorformat_supported(inst,
+						formats & BIT(i))) {
+					array[idx] = formats & BIT(i);
+					idx++;
+				}
 			}
 			i++;
 			formats >>= 1;

+ 2 - 11
driver/vidc/src/msm_vidc.c

@@ -700,18 +700,9 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
 		return NULL;
 	}
 
-	if (core->state == MSM_VIDC_CORE_ERROR) {
-		d_vpr_e("%s: core invalid state\n", __func__);
+	rc = msm_vidc_core_init(core);
+	if (rc)
 		return NULL;
-	}
-
-	if (core->state == MSM_VIDC_CORE_DEINIT) {
-		rc = msm_vidc_core_init(core);
-		if (rc) {
-			msm_vidc_core_deinit(core);
-			return NULL;
-		}
-	}
 
 	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
 	if (!inst) {

+ 18 - 1
driver/vidc/src/msm_vidc_debug.c

@@ -5,7 +5,7 @@
 
 #include "msm_vidc_debug.h"
 
-int msm_vidc_debug = VIDC_HIGH | VIDC_LOW | VIDC_PKT | VIDC_ERR | VIDC_PRINTK |
+int msm_vidc_debug = VIDC_HIGH | VIDC_PKT | VIDC_ERR | VIDC_PRINTK |
 	FW_ERROR | FW_FATAL | FW_FTRACE | FW_LOW | FW_MED | FW_HIGH |
 	FW_PERF | FW_PRINTK;
 EXPORT_SYMBOL(msm_vidc_debug);
@@ -18,3 +18,20 @@ EXPORT_SYMBOL(msm_vidc_syscache_disable);
 
 int msm_vidc_clock_voting = !1;
 
+const char *level_str(u32 level)
+{
+	if (level & VIDC_ERR)
+		return "err ";
+	else if (level & VIDC_HIGH)
+		return "high";
+	else if (level & VIDC_LOW)
+		return "low ";
+	else if (level & VIDC_PERF)
+		return "perf";
+	else if (level & VIDC_PKT)
+		return "pkt ";
+	else if (level & VIDC_BUS)
+		return "bus ";
+	else
+		return "????";
+}

+ 194 - 32
driver/vidc/src/msm_vidc_driver.c

@@ -415,6 +415,45 @@ struct msm_vidc_allocations *msm_vidc_get_allocations(
 	}
 }
 
+const char *core_state_name(enum msm_vidc_core_state state)
+{
+	const char* name = "UNKNOWN";
+
+	switch (state) {
+	case MSM_VIDC_CORE_INIT:
+		name = "CORE_INIT";
+		break;
+	case MSM_VIDC_CORE_DEINIT:
+		name = "CORE_DEINIT";
+		break;
+	default:
+		name = "UNKNOWN";
+		break;
+	}
+
+	return name;
+}
+
+int msm_vidc_change_core_state(struct msm_vidc_core *core,
+	enum msm_vidc_core_state request_state, const char *func)
+{
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!request_state) {
+		d_vpr_e("%s: invalid core request state\n", func);
+		return -EINVAL;
+	}
+
+	d_vpr_h("%s: core state changed from %s to %s\n",
+		func, core_state_name(core->state),
+		core_state_name(request_state));
+	core->state = request_state;
+	return 0;
+}
+
 const char *state_name(enum msm_vidc_inst_state state)
 {
 	const char *name = "UNKNOWN";
@@ -1097,29 +1136,31 @@ int msm_vidc_get_fps(struct msm_vidc_inst *inst)
 	return fps;
 }
 
-int msm_vidc_num_queued_bufs(struct msm_vidc_inst *inst, u32 type)
+int msm_vidc_num_buffers(struct msm_vidc_inst *inst,
+		enum msm_vidc_buffer_type type, enum msm_vidc_buffer_attributes attr)
 {
 	int count = 0;
 	struct msm_vidc_buffer *vbuf;
-	struct msm_vidc_buffers* buffers;
+	struct msm_vidc_buffers *buffers;
 
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
-		return 0;
+		return count;
 	}
-	if (type == OUTPUT_MPLANE) {
+	if (type == MSM_VIDC_BUF_OUTPUT) {
 		buffers = &inst->buffers.output;
-	} else if (type == INPUT_MPLANE) {
+	} else if (type == MSM_VIDC_BUF_INPUT) {
 		buffers = &inst->buffers.input;
 	} else {
-		s_vpr_e(inst->sid, "%s: invalid buffer type %#x\n", __func__, type);
-		return -EINVAL;
+		s_vpr_e(inst->sid, "%s: invalid buffer type %#x\n",
+				__func__, type);
+		return count;
 	}
 
 	list_for_each_entry(vbuf, &buffers->list, list) {
 		if (vbuf->type != type)
 			continue;
-		if (!(vbuf->attr & MSM_VIDC_ATTR_QUEUED))
+		if (!(vbuf->attr & attr))
 			continue;
 		count++;
 	}
@@ -1565,7 +1606,6 @@ int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst,
 	struct msm_vidc_alloc *alloc;
 	struct msm_vidc_map *map;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
@@ -1650,7 +1690,6 @@ int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffers *buffers;
 	int i;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
@@ -1679,7 +1718,6 @@ int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffers *buffers;
 	struct msm_vidc_buffer *buffer, *dummy;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
@@ -1727,7 +1765,6 @@ int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst,
 	struct msm_vidc_buffers *buffers;
 	struct msm_vidc_buffer *buffer, *dummy;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
@@ -1999,8 +2036,22 @@ int msm_vidc_session_open(struct msm_vidc_inst *inst)
 		return -EINVAL;
 	}
 
+	inst->packet_size = 4096;
+	inst->packet = kzalloc(inst->packet_size, GFP_KERNEL);
+	if (!inst->packet) {
+		s_vpr_e(inst->sid, "%s(): inst packet allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
 	rc = venus_hfi_session_open(inst);
+	if (rc)
+		goto error;
 
+	return 0;
+error:
+	s_vpr_e(inst->sid, "%s(): session open failed\n", __func__);
+	kfree(inst->packet);
+	inst->packet = NULL;
 	return rc;
 }
 
@@ -2043,8 +2094,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
 	enum msm_vidc_port_type port)
 {
 	int rc = 0;
+	int count = 0;
 	struct msm_vidc_core *core;
 	enum signal_session_response signal_type;
+	enum msm_vidc_buffer_type buffer_type;
 
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
@@ -2053,8 +2106,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
 
 	if (port == INPUT_PORT) {
 		signal_type = SIGNAL_CMD_STOP_INPUT;
+		buffer_type = MSM_VIDC_BUF_INPUT;
 	} else if (port == OUTPUT_PORT) {
 		signal_type = SIGNAL_CMD_STOP_OUTPUT;
+		buffer_type = MSM_VIDC_BUF_OUTPUT;
 	} else {
 		s_vpr_e(inst->sid, "%s: invalid port: %d\n", __func__, port);
 		return -EINVAL;
@@ -2072,19 +2127,31 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst,
 			&inst->completions[signal_type],
 			msecs_to_jiffies(
 			core->capabilities[HW_RESPONSE_TIMEOUT].value));
-	mutex_lock(&inst->lock);
 	if (!rc) {
 		s_vpr_e(inst->sid, "%s: session stop timed out for port: %d\n",
 				__func__, port);
-		//msm_comm_kill_session(inst);
-		rc = -EIO;
+		rc = -ETIMEDOUT;
+		msm_vidc_core_timeout(inst->core);
 	} else {
 		rc = 0;
-		s_vpr_h(inst->sid, "%s: stop successful on port: %d\n",
-			__func__, port);
 	}
+	mutex_lock(&inst->lock);
 
-	return rc;
+	/* no more queued buffers after streamoff */
+	count = msm_vidc_num_buffers(inst, buffer_type, MSM_VIDC_ATTR_QUEUED);
+	if (count) {
+		s_vpr_e(inst->sid, "%s: %d buffers pending on port: %d\n",
+			__func__, count, port);
+		msm_vidc_kill_session(inst);
+	}
+	rc = msm_vidc_flush_buffers(inst, buffer_type);
+	if (rc)
+		return rc;
+
+	s_vpr_h(inst->sid, "%s: stop successful on port: %d\n",
+		__func__, port);
+
+	return 0;
 }
 
 int msm_vidc_session_close(struct msm_vidc_inst *inst)
@@ -2109,19 +2176,43 @@ int msm_vidc_session_close(struct msm_vidc_inst *inst)
 			&inst->completions[SIGNAL_CMD_CLOSE],
 			msecs_to_jiffies(
 			core->capabilities[HW_RESPONSE_TIMEOUT].value));
-	mutex_lock(&inst->lock);
 	if (!rc) {
 		s_vpr_e(inst->sid, "%s: session close timed out\n", __func__);
-		//msm_comm_kill_session(inst);
-		rc = -EIO;
+		rc = -ETIMEDOUT;
+		msm_vidc_core_timeout(inst->core);
 	} else {
 		rc = 0;
 		s_vpr_h(inst->sid, "%s: close successful\n", __func__);
 	}
+	mutex_lock(&inst->lock);
+
+	msm_vidc_remove_session(inst);
+
+	s_vpr_h(inst->sid, "%s: free session packet data\n", __func__);
+	kfree(inst->packet);
+	inst->packet = NULL;
 
 	return rc;
 }
 
+int msm_vidc_kill_session(struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	if (!inst->session_id) {
+		s_vpr_e(inst->sid, "%s: already killed\n", __func__);
+		return 0;
+	}
+
+	s_vpr_e(inst->sid, "%s: killing session\n", __func__);
+	msm_vidc_session_close(inst);
+	msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+
+	return 0;
+}
+
 int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
@@ -2367,16 +2458,28 @@ error:
 int msm_vidc_core_deinit(struct msm_vidc_core *core)
 {
 	int rc = 0;
+	struct msm_vidc_inst *inst, *dummy;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
 	mutex_lock(&core->lock);
+	d_vpr_h("%s()\n", __func__);
+	if (core->state == MSM_VIDC_CORE_DEINIT)
+		goto unlock;
+
 	venus_hfi_core_deinit(core);
 	msm_vidc_deinit_instance_caps(core);
 	msm_vidc_deinit_core_caps(core);
+	/* unlink all sessions from core, if any */
+	list_for_each_entry_safe(inst, dummy, &core->instances, list) {
+		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+		list_del(&inst->list);
+	}
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
+
+unlock:
 	mutex_unlock(&core->lock);
 	return rc;
 }
@@ -2385,18 +2488,12 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 {
 	int rc = 0;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!core || !core->platform) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
 
 	mutex_lock(&core->lock);
-	if (core->state == MSM_VIDC_CORE_ERROR) {
-		d_vpr_e("%s: core invalid state\n", __func__);
-		rc = -EINVAL;
-		goto unlock;
-	}
 	if (core->state == MSM_VIDC_CORE_INIT) {
 		rc = 0;
 		goto unlock;
@@ -2409,7 +2506,7 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 	if (rc)
 		goto unlock;
 
-	core->state = MSM_VIDC_CORE_INIT;
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__);
 	init_completion(&core->init_done);
 	core->smmu_fault_handled = false;
 	core->ssr.trigger = false;
@@ -2417,7 +2514,6 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 	rc = venus_hfi_core_init(core);
 	if (rc) {
 		d_vpr_e("%s: core init failed\n", __func__);
-		core->state = MSM_VIDC_CORE_DEINIT;
 		goto unlock;
 	}
 
@@ -2426,20 +2522,27 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 	mutex_unlock(&core->lock);
 	rc = wait_for_completion_timeout(&core->init_done, msecs_to_jiffies(
 			core->capabilities[HW_RESPONSE_TIMEOUT].value));
+	mutex_lock(&core->lock);
 	if (!rc) {
-		d_vpr_e("%s: system init timed out\n", __func__);
+		d_vpr_e("%s: core init timed out\n", __func__);
 		rc = -ETIMEDOUT;
 	} else {
 		d_vpr_h("%s: system init wait completed\n", __func__);
 		rc = 0;
 	}
-	mutex_lock(&core->lock);
 
 unlock:
 	mutex_unlock(&core->lock);
+	if (rc)
+		msm_vidc_core_init(core);
 	return rc;
 }
 
+int msm_vidc_core_timeout(struct msm_vidc_core *core)
+{
+	return msm_vidc_core_deinit(core);
+}
+
 int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
 		struct device *dev, unsigned long iova, int flags, void *data)
 {
@@ -2468,6 +2571,50 @@ void msm_vidc_batch_handler(struct work_struct *work)
 {
 }
 
+int msm_vidc_flush_buffers(struct msm_vidc_inst* inst,
+		enum msm_vidc_buffer_type type)
+{
+	int rc = 0;
+	struct msm_vidc_buffers *buffers;
+	struct msm_vidc_buffer *buf, *dummy;
+	enum msm_vidc_buffer_type buffer_type[2];
+	int i;
+
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (type == MSM_VIDC_BUF_INPUT) {
+		buffer_type[0] = MSM_VIDC_BUF_INPUT_META;
+		buffer_type[1] = MSM_VIDC_BUF_INPUT;
+	} else if (type == MSM_VIDC_BUF_OUTPUT) {
+		buffer_type[0] = MSM_VIDC_BUF_OUTPUT_META;
+		buffer_type[1] = MSM_VIDC_BUF_OUTPUT;
+	} else {
+		s_vpr_h(inst->sid, "%s: invalid buffer type %d\n",
+				__func__, type);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(buffer_type); i++) {
+		buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__);
+		if (!buffers)
+			return -EINVAL;
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			if (buf->attr & MSM_VIDC_ATTR_QUEUED ||
+				buf->attr & MSM_VIDC_ATTR_DEFERRED) {
+				print_vidc_buffer(VIDC_ERR, "flushing buffer", inst, buf);
+				msm_vidc_vb2_buffer_done(inst, buf);
+				msm_vidc_put_driver_buf(inst, buf);
+			}
+		}
+	}
+
+	return rc;
+}
+
 void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst)
 {
 	struct msm_vidc_buffers *buffers;
@@ -2488,6 +2635,11 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst)
 	};
 	int i;
 
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(buf_types); i++) {
 		buffers = msm_vidc_get_buffers(inst, buf_types[i], __func__);
 		if (!buffers)
@@ -2577,6 +2729,11 @@ void put_inst(struct msm_vidc_inst *inst)
 	kref_put(&inst->kref, msm_vidc_close_helper);
 }
 
+bool core_lock_check(struct msm_vidc_core *core, const char* func)
+{
+	return mutex_is_locked(&core->lock);
+}
+
 void core_lock(struct msm_vidc_core *core, const char *function)
 {
 	mutex_lock(&core->lock);
@@ -2587,6 +2744,11 @@ void core_unlock(struct msm_vidc_core *core, const char *function)
 	mutex_unlock(&core->lock);
 }
 
+bool inst_lock_check(struct msm_vidc_inst *inst, const char* func)
+{
+	return mutex_is_locked(&inst->lock);
+}
+
 void inst_lock(struct msm_vidc_inst *inst, const char *function)
 {
 	mutex_lock(&inst->lock);

+ 4 - 2
driver/vidc/src/msm_vidc_power.c

@@ -425,9 +425,11 @@ static int msm_vidc_apply_dcvs(struct msm_vidc_inst *inst)
 	power = &inst->power;
 
 	if (is_decode_session(inst)) {
-		bufs_with_fw = msm_vidc_num_queued_bufs(inst, OUTPUT_MPLANE);
+		bufs_with_fw = msm_vidc_num_buffers(inst,
+			MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_QUEUED);
 	} else {
-		bufs_with_fw = msm_vidc_num_queued_bufs(inst, INPUT_MPLANE);
+		bufs_with_fw = msm_vidc_num_buffers(inst,
+			MSM_VIDC_BUF_INPUT, MSM_VIDC_ATTR_QUEUED);
 	}
 
 	/* +1 as one buffer is going to be queued after the function */

+ 2 - 2
driver/vidc/src/msm_vidc_probe.c

@@ -178,7 +178,7 @@ static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
 	d_vpr_h("%s()\n", __func__);
 
 	mutex_destroy(&core->lock);
-	core->state = MSM_VIDC_CORE_DEINIT;
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
 
 	if (core->pm_workq)
 		destroy_workqueue(core->pm_workq);
@@ -199,7 +199,7 @@ static int msm_vidc_initialize_core(struct msm_vidc_core *core)
 	}
 	d_vpr_h("%s()\n", __func__);
 
-	core->state = MSM_VIDC_CORE_DEINIT;
+	msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__);
 
 	core->device_workq = create_singlethread_workqueue("device_workq");
 	if (!core->device_workq) {

+ 1 - 1
driver/vidc/src/msm_vidc_v4l2.c

@@ -12,7 +12,7 @@
 
 static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
 {
-	if (!filp->private_data)
+	if (!filp || !filp->private_data)
 		return NULL;
 	return container_of(filp->private_data,
 					struct msm_vidc_inst, event_handler);

+ 89 - 25
driver/vidc/src/venus_hfi.c

@@ -33,6 +33,8 @@
 
 #define MAX_FIRMWARE_NAME_SIZE 128
 
+extern struct msm_vidc_core *g_core;
+
 static int __resume(struct msm_vidc_core *core);
 static int __suspend(struct msm_vidc_core *core);
 
@@ -161,7 +163,7 @@ static void __strict_check(struct msm_vidc_core *core)
 
 bool __core_in_valid_state(struct msm_vidc_core *core)
 {
-	return core->state != MSM_VIDC_CORE_ERROR;
+	return core->state == MSM_VIDC_CORE_INIT;
 }
 
 static bool is_sys_cache_present(struct msm_vidc_core *core)
@@ -169,6 +171,30 @@ static bool is_sys_cache_present(struct msm_vidc_core *core)
 	return core->dt->sys_cache_present;
 }
 
+static bool valdiate_session(struct msm_vidc_inst* inst, const char *func)
+{
+	bool valid = false;
+	struct msm_vidc_inst *temp;
+	struct msm_vidc_core *core = g_core;
+
+	if (!core)
+		return false;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp == inst) {
+			valid = true;
+			break;
+		}
+	}
+	mutex_unlock(&core->lock);
+
+	if (!valid)
+		s_vpr_e(inst->sid, "%s: invalid session\n", func);
+
+	return valid;
+}
+
 void __write_register(struct msm_vidc_core *core,
 		u32 reg, u32 value)
 {
@@ -879,8 +905,12 @@ int __iface_msgq_read(struct msm_vidc_core *core, void *pkt)
 	}
 
 	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
-		if (tx_req_is_set)
-			call_venus_op(core, raise_interrupt, core);
+		if (tx_req_is_set) {
+			//call_venus_op(core, raise_interrupt, core);
+			d_vpr_e("%s: queue is full\n", __func__);
+			rc = -EINVAL;
+			goto read_error_null;
+		}
 		rc = 0;
 	} else {
 		rc = -ENODATA;
@@ -911,11 +941,16 @@ int __iface_dbgq_read(struct msm_vidc_core *core, void *pkt)
 	}
 
 	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
-		if (tx_req_is_set)
-			call_venus_op(core, raise_interrupt, core);
+		if (tx_req_is_set) {
+			d_vpr_e("%s: queue is full\n", __func__);
+			//call_venus_op(core, raise_interrupt, core);
+			rc = -EINVAL;
+			goto dbg_error_null;
+		}
 		rc = 0;
-	} else
+	} else {
 		rc = -ENODATA;
+	}
 
 dbg_error_null:
 	return rc;
@@ -1909,6 +1944,24 @@ static int __set_ubwc_config(struct msm_vidc_core *core)
 	return rc;
 }
 */
+
+static int __venus_power_off(struct msm_vidc_core* core)
+{
+	int rc = 0;
+
+	if (!core->power_enabled)
+		return 0;
+
+	rc = call_venus_op(core, power_off, core);
+	if (rc) {
+		d_vpr_e("Failed to power off, err: %d\n", rc);
+		return rc;
+	}
+	core->power_enabled = false;
+
+	return rc;
+}
+
 static int __venus_power_on(struct msm_vidc_core *core)
 {
 	int rc = 0;
@@ -2009,7 +2062,7 @@ static int __resume(struct msm_vidc_core *core)
 	} else if (core->power_enabled) {
 		goto exit;
 	} else if (!__core_in_valid_state(core)) {
-		d_vpr_e("%s: core in deinit state\n", __func__);
+		d_vpr_e("%s: core not in valid state\n", __func__);
 		return -EINVAL;
 	}
 
@@ -2394,9 +2447,7 @@ static void __unload_fw(struct msm_vidc_core *core)
 	qcom_scm_pas_shutdown(core->dt->fw_cookie);
 	core->dt->fw_cookie = 0;
 
-	__interface_queues_deinit(core);
-	call_venus_op(core, power_off, core);
-
+	__venus_power_off(core);
 	__deinit_resources(core);
 
 	d_vpr_h("Firmware unloaded successfully\n");
@@ -2447,16 +2498,15 @@ void venus_hfi_work_handler(struct work_struct *work)
 	mutex_lock(&core->lock);
 	if (__resume(core)) {
 		d_vpr_e("%s: Power on failed\n", __func__);
+		mutex_unlock(&core->lock);
 		goto err_no_work;
 	}
-
 	call_venus_op(core, clear_interrupt, core);
 	mutex_unlock(&core->lock);
 
 	num_responses = __response_handler(core);
 
 err_no_work:
-	mutex_unlock(&core->lock);
 	if (!call_venus_op(core, watchdog, core, core->intr_status))
 		enable_irq(core->dt->irq);
 }
@@ -2614,6 +2664,7 @@ int venus_hfi_core_deinit(struct msm_vidc_core *core)
 		return -EINVAL;
 	}
 	d_vpr_h("%s(): core %pK\n", __func__, core);
+	__flush_debug_queue(core, core->packet, core->packet_size);
 	__disable_subcaches(core);
 	__interface_queues_deinit(core);
 	__unload_fw(core);
@@ -2655,13 +2706,6 @@ int venus_hfi_session_open(struct msm_vidc_inst *inst)
 		return -EINVAL;
 	}
 
-	inst->packet_size = 4096;
-	inst->packet = kzalloc(inst->packet_size, GFP_KERNEL);
-	if (!inst->packet) {
-		d_vpr_e("%s(): inst packet allocation failed\n", __func__);
-		return -ENOMEM;
-	}
-
 	rc = hfi_packet_session_command(inst,
 				HFI_CMD_OPEN,
 				(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
@@ -2672,13 +2716,13 @@ int venus_hfi_session_open(struct msm_vidc_inst *inst)
 				&inst->session_id, /* payload */
 				sizeof(u32));
 	if (rc)
-		goto error;
+		return rc;
 
 	rc = __iface_cmdq_write(inst->core, inst->packet);
 	if (rc)
-		goto error;
-error:
-	return rc;
+		return rc;
+
+	return 0;
 }
 
 int venus_hfi_session_set_codec(struct msm_vidc_inst *inst)
@@ -2690,6 +2734,8 @@ int venus_hfi_session_set_codec(struct msm_vidc_inst *inst)
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
 
 	codec = get_hfi_codec(inst);
 	rc = venus_hfi_session_property(inst,
@@ -2719,6 +2765,9 @@ int venus_hfi_session_property(struct msm_vidc_inst *inst,
 	}
 	core = inst->core;
 
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
+
 	rc = hfi_create_header(inst->packet, inst->packet_size,
 				inst->session_id, core->header_id++);
 	if (rc)
@@ -2753,6 +2802,8 @@ int venus_hfi_session_close(struct msm_vidc_inst *inst)
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
 
 	rc = hfi_packet_session_command(inst,
 				HFI_CMD_CLOSE,
@@ -2767,8 +2818,6 @@ int venus_hfi_session_close(struct msm_vidc_inst *inst)
 	if (!rc)
 		__iface_cmdq_write(inst->core, inst->packet);
 
-	kfree(inst->packet);
-
 	return rc;
 }
 
@@ -2780,6 +2829,9 @@ int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port)
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
+
 	if (port != INPUT_PORT && port != OUTPUT_PORT) {
 		s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port);
 		return -EINVAL;
@@ -2812,6 +2864,9 @@ int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port)
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
+
 	if (port != INPUT_PORT && port != OUTPUT_PORT) {
 		s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port);
 		return -EINVAL;
@@ -2850,6 +2905,9 @@ int venus_hfi_session_command(struct msm_vidc_inst *inst,
 	}
 	core = inst->core;
 
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
+
 	rc = hfi_create_header(inst->packet, inst->packet_size,
 			inst->session_id,
 			core->header_id++);
@@ -2892,6 +2950,9 @@ int venus_hfi_queue_buffer(struct msm_vidc_inst *inst,
 	}
 	core = inst->core;
 
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
+
 	rc = get_hfi_buffer(inst, buffer, &hfi_buffer);
 	if (rc)
 		return rc;
@@ -2948,6 +3009,9 @@ int venus_hfi_release_buffer(struct msm_vidc_inst *inst,
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
+	if (!valdiate_session(inst, __func__))
+		return -EINVAL;
+
 	if (!is_internal_buffer(buffer->type)) {
 		s_vpr_e(inst->sid, "release not allowed for buffer type %d\n",
 			buffer->type);

+ 4 - 9
driver/vidc/src/venus_hfi_response.c

@@ -229,16 +229,8 @@ static int handle_session_error(struct msm_vidc_inst *inst,
 static int handle_system_error(struct msm_vidc_core *core,
 	struct hfi_packet *pkt)
 {
-	mutex_lock(&core->lock);
-	if (core->state == MSM_VIDC_CORE_DEINIT) {
-		d_vpr_e("%s: core already deinitialized\n", __func__);
-		mutex_unlock(&core->lock);
-		return 0;
-	}
-
 	d_vpr_e("%s: system error received\n", __func__);
-	core->state = MSM_VIDC_CORE_DEINIT;
-	mutex_unlock(&core->lock);
+	msm_vidc_core_deinit(core);
 	return 0;
 }
 
@@ -264,6 +256,7 @@ static int handle_session_open(struct msm_vidc_inst *inst,
 	if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
 		s_vpr_e(inst->sid, "%s: received session error\n", __func__);
 		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+		return 0;
 	}
 
 	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
@@ -293,6 +286,7 @@ static int handle_session_start(struct msm_vidc_inst *inst,
 	if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
 		s_vpr_e(inst->sid, "%s: received session error\n", __func__);
 		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+		return 0;
 	}
 
 	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
@@ -351,6 +345,7 @@ static int handle_session_drain(struct msm_vidc_inst *inst,
 	if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
 		s_vpr_e(inst->sid, "%s: received session error\n", __func__);
 		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+		return 0;
 	}
 
 	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)