aboutsummaryrefslogtreecommitdiff
path: root/drivers/crypto/msm/qcrypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/msm/qcrypto.c')
-rw-r--r--drivers/crypto/msm/qcrypto.c180
1 files changed, 175 insertions, 5 deletions
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index cb07ca58c1e..da9a9f3d41b 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1,6 +1,6 @@
/* Qualcomm Crypto driver
*
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cache.h>
+#include <soc/qcom/scm.h>
#include <crypto/ctr.h>
#include <crypto/des.h>
@@ -40,7 +41,6 @@
#include <crypto/scatterwalk.h>
#include <crypto/internal/hash.h>
-#include <mach/scm.h>
#include <linux/platform_data/qcom_crypto_device.h>
#include <mach/msm_bus.h>
#include <mach/qcrypto.h>
@@ -3237,6 +3237,16 @@ static int _sha256_hmac_digest(struct ahash_request *req)
return _sha_digest(req);
}
+static int _qcrypto_prefix_alg_cra_name(char cra_name[], unsigned int size)
+{
+ char new_cra_name[CRYPTO_MAX_ALG_NAME] = "qcom-";
+ if (CRYPTO_MAX_ALG_NAME < size + 5)
+ return -EINVAL;
+ strlcat(new_cra_name, cra_name, CRYPTO_MAX_ALG_NAME);
+ strlcpy(cra_name, new_cra_name, CRYPTO_MAX_ALG_NAME);
+ return 0;
+}
+
int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags)
{
struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
@@ -3868,6 +3878,17 @@ static int _qcrypto_probe(struct platform_device *pdev)
rc = PTR_ERR(q_alg);
goto err;
}
+ if (cp->ce_support.use_sw_aes_cbc_ecb_ctr_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ goto err;
+ }
+ }
rc = crypto_register_alg(&q_alg->cipher_alg);
if (rc) {
dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3890,6 +3911,17 @@ static int _qcrypto_probe(struct platform_device *pdev)
rc = PTR_ERR(q_alg);
goto err;
}
+ if (cp->ce_support.use_sw_aes_xts_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ goto err;
+ }
+ }
rc = crypto_register_alg(&q_alg->cipher_alg);
if (rc) {
dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3915,7 +3947,17 @@ static int _qcrypto_probe(struct platform_device *pdev)
rc = PTR_ERR(q_alg);
goto err;
}
-
+ if (cp->ce_support.use_sw_ahash_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->sha_alg.halg.base.cra_name,
+ strlen(q_alg->sha_alg.halg.base.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->sha_alg.halg.base.cra_name);
+ goto err;
+ }
+ }
rc = crypto_register_ahash(&q_alg->sha_alg);
if (rc) {
dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3941,7 +3983,17 @@ static int _qcrypto_probe(struct platform_device *pdev)
rc = PTR_ERR(q_alg);
goto err;
}
-
+ if (cp->ce_support.use_sw_aead_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ goto err;
+ }
+ }
rc = crypto_register_alg(&q_alg->cipher_alg);
if (rc) {
dev_err(&pdev->dev,
@@ -3968,7 +4020,18 @@ static int _qcrypto_probe(struct platform_device *pdev)
rc = PTR_ERR(q_alg);
goto err;
}
-
+ if (cp->ce_support.use_sw_hmac_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->sha_alg.halg.base.cra_name,
+ strlen(
+ q_alg->sha_alg.halg.base.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->sha_alg.halg.base.cra_name);
+ goto err;
+ }
+ }
rc = crypto_register_ahash(&q_alg->sha_alg);
if (rc) {
dev_err(&pdev->dev,
@@ -3994,6 +4057,17 @@ static int _qcrypto_probe(struct platform_device *pdev)
rc = PTR_ERR(q_alg);
goto err;
}
+ if (cp->ce_support.use_sw_aes_ccm_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ goto err;
+ }
+ }
rc = crypto_register_alg(&q_alg->cipher_alg);
if (rc) {
dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -4018,6 +4092,100 @@ err:
};
+static int _qcrypto_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret = 0;
+ struct crypto_engine *pengine;
+ struct crypto_priv *cp;
+
+ pengine = platform_get_drvdata(pdev);
+ if (!pengine)
+ return -EINVAL;
+
+ /*
+ * Check if this platform supports clock management in suspend/resume
+ * If not, just simply return 0.
+ */
+ cp = pengine->pcp;
+ if (!cp->ce_support.clk_mgmt_sus_res)
+ return 0;
+
+ mutex_lock(&cp->engine_lock);
+
+ if (pengine->high_bw_req) {
+ del_timer_sync(&(pengine->bw_scale_down_timer));
+ ret = msm_bus_scale_client_update_request(
+ pengine->bus_scale_handle, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "%s Unable to set to low bandwidth\n",
+ __func__);
+ mutex_unlock(&cp->engine_lock);
+ return ret;
+ }
+ ret = qce_disable_clk(pengine->qce);
+ if (ret) {
+ pr_err("%s Unable disable clk\n", __func__);
+ ret = msm_bus_scale_client_update_request(
+ pengine->bus_scale_handle, 1);
+ if (ret)
+ dev_err(&pdev->dev,
+ "%s Unable to set to high bandwidth\n",
+ __func__);
+ mutex_unlock(&cp->engine_lock);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&cp->engine_lock);
+ return 0;
+}
+
+static int _qcrypto_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct crypto_engine *pengine;
+ struct crypto_priv *cp;
+
+ pengine = platform_get_drvdata(pdev);
+
+ if (!pengine)
+ return -EINVAL;
+
+ cp = pengine->pcp;
+ if (!cp->ce_support.clk_mgmt_sus_res)
+ return 0;
+
+ mutex_lock(&cp->engine_lock);
+ if (pengine->high_bw_req) {
+ ret = qce_enable_clk(pengine->qce);
+ if (ret) {
+ dev_err(&pdev->dev, "%s Unable to enable clk\n",
+ __func__);
+ mutex_unlock(&cp->engine_lock);
+ return ret;
+ }
+ ret = msm_bus_scale_client_update_request(
+ pengine->bus_scale_handle, 1);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s Unable to set to high bandwidth\n",
+ __func__);
+ qce_disable_clk(pengine->qce);
+ mutex_unlock(&cp->engine_lock);
+ return ret;
+ }
+ pengine->bw_scale_down_timer.data =
+ (unsigned long)(pengine);
+ pengine->bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(QCRYPTO_HIGH_BANDWIDTH_TIMEOUT);
+ add_timer(&(pengine->bw_scale_down_timer));
+ }
+
+ mutex_unlock(&cp->engine_lock);
+
+ return 0;
+}
+
static struct of_device_id qcrypto_match[] = {
{ .compatible = "qcom,qcrypto",
},
@@ -4027,6 +4195,8 @@ static struct of_device_id qcrypto_match[] = {
static struct platform_driver _qualcomm_crypto = {
.probe = _qcrypto_probe,
.remove = _qcrypto_remove,
+ .suspend = _qcrypto_suspend,
+ .resume = _qcrypto_resume,
.driver = {
.owner = THIS_MODULE,
.name = "qcrypto",