msm: vidc: Handles secure/non-secure concurrency.

Handles concurrency scenarios by preventing
nonsecure sessions when secure sessions are
ongoing. This is required since secure and
non-secure sessions cannot run concurrently.

Change-Id: I197a4c437312d916c0f75e7eb026c0570fee12ff
Signed-off-by: Deepak Kotur <dkotur@codeaurora.org>
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 483eab0..77ad02e 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -33,6 +33,7 @@
 			struct mem_region *mregion);
 	u32 width;
 	u32 height;
+	int secure;
 };
 
 struct venc {
@@ -266,6 +267,7 @@
 	struct venc_inst *inst;
 	struct video_client_ctx *client_ctx;
 	struct venc_msg_ops *vmops  =  arg;
+	int flags = 0;
 	mutex_lock(&venc_p.lock);
 	client_index = venc_get_empty_client_index();
 	if (client_index < 0) {
@@ -284,7 +286,11 @@
 	inst->op_buffer_done = vmops->op_buffer_done;
 	inst->ip_buffer_done = vmops->ip_buffer_done;
 	inst->cbdata = vmops->cbdata;
-
+	inst->secure = vmops->secure;
+	if (vmops->secure) {
+		WFD_MSG_ERR("OPENING SECURE SESSION\n");
+		flags |= VCD_CP_SESSION;
+	}
 	if (vcd_get_ion_status()) {
 		client_ctx->user_ion_client = vcd_get_ion_client();
 		if (!client_ctx->user_ion_client) {
@@ -294,9 +300,10 @@
 	}
 
 	rc = vcd_open(venc_p.device_handle, false, venc_cb,
-					inst);
+				inst, flags);
 	if (rc) {
 		WFD_MSG_ERR("vcd_open failed, rc = %d\n", rc);
+		rc = -ENODEV;
 		goto no_free_client;
 	}
 	wait_for_completion(&client_ctx->event);
@@ -1684,6 +1691,7 @@
 	struct vcd_property_enc_recon_buffer *ctrl = NULL;
 	unsigned long phy_addr;
 	int i = 0;
+	int flags = 0;
 	u32 len;
 	control.width = inst->width;
 	control.height = inst->height;
@@ -1696,6 +1704,8 @@
 		WFD_MSG_ERR("Failed to get recon buf size\n");
 		goto err;
 	}
+	flags = ION_HEAP(ION_CP_MM_HEAP_ID);
+	flags |= inst->secure ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID);
 
 	if (vcd_get_ion_status()) {
 		for (i = 0; i < 4; ++i) {
@@ -1706,8 +1716,7 @@
 			ctrl->user_virtual_addr = (void *)i;
 			client_ctx->recon_buffer_ion_handle[i]
 				= ion_alloc(client_ctx->user_ion_client,
-			control.size, SZ_8K, ION_HEAP(ION_IOMMU_HEAP_ID) |
-			ION_HEAP(ION_CP_MM_HEAP_ID));
+			control.size, SZ_8K, flags);
 
 			ctrl->kernel_virtual_addr = ion_map_kernel(
 				client_ctx->user_ion_client,
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
index 69e7521..cafc9d5 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.h
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -44,6 +44,7 @@
 struct venc_msg_ops {
 	void *cookie;
 	void *cbdata;
+	int secure;
 	void (*op_buffer_done)(void *cookie, u32 status,
 			struct vb2_buffer *buf);
 	void (*ip_buffer_done)(void *cookie, u32 status,
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 2c2c551..fb586be 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -152,7 +152,7 @@
 	int rc;
 
 	alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
-	alloc_regions |= secure ? 0 :
+	alloc_regions |= secure ? ION_SECURE :
 				ION_HEAP(ION_IOMMU_HEAP_ID);
 	handle = ion_alloc(client,
 			mregion->size, SZ_4K, alloc_regions);
@@ -1279,6 +1279,7 @@
 	enc_mops.op_buffer_done = venc_op_buffer_done;
 	enc_mops.ip_buffer_done = venc_ip_buffer_done;
 	enc_mops.cbdata = filp;
+	enc_mops.secure = wfd_dev->secure_device;
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
 				(void *)&enc_mops);
 	if (rc || !enc_mops.cookie) {
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index b4161dd..a8ccebf 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -60,7 +60,7 @@
 #define DDL_ENC_MIN_DPB_BUFFERS           2
 #define DDL_ENC_MAX_DPB_BUFFERS           4
 
-#define DDL_FW_AUX_HOST_CMD_SPACE_SIZE         (DDL_KILO_BYTE(8))
+#define DDL_FW_AUX_HOST_CMD_SPACE_SIZE         (DDL_KILO_BYTE(4))
 #define DDL_FW_INST_GLOBAL_CONTEXT_SPACE_SIZE  (DDL_KILO_BYTE(800))
 #define DDL_FW_H264DEC_CONTEXT_SPACE_SIZE      (DDL_KILO_BYTE(800))
 #define DDL_FW_H264ENC_CONTEXT_SPACE_SIZE      (DDL_KILO_BYTE(20))
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 61deb8d..9b6d4b4 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -2034,29 +2034,38 @@
 	return true;
 }
 
-struct video_client_ctx *vid_dec_open_client(void)
+int vid_dec_open_client(struct video_client_ctx **vid_clnt_ctx, int flags)
 {
+	int rc = 0;
 	s32 client_index;
-	struct video_client_ctx *client_ctx;
-	u32 vcd_status = VCD_ERR_FAIL;
+	struct video_client_ctx *client_ctx = NULL;
 	u8 client_count;
 
+	if (!vid_clnt_ctx) {
+		ERR("Invalid input\n");
+		return -EINVAL;
+	}
+	*vid_clnt_ctx = NULL;
 	client_count = vcd_get_num_of_clients();
 	if (client_count == VIDC_MAX_NUM_CLIENTS) {
 		ERR("ERROR : vid_dec_open() max number of clients"
 			"limit reached\n");
+		rc = -ENOMEM;
 		goto client_failure;
 	}
 
 	DBG(" Virtual Address of ioremap is %p\n", vid_dec_device_p->virt_base);
 	if (!vid_dec_device_p->num_clients) {
-		if (!vidc_load_firmware())
+		if (!vidc_load_firmware()) {
+			rc = -ENOMEM;
 			goto client_failure;
+		}
 	}
 
 	client_index = vid_dec_get_empty_client_index();
-	if (client_index < 0) {
-		ERR("%s() : No free clients client_index < 0\n", __func__);
+	if (client_index == -1) {
+		ERR("%s() : No free clients client_index == -1\n", __func__);
+		rc = -ENOMEM;
 		goto client_failure;
 	}
 	client_ctx = &vid_dec_device_p->vdec_clients[client_index];
@@ -2074,72 +2083,82 @@
 		client_ctx->user_ion_client = vcd_get_ion_client();
 		if (!client_ctx->user_ion_client) {
 			ERR("vcd_open ion client get failed");
+			rc = -ENOMEM;
 			goto client_failure;
 		}
 	}
-	vcd_status = vcd_open(vid_dec_device_p->device_handle, true,
-				  vid_dec_vcd_cb, client_ctx);
-	if (!vcd_status) {
+	rc = vcd_open(vid_dec_device_p->device_handle, true,
+				  vid_dec_vcd_cb, client_ctx, flags);
+	if (!rc) {
 		wait_for_completion(&client_ctx->event);
 		if (client_ctx->event_status) {
 			ERR("callback for vcd_open returned error: %u",
 				client_ctx->event_status);
+			rc = -ENODEV;
 			goto client_failure;
 		}
 	} else {
-		ERR("vcd_open returned error: %u", vcd_status);
+		ERR("vcd_open returned error: %u", rc);
 		goto client_failure;
 	}
 	client_ctx->seq_header_set = false;
-	return client_ctx;
+	*vid_clnt_ctx = client_ctx;
 client_failure:
-	return NULL;
+	return rc;
 }
 
 static int vid_dec_open_secure(struct inode *inode, struct file *file)
 {
+	int rc = 0;
+	struct video_client_ctx *client_ctx;
 	mutex_lock(&vid_dec_device_p->lock);
-	if (res_trk_check_for_sec_session() || vcd_get_num_of_clients()) {
-		ERR("Secure session present return failure\n");
-		mutex_unlock(&vid_dec_device_p->lock);
-		return -ENODEV;
-	}
 	res_trk_secure_set();
-	file->private_data = vid_dec_open_client();
-	if (!file->private_data) {
+	rc = vid_dec_open_client(&client_ctx, VCD_CP_SESSION);
+	if (rc)
+		goto error;
+	if (!client_ctx) {
+		rc = -ENOMEM;
 		goto error;
 	}
 
+	file->private_data = client_ctx;
 	if (res_trk_open_secure_session()) {
 		ERR("Secure session operation failure\n");
+		rc = -EACCES;
 		goto error;
 	}
 	mutex_unlock(&vid_dec_device_p->lock);
 	return 0;
-
 error:
 	res_trk_secure_unset();
 	mutex_unlock(&vid_dec_device_p->lock);
-	return -ENODEV;
-
+	return rc;
 }
 
 static int vid_dec_open(struct inode *inode, struct file *file)
 {
+	int rc = 0;
+	struct video_client_ctx *client_ctx;
 	INFO("msm_vidc_dec: Inside %s()", __func__);
 	mutex_lock(&vid_dec_device_p->lock);
 	if (res_trk_check_for_sec_session()) {
 		ERR("Secure session present return failure\n");
 		mutex_unlock(&vid_dec_device_p->lock);
-		return -ENODEV;
+		return -EACCES;
 	}
-	file->private_data = vid_dec_open_client();
-	if (!file->private_data) {
+	rc = vid_dec_open_client(&client_ctx, 0);
+	if (rc) {
 		mutex_unlock(&vid_dec_device_p->lock);
-		return -ENODEV;
+		return rc;
 	}
+	if (!client_ctx) {
+		mutex_unlock(&vid_dec_device_p->lock);
+		return -ENOMEM;
+	}
+
+	file->private_data = client_ctx;
 	mutex_unlock(&vid_dec_device_p->lock);
-	return 0;
+	return rc;
 }
 
 static int vid_dec_release_secure(struct inode *inode, struct file *file)
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 93b1848..d93d07e 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -521,7 +521,7 @@
 {
 	s32 client_index;
 	struct video_client_ctx *client_ctx;
-	u32 vcd_status = VCD_ERR_FAIL;
+	int rc = 0;
 	u8 client_count = 0;
 
 	INFO("\n msm_vidc_enc: Inside %s()", __func__);
@@ -530,10 +530,9 @@
 
 	stop_cmd = 0;
 	client_count = vcd_get_num_of_clients();
-	if (client_count == VIDC_MAX_NUM_CLIENTS ||
-		res_trk_check_for_sec_session()) {
+	if (client_count == VIDC_MAX_NUM_CLIENTS) {
 		ERR("ERROR : vid_enc_open() max number of clients"
-		    "limit reached or secure session is open\n");
+		    "limit reached\n");
 		mutex_unlock(&vid_enc_device_p->lock);
 		return -ENODEV;
 	}
@@ -568,11 +567,11 @@
 			return -EFAULT;
 		}
 	}
-	vcd_status = vcd_open(vid_enc_device_p->device_handle, false,
-		vid_enc_vcd_cb, client_ctx);
+	rc = vcd_open(vid_enc_device_p->device_handle, false,
+		vid_enc_vcd_cb, client_ctx, 0);
 	client_ctx->stop_msg = 0;
 
-	if (!vcd_status) {
+	if (!rc) {
 		wait_for_completion(&client_ctx->event);
 		if (client_ctx->event_status) {
 			ERR("callback for vcd_open returned error: %u",
@@ -581,13 +580,13 @@
 			return -EFAULT;
 		}
 	} else {
-		ERR("vcd_open returned error: %u", vcd_status);
+		ERR("vcd_open returned error: %u", rc);
 		mutex_unlock(&vid_enc_device_p->lock);
-		return -EFAULT;
+		return rc;
 	}
 	file->private_data = client_ctx;
 	mutex_unlock(&vid_enc_device_p->lock);
-	return 0;
+	return rc;
 }
 
 static int vid_enc_release(struct inode *inode, struct file *file)
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.c b/drivers/video/msm/vidc/common/vcd/vcd_api.c
index e0ef3af..401aa43 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.c
@@ -74,24 +74,103 @@
 }
 EXPORT_SYMBOL(vcd_term);
 
+struct client_security_info {
+	int secure_enc;
+	int secure_dec;
+	int non_secure_enc;
+	int non_secure_dec;
+};
+
+static int vcd_get_clients_security_info(struct client_security_info *sec_info)
+{
+	struct vcd_drv_ctxt *drv_ctxt;
+	struct vcd_clnt_ctxt *cctxt;
+	int count = 0;
+	if (!sec_info) {
+		VCD_MSG_ERROR("Invalid argument\n");
+		return -EINVAL;
+	}
+	memset(sec_info, 0 , sizeof(*sec_info));
+	drv_ctxt = vcd_get_drv_context();
+	mutex_lock(&drv_ctxt->dev_mutex);
+	cctxt = drv_ctxt->dev_ctxt.cctxt_list_head;
+	while (cctxt) {
+		if (cctxt->secure && cctxt->decoding)
+			sec_info->secure_dec++;
+		else if (cctxt->secure && !cctxt->decoding)
+			sec_info->secure_enc++;
+		else if (!cctxt->secure && cctxt->decoding)
+			sec_info->non_secure_dec++;
+		else
+			sec_info->non_secure_enc++;
+		count++;
+		cctxt = cctxt->next;
+	}
+	mutex_unlock(&drv_ctxt->dev_mutex);
+	return count;
+}
+
+static int is_session_invalid(u32 decoding, u32 flags)
+{
+	int is_secure;
+	struct client_security_info sec_info;
+	int client_count = 0;
+	int secure_session_running = 0;
+	is_secure = (flags & VCD_CP_SESSION) ? 1 : 0;
+	client_count = vcd_get_clients_security_info(&sec_info);
+	secure_session_running = (sec_info.secure_enc > 0) ||
+			(sec_info.secure_dec > 0);
+	if (!decoding && is_secure) {
+		if ((sec_info.secure_dec > 1) ||
+			(sec_info.secure_enc)
+		   ) {
+			VCD_MSG_HIGH("SE-SE: FAILURE\n");
+			VCD_MSG_HIGH("S-S-SE: FAILURE\n");
+			return -EACCES;
+		}
+	} else if (!decoding && !is_secure) {
+		if (secure_session_running) {
+			VCD_MSG_HIGH("SD-NSE: FAILURE\n");
+			VCD_MSG_HIGH("SE-NSE: FAILURE\n");
+			return -EACCES;
+		}
+	} else if (decoding && is_secure) {
+		if (client_count > 0) {
+			VCD_MSG_HIGH("S/NS-SD: FAILURE\n");
+			if (sec_info.secure_enc > 0 ||
+				sec_info.non_secure_enc > 0) {
+				return -EAGAIN;
+			}
+			return -EACCES;
+		}
+	} else {
+		if (sec_info.secure_dec > 0) {
+			VCD_MSG_HIGH("SD-NSD: FAILURE\n");
+			return -EACCES;
+		}
+	}
+	return 0;
+}
+
 u32 vcd_open(s32 driver_handle, u32 decoding,
 	void (*callback) (u32 event, u32 status, void *info, size_t sz,
 		       void *handle, void *const client_data),
-	void *client_data)
+	void *client_data, int flags)
 {
-	u32 rc = VCD_S_SUCCESS;
+	u32 rc = 0;
 	struct vcd_drv_ctxt *drv_ctxt;
-
+	struct vcd_clnt_ctxt *cctxt;
+	int is_secure = (flags & VCD_CP_SESSION) ? 1 : 0;
 	VCD_MSG_MED("vcd_open:");
 
 	if (!callback) {
 		VCD_MSG_ERROR("Bad parameters");
-
-		return VCD_ERR_ILLEGAL_PARM;
+		return -EINVAL;
 	}
-	if (res_trk_check_for_sec_session() && vcd_get_num_of_clients()) {
-		VCD_MSG_ERROR("Secure session in progress");
-		return VCD_ERR_BAD_STATE;
+	rc = is_session_invalid(decoding, flags);
+	if (rc) {
+			VCD_MSG_ERROR("Secure session in progress");
+			return rc;
 	}
 	drv_ctxt = vcd_get_drv_context();
 	mutex_lock(&drv_ctxt->dev_mutex);
@@ -100,17 +179,19 @@
 		rc = drv_ctxt->dev_state.state_table->ev_hdlr.
 		    open(drv_ctxt, driver_handle, decoding, callback,
 			    client_data);
+		if (rc)
+			rc = -ENODEV;
 	} else {
 		VCD_MSG_ERROR("Unsupported API in device state %d",
 			      drv_ctxt->dev_state.state);
-
-		rc = VCD_ERR_BAD_STATE;
+		rc = -EPERM;
 	}
-
+	if (!rc) {
+		cctxt = drv_ctxt->dev_ctxt.cctxt_list_head;
+		cctxt->secure = is_secure;
+	}
 	mutex_unlock(&drv_ctxt->dev_mutex);
-
 	return rc;
-
 }
 EXPORT_SYMBOL(vcd_open);
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index b8438e1..e33c8cd 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -210,6 +210,7 @@
 	struct vcd_clnt_ctxt *next;
 	u32 meta_mode;
 	int perf_set_by_client;
+	int secure;
 };
 
 #define VCD_BUFFERPOOL_INUSE_DECREMENT(val) \
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 20d3ef9..32a1759 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -116,11 +116,14 @@
 	void (*timer_stop) (void *timer_handle);
 };
 
+/*Flags passed to vcd_open*/
+#define VCD_CP_SESSION 0x00000001
+
 u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle);
 u32 vcd_term(s32 driver_handle);
 u32 vcd_open(s32 driver_handle, u32 decoding,
 	void (*callback) (u32 event, u32 status, void *info, size_t sz,
-	void *handle, void *const client_data), void *client_data);
+	void *handle, void *const client_data), void *client_data, int flags);
 u32 vcd_close(void *handle);
 u32 vcd_encode_start(void *handle);
 u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame);