diff options
Diffstat (limited to 'drivers/crypto')
| -rw-r--r-- | drivers/crypto/msm/qce.h | 9 | ||||
| -rw-r--r-- | drivers/crypto/msm/qce50.c | 44 | ||||
| -rw-r--r-- | drivers/crypto/msm/qcedev.c | 2 | ||||
| -rw-r--r-- | drivers/crypto/msm/qcrypto.c | 180 |
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", |
