aboutsummaryrefslogtreecommitdiff
path: root/drivers/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/msm/qce.h9
-rw-r--r--drivers/crypto/msm/qce50.c44
-rw-r--r--drivers/crypto/msm/qcedev.c2
-rw-r--r--drivers/crypto/msm/qcrypto.c180
4 files changed, 228 insertions, 7 deletions
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index afd51417fbe..73438d0af15 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -1,6 +1,6 @@
/* Qualcomm Crypto Engine driver API
*
- * 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
@@ -116,6 +116,13 @@ struct ce_hw_support {
bool bam;
bool is_shared;
bool hw_key;
+ bool use_sw_aes_cbc_ecb_ctr_algo;
+ bool use_sw_aead_algo;
+ bool use_sw_aes_xts_algo;
+ bool use_sw_ahash_algo;
+ bool use_sw_hmac_algo;
+ bool use_sw_aes_ccm_algo;
+ bool clk_mgmt_sus_res;
};
/* Sha operation parameters */
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 7295ddab2ac..92e6b28e10d 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -73,6 +73,7 @@ struct qce_device {
int is_shared; /* CE HW is shared */
bool support_cmd_dscr;
bool support_hw_key;
+ bool support_clk_mgmt_sus_res;
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
@@ -101,6 +102,13 @@ struct qce_device {
dma_addr_t phy_ota_src;
dma_addr_t phy_ota_dst;
unsigned int ota_size;
+
+ bool use_sw_aes_cbc_ecb_ctr_algo;
+ bool use_sw_aead_algo;
+ bool use_sw_aes_xts_algo;
+ bool use_sw_ahash_algo;
+ bool use_sw_hmac_algo;
+ bool use_sw_aes_ccm_algo;
};
/* Standard initialization vector for SHA-1, source: FIPS 180-2 */
@@ -5060,6 +5068,28 @@ static int __qce_get_device_tree_data(struct platform_device *pdev,
"qcom,ce-hw-shared");
pce_dev->support_hw_key = of_property_read_bool((&pdev->dev)->of_node,
"qcom,ce-hw-key");
+
+ pce_dev->use_sw_aes_cbc_ecb_ctr_algo =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-sw-aes-cbc-ecb-ctr-algo");
+ pce_dev->use_sw_aead_algo =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-sw-aead-algo");
+ pce_dev->use_sw_aes_xts_algo =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-sw-aes-xts-algo");
+ pce_dev->use_sw_ahash_algo =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-sw-ahash-algo");
+ pce_dev->use_sw_hmac_algo =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-sw-hmac-algo");
+ pce_dev->use_sw_aes_ccm_algo =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,use-sw-aes-ccm-algo");
+ pce_dev->support_clk_mgmt_sus_res = of_property_read_bool(
+ (&pdev->dev)->of_node, "qcom,clk-mgmt-sus-res");
+
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -5387,10 +5417,24 @@ int qce_hw_support(void *handle, struct ce_hw_support *ce_support)
ce_support->is_shared = (pce_dev->is_shared == 1) ? true : false;
ce_support->hw_key = pce_dev->support_hw_key;
ce_support->aes_ccm = true;
+ ce_support->clk_mgmt_sus_res = pce_dev->support_clk_mgmt_sus_res;
if (pce_dev->ce_sps.minor_version)
ce_support->aligned_only = false;
else
ce_support->aligned_only = true;
+
+ ce_support->use_sw_aes_cbc_ecb_ctr_algo =
+ pce_dev->use_sw_aes_cbc_ecb_ctr_algo;
+ ce_support->use_sw_aead_algo =
+ pce_dev->use_sw_aead_algo;
+ ce_support->use_sw_aes_xts_algo =
+ pce_dev->use_sw_aes_xts_algo;
+ ce_support->use_sw_ahash_algo =
+ pce_dev->use_sw_ahash_algo;
+ ce_support->use_sw_hmac_algo =
+ pce_dev->use_sw_hmac_algo;
+ ce_support->use_sw_aes_ccm_algo =
+ pce_dev->use_sw_aes_ccm_algo;
return 0;
}
EXPORT_SYMBOL(qce_hw_support);
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 4845f11b3fc..72dbff3398a 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
#include <linux/mman.h>
+#include <soc/qcom/scm.h>
#include <linux/types.h>
#include <linux/platform_device.h>
@@ -30,7 +31,6 @@
#include <linux/crypto.h>
#include <crypto/hash.h>
#include <linux/platform_data/qcom_crypto_device.h>
-#include <mach/scm.h>
#include <mach/msm_bus.h>
#include <linux/qcedev.h>
#include "qce.h"
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",