summaryrefslogtreecommitdiff
path: root/drivers/crypto
diff options
context:
space:
mode:
authorKasoju Mallikarjun <mkasoju@nvidia.com>2011-08-09 18:02:28 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:10 -0800
commit26bbc5c58481c3854a9fcd9f96165f08a15f3dba (patch)
tree9a9db0f5a90a57df74fc2506472d8e2479b30d02 /drivers/crypto
parentdd314ff51c70b038107202a4030621114283fa60 (diff)
crypto: tegra-se: RNG support for more than 16 bytes
Added support for generating RNG for more than 16 bytes. Bug 861777 Original-Change-Id: I414063378c1b7c31c9ef2ade950adcaa4e7db388 Reviewed-on: http://git-master/r/46066 Tested-by: Mallikarjun Kasoju <mkasoju@nvidia.com> Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com> Rebase-Id: Ra4ff01903b00f98b317606be3ffdfef58668aa92
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/tegra-se.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/crypto/tegra-se.c b/drivers/crypto/tegra-se.c
index d4df3569f87c..658b89cd5bd6 100644
--- a/drivers/crypto/tegra-se.c
+++ b/drivers/crypto/tegra-se.c
@@ -82,6 +82,7 @@ struct tegra_se_dev {
struct clk *pclk; /* Security Engine clock */
struct crypto_queue queue; /* Security Engine crypto queue */
struct tegra_se_slot *slot_list; /* pointer to key slots */
+ u64 ctr;
u32 *src_ll_buf; /* pointer to source linked list buffer */
dma_addr_t src_ll_buf_adr; /* Source linked list buffer dma address */
u32 src_ll_size; /* Size of source linked list buffer */
@@ -184,6 +185,8 @@ static void tegra_se_leftshift_onebit(u8 *in_buf, u32 size, u8 *org_msb)
}
}
+extern unsigned long long tegra_chip_uid(void);
+
static inline void se_writel(struct tegra_se_dev *se_dev,
unsigned int val, unsigned int reg_offset)
{
@@ -1049,10 +1052,12 @@ static int tegra_se_rng_get_random(struct crypto_rng *tfm, u8 *rdata, u32 dlen)
struct tegra_se_dev *se_dev = rng_ctx->se_dev;
struct tegra_se_ll *src_ll, *dst_ll;
unsigned char *dt_buf = (unsigned char *)rng_ctx->dt_buf;
- int ret = 0, i;
+ u8 *rdata_addr;
+ int ret = 0, i, j, num_blocks;
- if (dlen > TEGRA_SE_RNG_DT_SIZE)
+ if (dlen < TEGRA_SE_RNG_DT_SIZE)
return -EINVAL;
+ num_blocks = (dlen / TEGRA_SE_RNG_DT_SIZE);
/* take access to the hw */
mutex_lock(&se_hw_lock);
@@ -1063,28 +1068,39 @@ static int tegra_se_rng_get_random(struct crypto_rng *tfm, u8 *rdata, u32 dlen)
src_ll = (struct tegra_se_ll *)(se_dev->src_ll_buf + 1);
dst_ll = (struct tegra_se_ll *)(se_dev->dst_ll_buf + 1);
src_ll->addr = rng_ctx->dt_buf_adr;
- src_ll->data_len = dlen;
+ src_ll->data_len = TEGRA_SE_RNG_DT_SIZE;
dst_ll->addr = rng_ctx->rng_buf_adr;
- dst_ll->data_len = dlen;
+ dst_ll->data_len = TEGRA_SE_RNG_DT_SIZE;
tegra_se_config_algo(se_dev, SE_AES_OP_MODE_RNG_X931, true,
TEGRA_SE_KEY_128_SIZE);
tegra_se_config_crypto(se_dev, SE_AES_OP_MODE_RNG_X931, true,
rng_ctx->slot->slot_num, rng_ctx->use_org_iv);
- ret = tegra_se_start_operation(se_dev, dlen, false);
-
- if (!ret) {
- memcpy(rdata, rng_ctx->rng_buf, dlen);
- /* update DT vector */
- for (i = TEGRA_SE_RNG_DT_SIZE - 1; i >= 0; i--) {
- dt_buf[i] += 1;
- if (dt_buf[i] != 0)
- break;
+ for (j = 0; j < num_blocks; j++) {
+ ret = tegra_se_start_operation(se_dev,
+ TEGRA_SE_RNG_DT_SIZE, false);
+
+ if (!ret) {
+ rdata_addr = (rdata + (j * TEGRA_SE_RNG_DT_SIZE));
+ memcpy(rdata_addr,
+ rng_ctx->rng_buf, TEGRA_SE_RNG_DT_SIZE);
+
+ /* update DT vector */
+ for (i = TEGRA_SE_RNG_DT_SIZE - 1; i >= 0; i--) {
+ dt_buf[i] += 1;
+ if (dt_buf[i] != 0)
+ break;
+ }
+ } else {
+ dlen = 0;
+ }
+ if (rng_ctx->use_org_iv) {
+ rng_ctx->use_org_iv = false;
+ tegra_se_config_crypto(se_dev,
+ SE_AES_OP_MODE_RNG_X931, true,
+ rng_ctx->slot->slot_num, rng_ctx->use_org_iv);
}
- } else {
- dlen = 0;
}
- rng_ctx->use_org_iv = false;
tegra_se_clk_disable(se_dev->pclk);
mutex_unlock(&se_hw_lock);
@@ -1099,12 +1115,11 @@ static int tegra_se_rng_reset(struct crypto_rng *tfm, u8 *seed, u32 slen)
u8 *iv = seed;
u8 *key = (u8 *)(seed + TEGRA_SE_RNG_IV_SIZE);
u8 *dt = key + TEGRA_SE_RNG_KEY_SIZE;
+ struct timespec ts;
+ u64 nsec, tmp[2];
BUG_ON(!seed);
- if (slen < TEGRA_SE_RNG_SEED_SIZE)
- return -EINVAL;
-
/* take access to the hw */
mutex_lock(&se_hw_lock);
tegra_se_clk_enable(se_dev->pclk);
@@ -1118,7 +1133,19 @@ static int tegra_se_rng_reset(struct crypto_rng *tfm, u8 *seed, u32 slen)
tegra_se_clk_disable(se_dev->pclk);
mutex_unlock(&se_hw_lock);
- memcpy(rng_ctx->dt_buf, dt, TEGRA_SE_RNG_DT_SIZE);
+ if (slen < TEGRA_SE_RNG_SEED_SIZE) {
+ getnstimeofday(&ts);
+ nsec = timespec_to_ns(&ts);
+ do_div(nsec, 1000);
+ nsec ^= se_dev->ctr << 56;
+ se_dev->ctr++;
+ tmp[0] = nsec;
+ tmp[1] = tegra_chip_uid();
+ memcpy(rng_ctx->dt_buf, (u8 *)tmp, TEGRA_SE_RNG_DT_SIZE);
+ } else {
+ memcpy(rng_ctx->dt_buf, dt, TEGRA_SE_RNG_DT_SIZE);
+ }
+
rng_ctx->use_org_iv = true;
return 0;