Browse Source

msm: vidc: response handling

add response handling for commands, properties,
system and session errors.

Change-Id: I87a8cba136979d425d978dfe55317a3deb081c53
Signed-off-by: Darshana Patil <[email protected]>
Darshana Patil 4 years ago
parent
commit
9a854613cd

+ 2 - 1
Makefile

@@ -29,7 +29,8 @@ msm-vidc-objs   := driver/vidc/src/msm_vidc_v4l2.o \
                    driver/vidc/src/msm_vidc_debug.o \
                    driver/vidc/src/msm_vidc_memory.o \
                    driver/vidc/src/venus_hfi.o \
-                   driver/vidc/src/hfi_packet.o
+                   driver/vidc/src/hfi_packet.o \
+                   driver/vidc/src/venus_hfi_response.o
 
 ifneq ($(CONFIG_ARCH_QTI_VM), y)
 ifeq ($(CONFIG_ARCH_LAHAINA), y)

+ 6 - 5
driver/vidc/inc/hfi_command.h

@@ -127,12 +127,13 @@ struct metapayload_header {
 };
 
 enum hfi_property_mode_type {
-	HFI_MODE_NONE = 0,
-	HFI_MODE_PORT_SETTINGS_CHANGE = BIT(0),
-	HFI_MODE_PROPERTY = BIT(1),
-	HFI_MODE_METADATA = BIT(2),
+	HFI_MODE_NONE                  = 0,
+	HFI_MODE_PORT_SETTINGS_CHANGE  = BIT(0),
+	HFI_MODE_PROPERTY              = BIT(1),
+	HFI_MODE_METADATA              = BIT(2),
 };
 
+#define HFI_CMD_BEGIN                                           0x0
 #define HFI_CMD_INIT                                            0x1
 #define HFI_CMD_POWER_COLLAPSE                                  0x2
 #define HFI_CMD_OPEN                                            0x3
