Commit d072bfa4 authored by Christian Lamparter's avatar Christian Lamparter Committed by Herbert Xu

crypto: crypto4xx - add prng crypto support

This patch adds support for crypto4xx's ANSI X9.17 Annex C compliant
pseudo random number generator which provides a pseudo random source
for the purpose of generating  Initialization Vectors (IV's) for AES
algorithms to the Packet Engine and other pseudo random number
requirements.
Signed-off-by: default avatarChristian Lamparter <chunkeey@gmail.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 12b8567f
...@@ -40,9 +40,11 @@ ...@@ -40,9 +40,11 @@
#include <crypto/ctr.h> #include <crypto/ctr.h>
#include <crypto/gcm.h> #include <crypto/gcm.h>
#include <crypto/sha.h> #include <crypto/sha.h>
#include <crypto/rng.h>
#include <crypto/scatterwalk.h> #include <crypto/scatterwalk.h>
#include <crypto/skcipher.h> #include <crypto/skcipher.h>
#include <crypto/internal/aead.h> #include <crypto/internal/aead.h>
#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h> #include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h" #include "crypto4xx_reg_def.h"
#include "crypto4xx_core.h" #include "crypto4xx_core.h"
...@@ -1035,6 +1037,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, ...@@ -1035,6 +1037,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
rc = crypto_register_ahash(&alg->alg.u.hash); rc = crypto_register_ahash(&alg->alg.u.hash);
break; break;
case CRYPTO_ALG_TYPE_RNG:
rc = crypto_register_rng(&alg->alg.u.rng);
break;
default: default:
rc = crypto_register_skcipher(&alg->alg.u.cipher); rc = crypto_register_skcipher(&alg->alg.u.cipher);
break; break;
...@@ -1064,6 +1070,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev) ...@@ -1064,6 +1070,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
crypto_unregister_aead(&alg->alg.u.aead); crypto_unregister_aead(&alg->alg.u.aead);
break; break;
case CRYPTO_ALG_TYPE_RNG:
crypto_unregister_rng(&alg->alg.u.rng);
break;
default: default:
crypto_unregister_skcipher(&alg->alg.u.cipher); crypto_unregister_skcipher(&alg->alg.u.cipher);
} }
...@@ -1122,6 +1132,69 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data) ...@@ -1122,6 +1132,69 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
PPC4XX_TMO_ERR_INT); PPC4XX_TMO_ERR_INT);
} }
static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
u8 *data, unsigned int max)
{
unsigned int i, curr = 0;
u32 val[2];
do {
/* trigger PRN generation */
writel(PPC4XX_PRNG_CTRL_AUTO_EN,
dev->ce_base + CRYPTO4XX_PRNG_CTRL);
for (i = 0; i < 1024; i++) {
/* usually 19 iterations are enough */
if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
CRYPTO4XX_PRNG_STAT_BUSY))
continue;
val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
break;
}
if (i == 1024)
return -ETIMEDOUT;
if ((max - curr) >= 8) {
memcpy(data, &val, 8);
data += 8;
curr += 8;
} else {
/* copy only remaining bytes */
memcpy(data, &val, max - curr);
break;
}
} while (curr < max);
return curr;
}
static int crypto4xx_prng_generate(struct crypto_rng *tfm,
const u8 *src, unsigned int slen,
u8 *dstn, unsigned int dlen)
{
struct rng_alg *alg = crypto_rng_alg(tfm);
struct crypto4xx_alg *amcc_alg;
struct crypto4xx_device *dev;
int ret;
amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
dev = amcc_alg->dev;
mutex_lock(&dev->core_dev->rng_lock);
ret = ppc4xx_prng_data_read(dev, dstn, dlen);
mutex_unlock(&dev->core_dev->rng_lock);
return ret;
}
static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
unsigned int slen)
{
return 0;
}
/** /**
* Supported Crypto Algorithms * Supported Crypto Algorithms
*/ */
...@@ -1291,6 +1364,18 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { ...@@ -1291,6 +1364,18 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_module = THIS_MODULE, .cra_module = THIS_MODULE,
}, },
} }, } },
{ .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
.base = {
.cra_name = "stdrng",
.cra_driver_name = "crypto4xx_rng",
.cra_priority = 300,
.cra_ctxsize = 0,
.cra_module = THIS_MODULE,
},
.generate = crypto4xx_prng_generate,
.seed = crypto4xx_prng_seed,
.seedsize = 0,
} },
}; };
/** /**
...@@ -1360,6 +1445,7 @@ static int crypto4xx_probe(struct platform_device *ofdev) ...@@ -1360,6 +1445,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
core_dev->dev->core_dev = core_dev; core_dev->dev->core_dev = core_dev;
core_dev->dev->is_revb = is_revb; core_dev->dev->is_revb = is_revb;
core_dev->device = dev; core_dev->device = dev;
mutex_init(&core_dev->rng_lock);
spin_lock_init(&core_dev->lock); spin_lock_init(&core_dev->lock);
INIT_LIST_HEAD(&core_dev->dev->alg_list); INIT_LIST_HEAD(&core_dev->dev->alg_list);
ratelimit_default_init(&core_dev->dev->aead_ratelimit); ratelimit_default_init(&core_dev->dev->aead_ratelimit);
...@@ -1439,6 +1525,7 @@ static int crypto4xx_remove(struct platform_device *ofdev) ...@@ -1439,6 +1525,7 @@ static int crypto4xx_remove(struct platform_device *ofdev)
tasklet_kill(&core_dev->tasklet); tasklet_kill(&core_dev->tasklet);
/* Un-register with Linux CryptoAPI */ /* Un-register with Linux CryptoAPI */
crypto4xx_unregister_alg(core_dev->dev); crypto4xx_unregister_alg(core_dev->dev);
mutex_destroy(&core_dev->rng_lock);
/* Free all allocated memory */ /* Free all allocated memory */
crypto4xx_stop_all(core_dev); crypto4xx_stop_all(core_dev);
......
...@@ -23,8 +23,10 @@ ...@@ -23,8 +23,10 @@
#define __CRYPTO4XX_CORE_H__ #define __CRYPTO4XX_CORE_H__
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/mutex.h>
#include <crypto/internal/hash.h> #include <crypto/internal/hash.h>
#include <crypto/internal/aead.h> #include <crypto/internal/aead.h>
#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h> #include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h" #include "crypto4xx_reg_def.h"
#include "crypto4xx_sa.h" #include "crypto4xx_sa.h"
...@@ -119,6 +121,7 @@ struct crypto4xx_core_device { ...@@ -119,6 +121,7 @@ struct crypto4xx_core_device {
u32 irq; u32 irq;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
spinlock_t lock; spinlock_t lock;
struct mutex rng_lock;
}; };
struct crypto4xx_ctx { struct crypto4xx_ctx {
...@@ -143,6 +146,7 @@ struct crypto4xx_alg_common { ...@@ -143,6 +146,7 @@ struct crypto4xx_alg_common {
struct skcipher_alg cipher; struct skcipher_alg cipher;
struct ahash_alg hash; struct ahash_alg hash;
struct aead_alg aead; struct aead_alg aead;
struct rng_alg rng;
} u; } u;
}; };
......
...@@ -100,6 +100,7 @@ ...@@ -100,6 +100,7 @@
#define CRYPTO4XX_ENDIAN_CFG 0x000600d8 #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
#define CRYPTO4XX_PRNG_STAT 0x00070000 #define CRYPTO4XX_PRNG_STAT 0x00070000
#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
#define CRYPTO4XX_PRNG_CTRL 0x00070004 #define CRYPTO4XX_PRNG_CTRL 0x00070004
#define CRYPTO4XX_PRNG_SEED_L 0x00070008 #define CRYPTO4XX_PRNG_SEED_L 0x00070008
#define CRYPTO4XX_PRNG_SEED_H 0x0007000c #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment