]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
ARM: tegra: Call tegra_se_suspend to save SE context
authorShravani Dingari <shravanid@nvidia.com>
Tue, 9 Jul 2013 07:03:19 +0000 (12:33 +0530)
committervenkata jagadish <vjagadish@nvidia.com>
Thu, 22 Sep 2016 05:20:18 +0000 (10:50 +0530)
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>
drivers/crypto/tegra-se.c
drivers/crypto/tegra-se.h

index 5530707827978f442a2468b811c3c1ba3046394f..743f74a6c4c91119de5ea783dfd31fac417688fc 100644 (file)
@@ -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);
 
-       reinit_completion(&se_dev->complete);
+               reinit_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);
+
+                       reinit_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);
 
-               reinit_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)
 {
index 28723a0500f3f4b575ef60b1681e1367a19539f3..d96d1f194f299d4f88169cef89319427a1958ea9 100644 (file)
@@ -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
 #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