@@ -145,6 +146,6 @@ enum hfi_property_mode_type {
 #define HFI_CMD_DELIVERY_MODE                                   0xA
 #define HFI_CMD_SUBSCRIBE_MODE                                  0xB
 #define HFI_CMD_SETTINGS_CHANGE                                 0xC
-
+#define HFI_CMD_END                                             0xD
 
 #endif //__H_HFI_COMMAND_H__

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

@@ -43,4 +43,3 @@ int hfi_packet_session_property(struct msm_vidc_inst *inst,
 	u32 pkt_type, u32 flags, u32 port,
 	u32 payload_type, void *payload, u32 payload_size);
 #endif // _HFI_PACKET_H_
-

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

@@ -96,6 +96,7 @@ struct msm_vidc_core {
 	u32                                    last_packet_type;
 	u8                                    *packet;
 	u32                                    packet_size;
+	u8                                    *response_packet;
 	struct v4l2_file_operations           *v4l2_file_ops;
 	struct v4l2_ioctl_ops                 *v4l2_ioctl_ops;
 	struct v4l2_ctrl_ops                  *v4l2_ctrl_ops;
@@ -106,6 +107,7 @@ struct msm_vidc_core {
 	struct msm_vidc_memory_ops            *mem_ops;
 	u32                                    header_id;
 	u32                                    packet_id;
+	struct completion                      init_done;
 };
 
 #endif // _MSM_VIDC_CORE_H_

+ 7 - 0
driver/vidc/inc/msm_vidc_debug.h

@@ -87,6 +87,13 @@ enum vidc_msg_prio {
 #define d_vpr_b(__fmt, ...) \
 			dprintk(VIDC_BUS, DEFAULT_SID, __fmt, ##__VA_ARGS__)
 
+#define dprintk_firmware(__level, __fmt, ...)	\
+	do { \
+		pr_err(FW_DBG_TAG __fmt, \
+			"fw", \
+			##__VA_ARGS__); \
+	} while (0)
+
 #define MSM_VIDC_ERROR(value)					\
 	do {	if (value)					\
 			d_vpr_e("BugOn");		\

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

@@ -103,7 +103,9 @@ struct msm_vidc_map_info *msm_vidc_get_map_info(struct msm_vidc_inst *inst,
 	enum msm_vidc_buffer_type buffer_type);
 struct msm_vidc_alloc_info *msm_vidc_get_alloc_info(struct msm_vidc_inst *inst,
 	enum msm_vidc_buffer_type buffer_type);
-
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
+		u32 session_id);
+void put_inst(struct msm_vidc_inst *inst);
 void core_lock(struct msm_vidc_core *core, const char *function);
 void core_unlock(struct msm_vidc_core *core, const char *function);
 void inst_lock(struct msm_vidc_inst *inst, const char *function);

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

@@ -110,6 +110,7 @@ struct msm_vidc_inst {
 	struct dentry                     *debugfs_root;
 	struct msm_vidc_debug              debug;
 	struct msm_vidc_inst_capability   *capabilities;
+	struct completion                  completions[MAX_SIGNAL];
 };
 
 #endif // _MSM_VIDC_INST_H_

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

@@ -299,6 +299,12 @@ enum profiling_points {
 	MAX_PROFILING_POINTS,
 };
 
+enum signal_session_response {
+	SIGNAL_CMD_STOP  = 0,
+	SIGNAL_CMD_CLOSE,
+	MAX_SIGNAL,
+};
+
 #define HFI_MASK_QHDR_TX_TYPE			0xFF000000
 #define HFI_MASK_QHDR_RX_TYPE			0x00FF0000
 #define HFI_MASK_QHDR_PRI_TYPE			0x0000FF00

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

@@ -76,5 +76,6 @@ int __interrupt_init(struct msm_vidc_core *core);
 int __setup_ucregion_memmap(struct msm_vidc_core *core);
 int __raise_interrupt(struct msm_vidc_core *core);
 int __power_off(struct msm_vidc_core *core);
+bool __core_in_valid_state(struct msm_vidc_core *core);
 
 #endif // _VENUS_HFI_H_

+ 18 - 0
driver/vidc/inc/venus_hfi_response.h

@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __VENUS_HFI_RESPONSE_H__
+#define __VENUS_HFI_RESPONSE_H__
+
+int handle_response(struct msm_vidc_core *core,
+	void *response);
+int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
+	u32 core_resp_pkt_size, const char *func);
+bool is_valid_port(struct msm_vidc_inst *inst, u32 port,
+	const char *func);
+bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
+	u32 buffer_type, const char *func);
+
+#endif // __VENUS_HFI_RESPONSE_H__

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

@@ -429,7 +429,7 @@ int hfi_packet_sys_debug_config(struct msm_vidc_core *core,
 		goto err_debug;
 
 	/* HFI_PROP_DEBUG_CONFIG */
-	payload = debug_config; /*TODO:Change later*/
+	payload = 0; /*TODO:Change later*/
 	rc = hfi_create_packet(pkt, pkt_size,
 				   HFI_PROP_DEBUG_CONFIG,
 				   HFI_HOST_FLAGS_NONE,

+ 4 - 0
driver/vidc/src/msm_vidc.c

@@ -589,6 +589,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
 	int rc = 0;
 	struct msm_vidc_inst *inst;
 	struct msm_vidc_core *core;
+	int i = 0;
 
 	d_vpr_h("%s()\n", __func__);
 	core = vidc_core;
@@ -667,6 +668,9 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
 	inst->domain = session_type;
 	inst->state = MSM_VIDC_OPEN;
 	inst->request = false;
+	for (i = 0; i < MAX_SIGNAL; i++)
+		init_completion(&inst->completions[i]);
+
 	//inst->debugfs_root =
 	//	msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
 

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

@@ -6,7 +6,8 @@
 #include "msm_vidc_debug.h"
 
 int msm_vidc_debug = VIDC_HIGH | VIDC_LOW | VIDC_PKT | VIDC_ERR | VIDC_PRINTK |
-	FW_ERROR | FW_FATAL | FW_FTRACE;
+	FW_ERROR | FW_FATAL | FW_FTRACE | FW_LOW | FW_MEDIUM | FW_HIGH |
+	FW_PERF | FW_PRINTK;
 EXPORT_SYMBOL(msm_vidc_debug);
 
 bool msm_vidc_lossless_encode = !true;

+ 60 - 4
driver/vidc/src/msm_vidc_driver.c

@@ -14,6 +14,7 @@
 #include "msm_vidc_memory.h"
 #include "msm_vidc_debug.h"
 #include "venus_hfi.h"
+#include "msm_vidc.h"
 
 #define COUNT_BITS(a, out) ({       \
 	while ((a) >= 1) {          \
@@ -901,6 +902,11 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 	if (rc)
 		goto unlock;
 
+	core->state = MSM_VIDC_CORE_INIT;
+	init_completion(&core->init_done);
+	core->smmu_fault_handled = false;
+	core->ssr.trigger = false;
+
 	rc = venus_hfi_core_init(core);
 	if (rc) {
 		d_vpr_e("%s: core init failed\n", __func__);
@@ -908,9 +914,18 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 		goto unlock;
 	}
 
-	core->state = MSM_VIDC_CORE_INIT;
-	core->smmu_fault_handled = false;
-	core->ssr.trigger = false;
+	mutex_unlock(&core->lock);
+	/*TODO: acquire lock or not */
+	rc = wait_for_completion_timeout(&core->init_done, msecs_to_jiffies(
+			core->platform->data.core_data[DEBUG_TIMEOUT].value));
+	if (!rc) {
+		d_vpr_e("%s: system init timed out\n", __func__);
+		//msm_comm_kill_session(inst);
+		rc = -EIO;
+	} else {
+		rc = 0;
+	}
+	mutex_lock(&core->lock);
 
 unlock:
 	mutex_unlock(&core->lock);
@@ -945,6 +960,47 @@ void msm_vidc_batch_handler(struct work_struct *work)
 {
 }
 
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
+		u32 session_id)
+{
+	struct msm_vidc_inst *inst = NULL;
+	bool matches = false;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return NULL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst->session_id == session_id) {
+			matches = true;
+			break;
+		}
+	}
+	inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL;
+	mutex_unlock(&core->lock);
+	return inst;
+}
+
+static void put_inst_helper(struct kref *kref)
+{
+	struct msm_vidc_inst *inst = container_of(kref,
+			struct msm_vidc_inst, kref);
+
+	msm_vidc_close(inst);
+}
+
+void put_inst(struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	kref_put(&inst->kref, put_inst_helper);
+}
+
 void core_lock(struct msm_vidc_core *core, const char *function)
 {
 	mutex_lock(&core->lock);
@@ -963,4 +1019,4 @@ void inst_lock(struct msm_vidc_inst *inst, const char *function)
 void inst_unlock(struct msm_vidc_inst *inst, const char *function)
 {
 	mutex_unlock(&inst->lock);
-}
+}

+ 122 - 6
driver/vidc/src/venus_hfi.c

@@ -23,6 +23,9 @@
 #include "msm_vidc_driver.h"
 #include "msm_vidc_debug.h"
 #include "hfi_packet.h"
+#include "venus_hfi_response.h"
+
+#define MIN_PAYLOAD_SIZE 3
 
 static int __resume(struct msm_vidc_core *core);
 static int __suspend(struct msm_vidc_core *core);
@@ -150,7 +153,7 @@ static void __strict_check(struct msm_vidc_core *core)
 	__fatal_error(core, !mutex_is_locked(&core->lock));
 }
 
-static bool __core_in_valid_state(struct msm_vidc_core *core)
+bool __core_in_valid_state(struct msm_vidc_core *core)
 {
 	return core->state != MSM_VIDC_CORE_ERROR;
 }
@@ -566,6 +569,7 @@ static int __write_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
 	d_vpr_e("skip writing packet\n");
 	return 0;
 
+
 	packet_size_in_words = (*(u32 *)packet) >> 2;
 	if (!packet_size_in_words || packet_size_in_words >
 		qinfo->q_array.mem_size>>2) {
@@ -624,7 +628,7 @@ static int __write_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
 	mb();
 	return 0;
 }
-#if 0
+
 static int __read_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
 		u32 *pb_tx_req_is_set)
 {
@@ -748,7 +752,7 @@ static int __read_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
 
 	return rc;
 }
-#endif
+
 /* Writes into cmdq without raising an interrupt */
 static int __iface_cmdq_write_relaxed(struct msm_vidc_core *core,
 		void *pkt, bool *requires_interrupt)
@@ -814,7 +818,7 @@ static int __iface_cmdq_write(struct msm_vidc_core *core,
 
 	return rc;
 }
-/*
+
 static int __iface_msgq_read(struct msm_vidc_core *core, void *pkt)
 {
 	u32 tx_req_is_set = 0;
@@ -845,8 +849,9 @@ static int __iface_msgq_read(struct msm_vidc_core *core, void *pkt)
 		if (tx_req_is_set)
 			call_venus_op(core, raise_interrupt, core);
 		rc = 0;
-	} else
+	} else {
 		rc = -ENODATA;
+	}
 
 read_error_null:
 	return rc;
@@ -882,7 +887,74 @@ static int __iface_dbgq_read(struct msm_vidc_core *core, void *pkt)
 dbg_error_null:
 	return rc;
 }
-*/
+
+/*TODO:darshana needs discussion*/
+static void __flush_debug_queue(struct msm_vidc_core *core, u8 *header)
+{
+	bool local_packet = false;
+	enum vidc_msg_prio log_level = msm_vidc_debug;
+	struct hfi_packet *pkt;
+	u32 payload = 0;
+
+	if (!header) {
+		header = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_KERNEL);
+		if (!header) {
+			d_vpr_e("%s: Fail to allocate mem\n", __func__);
+			return;
+		}
+
+		local_packet = true;
+
+		/*
+		 * Local packet is used when error occurred.
+		 * It is good to print these logs to printk as well.
+		 */
+		log_level |= FW_PRINTK;
+	}
+
+#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \
+		if (pkt_size < pkt_hdr_size || \
+			payload_size < MIN_PAYLOAD_SIZE || \
+			payload_size > \
+			(pkt_size - pkt_hdr_size + sizeof(u8))) { \
+			d_vpr_e("%s: invalid msg size - %d\n", \
+				__func__, payload_size); \
+			continue; \
+		} \
+	})
+
+	while (!__iface_dbgq_read(core, header)) {
+		struct hfi_header *hdr =
+			(struct hfi_header *) header;
+
+		if (!validate_packet((u8 *)pkt, core->response_packet,
+				core->packet_size, __func__))
+			return;
+
+		pkt = (struct hfi_packet *)(hdr + sizeof(struct hfi_header));
+		if (pkt->type == HFI_PROP_DEBUG_LOG_LEVEL) {
+			SKIP_INVALID_PKT(pkt->size,
+				sizeof(u32), sizeof(*pkt));
+
+			payload = (u32) *((u8 *)pkt + sizeof(struct hfi_packet));
+
+			/*
+			 * All fw messages starts with new line character. This
+			 * causes dprintk to print this message in two lines
+			 * in the kernel log. Ignoring the first character
+			 * from the message fixes this to print it in a single
+			 * line.
+			 */
+			//pkt->rg_msg_data[sizeof(u32)-1] = '\0';
+			dprintk_firmware(log_level, "%s", &payload);
+		}
+	}
+#undef SKIP_INVALID_PKT
+
+	if (local_packet)
+		kfree(header);
+}
+
 static int __sys_set_debug(struct msm_vidc_core *core, u32 debug)
 {
 	int rc = 0;
@@ -2192,9 +2264,29 @@ static void __unload_fw(struct msm_vidc_core *core)
 	d_vpr_h("Firmware unloaded successfully\n");
 }
 
