summaryrefslogtreecommitdiff
path: root/drivers/crypto
diff options
context:
space:
mode:
authorShravani Dingari <shravanid@nvidia.com>2013-07-09 12:33:19 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:32:11 -0700
commitc5c309d7e762c90f428d0b77ac3fe517e37b1c59 (patch)
tree5239758d726f198e65d6373002a8f20d9670be3e /drivers/crypto
parent722c530ee6f4ac9ee3891b7cf5fbb606e23456fe (diff)
ARM: tegra: Call tegra_se_suspend to save SE context
Call tegra_se_suspend() again, immediately after returning from tegra_suspend_dram(), during LP0 exit. To call se_suspend(), tegra_smmu_resume() also needs to be called. This is an attempt to regenerate SRK and SE context, so that BootROM won't kill SE on LP0 exit ( if we try to re-enter LP0 early without waking to active). Bug 1234330 Change-Id: Ib71e0c9972f307e48395b8f16d79867ad95659a0 Signed-off-by: Shravani Dingari <shravanid@nvidia.com> Reviewed-on: http://git-master/r/243462 (cherry picked from commit 155aef2ee1ce6cf0481f8419809024f3e4e7c0e9) Reviewed-on: http://git-master/r/250052 Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/tegra-se.c111
-rw-r--r--drivers/crypto/tegra-se.h6
2 files changed, 90 insertions, 27 deletions
diff --git a/drivers/crypto/tegra-se.c b/drivers/crypto/tegra-se.c
index fae31f308bd8..fe58909f7b9a 100644
--- a/drivers/crypto/tegra-se.c
+++ b/drivers/crypto/tegra-se.c
@@ -48,6 +48,8 @@
#define DRIVER_NAME "tegra-se"
+static struct device *save_se_device;
+
/* Security Engine operation modes */
enum tegra_se_aes_op_mode {
SE_AES_OP_MODE_CBC, /* Cipher Block Chaining (CBC) mode */
@@ -114,6 +116,7 @@ struct tegra_se_dev {
dma_addr_t ctx_save_buf_adr; /* LP context buffer dma address*/
struct completion complete; /* Tells the task completion */
bool work_q_busy; /* Work queue busy status */
+ bool polling;
struct tegra_se_chipdata *chipdata; /* chip specific data */
};
@@ -652,7 +655,7 @@ static int tegra_se_start_operation(struct tegra_se_dev *se_dev, u32 nbytes,
bool context_save)
{
u32 nblocks = nbytes / TEGRA_SE_AES_BLOCK_SIZE;
- int ret = 0;
+ int ret = 0, err = 0;
u32 val = 0;
if ((tegra_get_chipid() == TEGRA_CHIPID_TEGRA11) &&
@@ -672,11 +675,13 @@ static int tegra_se_start_operation(struct tegra_se_dev *se_dev, u32 nbytes,
if (nblocks)
se_writel(se_dev, nblocks-1, SE_BLOCK_COUNT_REG_OFFSET);
- /* enable interupts */
- val = SE_INT_ERROR(INT_ENABLE) | SE_INT_OP_DONE(INT_ENABLE);
- se_writel(se_dev, val, SE_INT_ENABLE_REG_OFFSET);
+ if (!se_dev->polling) {
+ /* enable interupts */
+ val = SE_INT_ERROR(INT_ENABLE) | SE_INT_OP_DONE(INT_ENABLE);
+ se_writel(se_dev, val, SE_INT_ENABLE_REG_OFFSET);
- INIT_COMPLETION(se_dev->complete);
+ INIT_COMPLETION(se_dev->complete);
+ }
if (context_save)
se_writel(se_dev, SE_OPERATION(OP_CTX_SAVE),
@@ -685,19 +690,30 @@ static int tegra_se_start_operation(struct tegra_se_dev *se_dev, u32 nbytes,
se_writel(se_dev, SE_OPERATION(OP_SRART),
SE_OPERATION_REG_OFFSET);
- ret = wait_for_completion_timeout(&se_dev->complete,
- msecs_to_jiffies(1000));
+ if (se_dev->polling) {
+ /* polling */
+ val = se_readl(se_dev, SE_INT_STATUS_REG_OFFSET);
+ while (!SE_OP_DONE(val, OP_DONE))
+ val = se_readl(se_dev, SE_INT_STATUS_REG_OFFSET);
+
+ if (!SE_OP_DONE(val, OP_DONE)) {
+ dev_err(se_dev->dev, "\nAbrupt end of operation\n");
+ err = -EINVAL;
+ }
+ } else {
+ ret = wait_for_completion_timeout(&se_dev->complete,
+ msecs_to_jiffies(1000));
+ if (ret == 0) {
+ dev_err(se_dev->dev, "operation timed out no interrupt\n");
+ err = -ETIMEDOUT;
+ }
+ }
dma_sync_single_for_cpu(se_dev->dev, se_dev->src_ll_buf_adr,
nbytes, DMA_FROM_DEVICE);
dma_sync_single_for_cpu(se_dev->dev, se_dev->dst_ll_buf_adr,
nbytes, DMA_FROM_DEVICE);
- if (ret == 0) {
- dev_err(se_dev->dev, "operation timed out no interrupt\n");
- return -ETIMEDOUT;
- }
-
- return 0;
+ return err;
}
static void tegra_se_read_hash_result(struct tegra_se_dev *se_dev,
@@ -3157,26 +3173,50 @@ static int tegra_se_save_SRK(struct tegra_se_dev *se_dev)
val = se_readl(se_dev, SE_INT_STATUS_REG_OFFSET);
se_writel(se_dev, val, SE_INT_STATUS_REG_OFFSET);
- /* enable interupts */
- val = SE_INT_ERROR(INT_ENABLE) | SE_INT_OP_DONE(INT_ENABLE);
- se_writel(se_dev, val, SE_INT_ENABLE_REG_OFFSET);
+ if (!se_dev->polling) {
+ /* enable interupts */
+ val = SE_INT_ERROR(INT_ENABLE)
+ | SE_INT_OP_DONE(INT_ENABLE);
+ se_writel(se_dev, val, SE_INT_ENABLE_REG_OFFSET);
+
+ INIT_COMPLETION(se_dev->complete);
+ }
val = SE_CONFIG_ENC_ALG(ALG_NOP) |
SE_CONFIG_DEC_ALG(ALG_NOP);
se_writel(se_dev, val, SE_CRYPTO_REG_OFFSET);
- INIT_COMPLETION(se_dev->complete);
-
se_writel(se_dev, SE_OPERATION(OP_CTX_SAVE),
SE_OPERATION_REG_OFFSET);
- ret = wait_for_completion_timeout(&se_dev->complete,
- msecs_to_jiffies(1000));
- if (ret == 0) {
- dev_err(se_dev->dev, "\n LP SRK timed out no interrupt\n");
- pm_runtime_put(se_dev->dev);
- mutex_unlock(&se_hw_lock);
- return -ETIMEDOUT;
+ if (se_dev->polling) {
+ /*polling*/
+ val = se_readl(se_dev, SE_INT_STATUS_REG_OFFSET);
+ while (!SE_OP_DONE(val, OP_DONE))
+ val = se_readl(se_dev,
+ SE_INT_STATUS_REG_OFFSET);
+
+ if (SE_OP_DONE(val, OP_DONE)) {
+ pm_runtime_put(se_dev->dev);
+ mutex_unlock(&se_hw_lock);
+ return 0;
+ } else {
+ dev_err(se_dev->dev,
+ "\nAbrupt end of operation\n");
+ pm_runtime_put(se_dev->dev);
+ mutex_unlock(&se_hw_lock);
+ return -EINVAL;
+ }
+ } else {
+ ret = wait_for_completion_timeout(&se_dev->complete,
+ msecs_to_jiffies(1000));
+ if (ret == 0) {
+ dev_err(se_dev->dev,
+ "\n LP SRK timed out no interrupt\n");
+ pm_runtime_put(se_dev->dev);
+ mutex_unlock(&se_hw_lock);
+ return -ETIMEDOUT;
+ }
}
}
@@ -3186,7 +3226,7 @@ static int tegra_se_save_SRK(struct tegra_se_dev *se_dev)
return 0;
}
-static int tegra_se_suspend(struct device *dev)
+int se_suspend(struct device *dev, bool polling)
{
struct platform_device *pdev = to_platform_device(dev);
struct tegra_se_dev *se_dev = platform_get_drvdata(pdev);
@@ -3199,6 +3239,10 @@ static int tegra_se_suspend(struct device *dev)
if (!se_dev)
return -ENODEV;
+ save_se_device = dev;
+
+ se_dev->polling = polling;
+
/* Generate SRK */
err = tegra_se_generate_srk(se_dev);
if (err) {
@@ -3306,6 +3350,21 @@ out:
pm_runtime_put_sync(dev);
return err;
}
+EXPORT_SYMBOL(se_suspend);
+
+struct device *get_se_device(void)
+{
+ return save_se_device;
+}
+EXPORT_SYMBOL(get_se_device);
+
+static int tegra_se_suspend(struct device *dev)
+{
+ int ret = 0;
+ ret = se_suspend(dev, false);
+
+ return ret;
+}
static int tegra_se_resume(struct device *dev)
{
diff --git a/drivers/crypto/tegra-se.h b/drivers/crypto/tegra-se.h
index 28723a0500f3..d96d1f194f29 100644
--- a/drivers/crypto/tegra-se.h
+++ b/drivers/crypto/tegra-se.h
@@ -1,7 +1,7 @@
/*
* Driver for Tegra Security Engine
*
- * Copyright (c) 2011-2013, NVIDIA Corporation.
+ * Copyright (c) 2011-2013, NVIDIA Corporation. 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 as published by
@@ -113,6 +113,10 @@
#define SE_KEYTABLE_PKT_SHIFT 0
#define SE_KEYTABLE_PKT(x) (x << SE_KEYTABLE_PKT_SHIFT)
+#define SE_OP_DONE_SHIFT 4
+#define OP_DONE 1
+#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
+
#define SE_CRYPTO_REG_OFFSET 0x304
#define SE_CRYPTO_HASH_SHIFT 0
#define HASH_DISABLE 0