summaryrefslogtreecommitdiffstats
path: root/drivers/crypto/sunxi-ss/sun4i-ss-prng.c
diff options
context:
space:
mode:
authorCorentin LABBE <clabbe.montjoie@gmail.com>2017-07-03 20:48:48 +0200
committerHerbert Xu <herbert@gondor.apana.org.au>2017-07-18 17:50:55 +0800
commitb8ae5c7387ad075ee61e8c8774ce2bca46bc9236 (patch)
treec200c113a4691166b83f41a85d75e6d3e67ac5ec /drivers/crypto/sunxi-ss/sun4i-ss-prng.c
parent3822c331c5be580d8f9f65bdd6c0c187e0c5b503 (diff)
downloadlinux-stable-b8ae5c7387ad075ee61e8c8774ce2bca46bc9236.tar.gz
linux-stable-b8ae5c7387ad075ee61e8c8774ce2bca46bc9236.tar.bz2
linux-stable-b8ae5c7387ad075ee61e8c8774ce2bca46bc9236.zip
crypto: sun4i-ss - support the Security System PRNG
The Security System has a PRNG, this patch adds support for it via crypto_rng. Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/sunxi-ss/sun4i-ss-prng.c')
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-prng.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c
new file mode 100644
index 000000000000..0d01d1624252
--- /dev/null
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c
@@ -0,0 +1,56 @@
+#include "sun4i-ss.h"
+
+int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+ unsigned int slen)
+{
+ struct sun4i_ss_alg_template *algt;
+ struct rng_alg *alg = crypto_rng_alg(tfm);
+
+ algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+ memcpy(algt->ss->seed, seed, slen);
+
+ return 0;
+}
+
+int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int dlen)
+{
+ struct sun4i_ss_alg_template *algt;
+ struct rng_alg *alg = crypto_rng_alg(tfm);
+ int i;
+ u32 v;
+ u32 *data = (u32 *)dst;
+ const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+ size_t len;
+ struct sun4i_ss_ctx *ss;
+ unsigned int todo = (dlen / 4) * 4;
+
+ algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+ ss = algt->ss;
+
+ spin_lock(&ss->slock);
+
+ writel(mode, ss->base + SS_CTL);
+
+ while (todo > 0) {
+ /* write the seed */
+ for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+ writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+
+ /* Read the random data */
+ len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+ readsl(ss->base + SS_TXFIFO, data, len / 4);
+ data += len / 4;
+ todo -= len;
+
+ /* Update the seed */
+ for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+ v = readl(ss->base + SS_KEY0 + i * 4);
+ ss->seed[i] = v;
+ }
+ }
+
+ writel(0, ss->base + SS_CTL);
+ spin_unlock(&ss->slock);
+ return dlen;
+}