+static int __response_handler(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	while (!__iface_msgq_read(core, core->response_packet)) {
+		rc = handle_response(core, core->response_packet);
+		if (rc)
+			continue;
+		/* check for system error */
+		if (core->state != MSM_VIDC_CORE_INIT)
+			break;
+	}
+
+	__schedule_power_collapse_work(core);
+	__flush_debug_queue(core, core->response_packet);
+
+	return rc;
+}
+
 void venus_hfi_work_handler(struct work_struct *work)
 {
 	struct msm_vidc_core *core;
+	int num_responses = 0;
 
 	core = container_of(work, struct msm_vidc_core, device_work);
 	if (!core) {
@@ -2202,6 +2294,21 @@ void venus_hfi_work_handler(struct work_struct *work)
 		return;
 	}
 	d_vpr_e("%s(): core %pK\n", __func__, core);
+
+	mutex_lock(&core->lock);
+	if (__resume(core)) {
+		d_vpr_e("%s: Power on failed\n", __func__);
+		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);
 }
 
 void venus_hfi_pm_work_handler(struct work_struct *work)
@@ -2273,6 +2380,14 @@ int venus_hfi_core_init(struct msm_vidc_core *core)
 		return -ENOMEM;
 	}
 
+	core->response_packet = kzalloc(core->packet_size, GFP_KERNEL);
+	if (!core->response_packet) {
+		d_vpr_e("%s(): core response packet allocation failed\n",
+			__func__);
+		kfree(core->packet);
+		return -ENOMEM;
+	}
+
 	rc = __load_fw(core);
 	if (rc)
 		return rc;
@@ -2311,6 +2426,7 @@ int venus_hfi_core_init(struct msm_vidc_core *core)
 error:
 	d_vpr_h("%s(): failed\n", __func__);
 	__unload_fw(core);
+	kfree(core->response_packet);
 	kfree(core->packet);
 	return rc;
 }

+ 469 - 0
driver/vidc/src/venus_hfi_response.c

@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include "hfi_packet.h"
+#include "venus_hfi.h"
+#include "venus_hfi_response.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+
+bool is_valid_hfi_port(struct msm_vidc_inst *inst, u32 port,
+	const char *func)
+{
+	if (!inst) {
+		s_vpr_e(inst->sid, "%s: invalid params\n", func);
+		return false;
+	}
+
+	if (port != HFI_PORT_BITSTREAM && port != HFI_PORT_RAW) {
+		s_vpr_e(inst->sid, "%s: invalid port %#x\n", func, port);
+		return false;
+	}
+	return true;
+}
+
+bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
+	u32 buffer_type, const char *func)
+{
+	if (!inst) {
+		s_vpr_e(inst->sid, "%s: invalid params\n", func);
+		return false;
+	}
+
+	if (buffer_type != HFI_BUFFER_BITSTREAM &&
+			buffer_type != HFI_BUFFER_RAW &&
+			buffer_type != HFI_BUFFER_METADATA) {
+		s_vpr_e(inst->sid, "%s: invalid buffer type %#x\n",
+			func, buffer_type);
+		return false;
+	}
+	return true;
+}
+
+static int signal_session_msg_receipt(struct msm_vidc_inst *inst,
+	enum signal_session_response cmd)
+{
+	if (cmd < MAX_SIGNAL)
+		complete(&inst->completions[cmd]);
+	return 0;
+}
+
+int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
+	u32 core_resp_pkt_size, const char *func)
+{
+	u8 *response_limit;
+
+	if (!response_pkt || !core_resp_pkt || !core_resp_pkt_size) {
+		d_vpr_e("%s: invalid params\n", func);
+		return -EINVAL;
+	}
+
+	response_limit = core_resp_pkt + core_resp_pkt_size -
+		max(sizeof(struct hfi_header), sizeof(struct hfi_packet));
+
+	if (response_pkt < core_resp_pkt || response_pkt > response_limit) {
+		d_vpr_e("%s: invalid packet address\n", func);
+		return -EINVAL;
+	}
+
+	if (response_pkt + *(u32 *)response_pkt > response_limit) {
+		d_vpr_e("%s: invalid packet size %d\n",
+			func, *(u32 *)response_pkt);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int handle_session_error(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	int rc = 0;
+	char *error;
+
+	switch (pkt->type) {
+	case HFI_ERROR_MAX_SESSIONS:
+		error = "exceeded max sessions";
+		break;
+	case HFI_ERROR_UNSUPPORTED:
+		error = "unsupported bitstream";
+		break;
+	default:
+		error = "unknown";
+		break;
+	}
+
+	s_vpr_e(inst->sid, "session error (%#x): %s\n", pkt->type, error);
+
+	rc = msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
+	return rc;
+}
+
+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);
+	return 0;
+}
+
+static int handle_system_init(struct msm_vidc_core *core,
+	struct hfi_packet *pkt)
+{
+	if (pkt->flags & HFI_FW_FLAGS_SYSTEM_ERROR) {
+		d_vpr_e("%s: received system error\n", __func__);
+		return 0;
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS) {
+		d_vpr_h("%s: successful\n", __func__);
+		complete(&core->init_done);
+	}
+
+	return 0;
+}
+
+static int handle_session_open(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	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);
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		s_vpr_h(inst->sid, "%s: successful\n", __func__);
+
+	return 0;
+}
+
+static int handle_session_close(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	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);
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		s_vpr_h(inst->sid, "%s: successful\n", __func__);
+
+	signal_session_msg_receipt(inst, SIGNAL_CMD_CLOSE);
+	return 0;
+}
+
+static int handle_session_start(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	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);
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		s_vpr_h(inst->sid, "%s: successful for port %d\n",
+			__func__, pkt->port);
+	return 0;
+}
+
+static int handle_session_stop(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	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);
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		s_vpr_h(inst->sid, "%s: successful for port %d\n",
+			__func__, pkt->port);
+	signal_session_msg_receipt(inst, SIGNAL_CMD_STOP);
+	return 0;
+}
+
+static int handle_session_drain(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	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);
+	}
+
+	if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
+		s_vpr_h(inst->sid, "%s: successful\n", __func__);
+	return 0;
+}
+
+static void handle_input_buffer(struct msm_vidc_inst *inst,
+	struct hfi_buffer *buffer)
+{
+}
+
+static void handle_output_buffer(struct msm_vidc_inst *inst,
+	struct hfi_buffer *buffer)
+{
+}
+
+static void handle_input_metadata_buffer(struct msm_vidc_inst *inst,
+	struct hfi_buffer *buffer)
+{
+}
+
+static void handle_output_metadata_buffer(struct msm_vidc_inst *inst,
+	struct hfi_buffer *buffer)
+{
+}
+
+static int handle_session_buffer(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	struct hfi_buffer *buffer;
+	u32 buf_type = 0, port_type = 0;
+
+	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);
+		return 0;
+	}
+
+	port_type = pkt->port;
+	if (!is_valid_hfi_port(inst, port_type, __func__)) {
+		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
+		return 0;
+	}
+
+	buffer = (struct hfi_buffer *)(pkt + sizeof(struct hfi_packet));
+	buf_type = buffer->type;
+	if (!is_valid_hfi_buffer_type(inst, buf_type, __func__)) {
+		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
+		return 0;
+	}
+
+	s_vpr_h(inst->sid, "%s: Received buffer of type %#x\n",
+		__func__, buf_type);
+
+	if (is_encode_session(inst)) {
+		if (port_type == HFI_PORT_BITSTREAM) {
+			if (buf_type == HFI_BUFFER_METADATA)
+				handle_output_metadata_buffer(inst, buffer);
+			else if (buf_type == HFI_BUFFER_BITSTREAM)
+				handle_output_buffer(inst, buffer);
+		} else  if (port_type == HFI_PORT_RAW) {
+			if (buf_type == HFI_BUFFER_METADATA)
+				handle_input_metadata_buffer(inst, buffer);
+			else if (buf_type == HFI_BUFFER_RAW)
+				handle_input_buffer(inst, buffer);
+		}
+	} else if (is_decode_session(inst)) {
+		if (port_type == HFI_PORT_BITSTREAM) {
+			if (buf_type == HFI_BUFFER_METADATA)
+				handle_input_metadata_buffer(inst, buffer);
+			else if (buf_type == HFI_BUFFER_BITSTREAM)
+				handle_input_buffer(inst, buffer);
+		} else  if (port_type == HFI_PORT_RAW) {
+			if (buf_type == HFI_BUFFER_METADATA)
+				handle_output_metadata_buffer(inst, buffer);
+			else if (buf_type == HFI_BUFFER_RAW)
+				handle_output_buffer(inst, buffer);
+		}
+	} else {
+		s_vpr_e(inst->sid, "%s: invalid session\n", __func__);
+	}
+
+	return 0;
+}
+
+static int handle_port_settings_change(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	s_vpr_h(inst->sid, "%s: Received port settings change, type %d\n",
+		__func__, pkt->port);
+	return 0;
+}
+
+static int handle_session_command(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	switch (pkt->type) {
+	case HFI_CMD_OPEN:
+		return handle_session_open(inst, pkt);
+	case HFI_CMD_CLOSE:
+		return handle_session_close(inst, pkt);
+	case HFI_CMD_START:
+		return handle_session_start(inst, pkt);
+	case HFI_CMD_STOP:
+		return handle_session_stop(inst, pkt);
+	case HFI_CMD_DRAIN:
+		return handle_session_drain(inst, pkt);
+	case HFI_CMD_BUFFER:
+		return handle_session_buffer(inst, pkt);
+	case HFI_CMD_SETTINGS_CHANGE:
+		return handle_port_settings_change(inst, pkt);
+	default:
+		s_vpr_e(inst->sid, "%s: Unsupported command type: %#x\n",
+			__func__, pkt->type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int handle_session_property(struct msm_vidc_inst *inst,
+	struct hfi_packet *pkt)
+{
+	s_vpr_h(inst->sid, "%s: property type %#x\n", __func__, pkt->type);
+	return 0;
+}
+
+static int handle_image_version_property(struct hfi_packet *pkt)
+{
+	u32 i = 0;
+	char version[256];
+	const u32 version_string_size = 128;
+	u8 *str_image_version;
+	u32 req_bytes;
+
+	req_bytes = pkt->size - sizeof(*pkt);
+	if (req_bytes < version_string_size) {
+		d_vpr_e("%s: bad_pkt: %d\n", __func__, req_bytes);
+		return -EINVAL;
+	}
+	str_image_version = (u8 *)pkt + sizeof(struct hfi_packet);
+	/*
+	 * The version string returned by firmware includes null
+	 * characters at the start and in between. Replace the null
+	 * characters with space, to print the version info.
+	 */
+	for (i = 0; i < version_string_size; i++) {
+		if (str_image_version[i] != '\0')
+			version[i] = str_image_version[i];
+		else
+			version[i] = ' ';
+	}
+	version[i] = '\0';
+	d_vpr_h("%s: F/W version: %s\n", __func__, version);
+	return 0;
+}
+
+static int handle_system_property(struct msm_vidc_core *core,
+	struct hfi_packet *pkt)
+{
+	int rc = 0;
+
+	if (pkt->flags & HFI_FW_FLAGS_SYSTEM_ERROR) {
+		d_vpr_e("%s: received system error for property type %#x\n",
+			__func__, pkt->type);
+		return handle_system_error(core, pkt);
+	}
+
+	switch (pkt->type) {
+	case HFI_PROP_IMAGE_VERSION:
+		rc = handle_image_version_property(pkt);
+		break;
+	default:
+		d_vpr_h("%s: property type %#x successful\n",
+			__func__, pkt->type);
+		break;
+	}
+	return rc;
+}
+
+static int handle_system_response(struct msm_vidc_core *core,
+	struct hfi_header *hdr)
+{
+	int rc = 0;
+	struct hfi_packet *pkt;
+	int i;
+
+	pkt = (struct hfi_packet *)(hdr + sizeof(struct hfi_header));
+
+	for (i = 0; i < hdr->num_packets; i++) {
+		if (!validate_packet((u8 *)pkt, core->response_packet,
+				core->packet_size, __func__))
+			return -EINVAL;
+		if (pkt->type == HFI_CMD_INIT) {
+			rc = handle_system_init(core, pkt);
+		} else if (pkt->type > HFI_SYSTEM_ERROR_BEGIN &&
+				pkt->type < HFI_SYSTEM_ERROR_END) {
+			rc = handle_system_error(core, pkt);
+		} else if (pkt->type > HFI_PROP_BEGIN &&
+				pkt->type < HFI_PROP_CODEC) {
+			rc = handle_system_property(core, pkt);
+		} else {
+			d_vpr_e("%s: Unknown packet type: %#x\n",
+			__func__, pkt->type);
+			return -EINVAL;
+		}
+		pkt += pkt->size;
+	}
+	return rc;
+}
+
+static int handle_session_response(struct msm_vidc_core *core,
+	struct hfi_header *hdr)
+{
+	struct hfi_packet *pkt;
+	struct msm_vidc_inst *inst;
+	int i, rc = 0;
+
+	inst = get_inst(core, hdr->session_id);
+	if (!inst) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		goto exit;
+	}
+
+	pkt = (struct hfi_packet *)(hdr + sizeof(struct hfi_header));
+
+	for (i = 0; i < hdr->num_packets; i++) {
+		if (!validate_packet((u8 *)pkt, core->response_packet,
+				core->packet_size, __func__))
+			goto exit;
+		if (pkt->type < HFI_CMD_END && pkt->type > HFI_CMD_BEGIN) {
+			rc = handle_session_command(inst, pkt);
+		} else if (pkt->type > HFI_PROP_BEGIN &&
+				pkt->type < HFI_PROP_END) {
+			rc = handle_session_property(inst, pkt);
+		} else if (pkt->type > HFI_SESSION_ERROR_BEGIN &&
+				pkt->type < HFI_SESSION_ERROR_END) {
+			rc = handle_session_error(inst, pkt);
+		} else {
+			s_vpr_e(inst->sid, "%s: Unknown packet type: %#x\n",
+				__func__, pkt->type);
+			goto exit;
+		}
+		pkt += pkt->size;
+	}
+exit:
+	put_inst(inst);
+	return rc;
+}
+
+int handle_response(struct msm_vidc_core *core, void *response)
+{
+	struct hfi_header *hdr;
+
+	if (!core || !response) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = (struct hfi_header *)response;
+	if (!validate_packet((u8 *)hdr, core->response_packet,
+			core->packet_size, __func__))
+		return -EINVAL;
+
+	if (!hdr->session_id)
+		return handle_system_response(core, hdr);
+	else
+		return handle_session_response(core, hdr);
+
+	return 0;
+}