crypto: msm: Add basic suspend resume functionality

If ce clock is not disabled in suspend state, memory may be corrupted
and device can not wake up. We add an optional flag "clk_mgmt_sus_res"
for qcrypto driver. This flag indicates if the ce clocks need to be
disabled in suspend function and enabled in resume function of qcrypto
driver. When the flag is set, we disable the clocks that are not disabled
in suspend function and re-enable them again in resume function.

Change-Id: I23be38b2765c0cc5f3ed41d65f8e4ae8a9372d18
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
This commit is contained in:
Zhen Kong 2013-12-18 12:51:42 -08:00
parent a18f488cdf
commit 00fa0d8c21
4 changed files with 102 additions and 0 deletions

View File

@ -22,6 +22,7 @@ Optional properties:
- qcom,use-sw-ahash-algo : optional, indicates if use SW hash algorithm.
- qcom,use-sw-hmac-algo : optional, indicates if use SW hmac algorithm.
- qcom,use-sw-aes-ccm-algo : optional, indicates if use SW aes-ccm algorithm.
- qcom,clk-mgmt-sus-res : optional, indicate if the ce clocks need to be disabled/enabled in suspend/resume function.
Example:

View File

@ -122,6 +122,7 @@ struct ce_hw_support {
bool use_sw_ahash_algo;
bool use_sw_hmac_algo;
bool use_sw_aes_ccm_algo;
bool clk_mgmt_sus_res;
};
/* Sha operation parameters */

View File

@ -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 */
@ -5086,6 +5087,8 @@ static int __qce_get_device_tree_data(struct platform_device *pdev,
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",
@ -5414,6 +5417,7 @@ 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

View File

@ -4092,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",
},
@ -4101,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",