crypto: Fix race conditons and synchronization issues

- Fix locking mechanism: Add ref count for locking and
  protect ce lock reference count
- Fix race conditions with processing sha request.

Signed-off-by: Mona Hossain <mhossain@codeaurora.org>
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 18eff22..6515ae1 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -86,6 +86,8 @@
 	int					err;
 };
 
+static DEFINE_MUTEX(send_cmd_lock);
+
 /**********************************************************************
  * Register ourselves as a misc device to be able to access the dev driver
  * from userspace. */
@@ -98,8 +100,7 @@
 	/* CE features supported by platform */
 	struct msm_ce_hw_support platform_support;
 
-	bool ce_locked;
-
+	uint32_t ce_lock_count;
 	/* CE features/algorithms supported by HW engine*/
 	struct ce_hw_support ce_support;
 
@@ -151,24 +152,38 @@
 
 static int qcedev_unlock_ce(struct qcedev_control *podev)
 {
-	if ((podev->platform_support.ce_shared) && (podev->ce_locked == true)) {
+	int ret = 0;
+
+	mutex_lock(&send_cmd_lock);
+	if (podev->ce_lock_count == 1) {
 		int response = 0;
 
 		if (qcedev_scm_cmd(podev->platform_support.shared_ce_resource,
 					QCEDEV_CE_UNLOCK_CMD, &response)) {
-			printk(KERN_ERR "%s Failed to release CE lock\n",
-				__func__);
-			return -EUSERS;
+			pr_err("Failed to release CE lock\n");
+			ret = -EIO;
 		}
-		podev->ce_locked = false;
 	}
-	return 0;
+	if (ret == 0) {
+		if (podev->ce_lock_count)
+			podev->ce_lock_count--;
+		else {
+			/* We should never be here */
+			ret = -EIO;
+			pr_err("CE hardware is already unlocked\n");
+		}
+	}
+	mutex_unlock(&send_cmd_lock);
+
+	return ret;
 }
 
 static int qcedev_lock_ce(struct qcedev_control *podev)
 {
-	if ((podev->platform_support.ce_shared) &&
-					(podev->ce_locked == false)) {
+	int ret = 0;
+
+	mutex_lock(&send_cmd_lock);
+	if (podev->ce_lock_count == 0) {
 		int response = -CE_BUSY;
 		int i = 0;
 
@@ -181,15 +196,17 @@
 			}
 		} while ((response == -CE_BUSY) && (i++ < NUM_RETRY));
 
-		if ((response == -CE_BUSY) && (i >= NUM_RETRY))
-			return -EUSERS;
-		if (response < 0)
-			return -EINVAL;
-
-		podev->ce_locked = true;
+		if ((response == -CE_BUSY) && (i >= NUM_RETRY)) {
+			ret = -EUSERS;
+		} else {
+			if (response < 0)
+				ret = -EINVAL;
+		}
 	}
-
-	return 0;
+	if (ret == 0)
+		podev->ce_lock_count++;
+	mutex_unlock(&send_cmd_lock);
+	return ret;
 }
 
 #define QCEDEV_MAGIC 0x56434544 /* "qced" */
@@ -198,8 +215,7 @@
 static int qcedev_open(struct inode *inode, struct file *file);
 static int qcedev_release(struct inode *inode, struct file *file);
 static int start_cipher_req(struct qcedev_control *podev);
-static int start_sha_req(struct qcedev_control *podev,
-			struct qcedev_sha_op_req *sha_op_req);
+static int start_sha_req(struct qcedev_control *podev);
 
 static const struct file_operations qcedev_fops = {
 	.owner = THIS_MODULE,
@@ -219,7 +235,6 @@
 	},
 };
 
-
 #define MAX_QCE_DEVICE ARRAY_SIZE(qce_dev)
 #define DEBUG_MAX_FNAME  16
 #define DEBUG_MAX_RW_BUF 1024
@@ -303,7 +318,7 @@
 		if (new_req->op_type == QCEDEV_CRYPTO_OPER_CIPHER)
 			ret = start_cipher_req(podev);
 		else
-			ret = start_sha_req(podev, &areq->sha_op_req);
+			ret = start_sha_req(podev);
 	}
 
 	spin_unlock_irqrestore(&podev->lock, flags);
@@ -470,8 +485,7 @@
 	return ret;
 };
 
-static int start_sha_req(struct qcedev_control *podev,
-			struct qcedev_sha_op_req *sha_op_req)
+static int start_sha_req(struct qcedev_control *podev)
 {
 	struct qcedev_async_req *qcedev_areq;
 	struct qce_sha_req sreq;
@@ -523,19 +537,19 @@
 
 	sreq.qce_cb = qcedev_sha_req_cb;
 	if (qcedev_areq->sha_op_req.alg != QCEDEV_ALG_AES_CMAC) {
-		sreq.auth_data[0] = sha_op_req->ctxt.auth_data[0];
-		sreq.auth_data[1] = sha_op_req->ctxt.auth_data[1];
-		sreq.auth_data[2] = sha_op_req->ctxt.auth_data[2];
-		sreq.auth_data[3] = sha_op_req->ctxt.auth_data[3];
-		sreq.digest = &sha_op_req->ctxt.digest[0];
-		sreq.first_blk = sha_op_req->ctxt.first_blk;
-		sreq.last_blk = sha_op_req->ctxt.last_blk;
+		sreq.auth_data[0] = qcedev_areq->sha_op_req.ctxt.auth_data[0];
+		sreq.auth_data[1] = qcedev_areq->sha_op_req.ctxt.auth_data[1];
+		sreq.auth_data[2] = qcedev_areq->sha_op_req.ctxt.auth_data[2];
+		sreq.auth_data[3] = qcedev_areq->sha_op_req.ctxt.auth_data[3];
+		sreq.digest = &qcedev_areq->sha_op_req.ctxt.digest[0];
+		sreq.first_blk = qcedev_areq->sha_op_req.ctxt.first_blk;
+		sreq.last_blk = qcedev_areq->sha_op_req.ctxt.last_blk;
 	}
 	sreq.size = qcedev_areq->sha_req.sreq.nbytes;
 	sreq.src = qcedev_areq->sha_req.sreq.src;
 	sreq.areq = (void *)&qcedev_areq->sha_req;
 	qcedev_areq->sha_req.sha_ctxt =
-		(struct qcedev_sha_ctxt *)(&sha_op_req->ctxt);
+		(struct qcedev_sha_ctxt *)(&qcedev_areq->sha_op_req.ctxt);
 
 	ret = qce_process_sha_req(podev->qce, &sreq);
 
@@ -555,9 +569,11 @@
 
 	qcedev_areq->err = 0;
 
-	ret = qcedev_lock_ce(podev);
-	if (ret)
-		return ret;
+	if (podev->platform_support.ce_shared) {
+		ret = qcedev_lock_ce(podev);
+		if (ret)
+			return ret;
+	}
 
 	spin_lock_irqsave(&podev->lock, flags);
 
@@ -566,7 +582,7 @@
 		if (qcedev_areq->op_type == QCEDEV_CRYPTO_OPER_CIPHER)
 			ret = start_cipher_req(podev);
 		else
-			ret = start_sha_req(podev, &qcedev_areq->sha_op_req);
+			ret = start_sha_req(podev);
 	} else {
 		list_add_tail(&qcedev_areq->list, &podev->ready_commands);
 	}
@@ -579,9 +595,11 @@
 	if (ret == 0)
 		wait_for_completion(&qcedev_areq->complete);
 
-	ret = qcedev_unlock_ce(podev);
+	if (podev->platform_support.ce_shared)
+		ret = qcedev_unlock_ce(podev);
+
 	if (ret)
-			qcedev_areq->err = -EIO;
+		qcedev_areq->err = -EIO;
 
 	pstat = &_qcedev_stat[podev->pdev->id];
 	if (qcedev_areq->op_type == QCEDEV_CRYPTO_OPER_CIPHER) {
@@ -906,6 +924,8 @@
 	qcedev_areq->sha_op_req.ctxt.last_blk = 0;
 	qcedev_areq->sha_op_req.ctxt.auth_data[0] = 0;
 	qcedev_areq->sha_op_req.ctxt.auth_data[1] = 0;
+	qcedev_areq->sha_op_req.ctxt.auth_data[2] = 0;
+	qcedev_areq->sha_op_req.ctxt.auth_data[3] = 0;
 	qcedev_areq->sha_op_req.ctxt.trailing_buf_len = 0;
 	memset(&qcedev_areq->sha_op_req.ctxt.trailing_buf[0], 0, 64);
 
@@ -1746,10 +1766,16 @@
 
 	switch (cmd) {
 	case QCEDEV_IOCTL_LOCK_CE:
-		err = qcedev_lock_ce(podev);
+		if (podev->platform_support.ce_shared)
+			err = qcedev_lock_ce(podev);
+		else
+			err = -ENOTTY;
 		break;
 	case QCEDEV_IOCTL_UNLOCK_CE:
-		err = qcedev_unlock_ce(podev);
+		if (podev->platform_support.ce_shared)
+			err = qcedev_unlock_ce(podev);
+		else
+			err = -ENOTTY;
 		break;
 	case QCEDEV_IOCTL_ENC_REQ:
 	case QCEDEV_IOCTL_DEC_REQ:
@@ -1916,7 +1942,7 @@
 				platform_support->shared_ce_resource;
 	podev->platform_support.hw_key_support =
 				platform_support->hw_key_support;
-	podev->ce_locked = false;
+	podev->ce_lock_count = 0;
 
 	INIT_LIST_HEAD(&podev->ready_commands);
 	podev->active_command = NULL;
@@ -2089,7 +2115,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.20");
+MODULE_VERSION("1.21");
 
 module_init(qcedev_init);
 module_exit(qcedev_exit);