]> git.itanic.dy.fi Git - linux-stable/commitdiff
crypto: crypto4xx - add prng crypto support
authorChristian Lamparter <chunkeey@gmail.com>
Sun, 23 Dec 2018 01:16:13 +0000 (02:16 +0100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 11 Jan 2019 06:16:56 +0000 (14:16 +0800)
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: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/amcc/crypto4xx_core.c
drivers/crypto/amcc/crypto4xx_core.h
drivers/crypto/amcc/crypto4xx_reg_def.h

index 63cb6956c948b758e6481c520b0ad8f592884459..f869e8cc4e0b7b24842c0c2d20fafff237095af3 100644 (file)
 #include <crypto/ctr.h>
 #include <crypto/gcm.h>
 #include <crypto/sha.h>
+#include <crypto/rng.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/skcipher.h>
 #include <crypto/internal/aead.h>
+#include <crypto/internal/rng.h>
 #include <crypto/internal/skcipher.h>
 #include "crypto4xx_reg_def.h"
 #include "crypto4xx_core.h"
@@ -1035,6 +1037,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
                        rc = crypto_register_ahash(&alg->alg.u.hash);
                        break;
 
+               case CRYPTO_ALG_TYPE_RNG:
+                       rc = crypto_register_rng(&alg->alg.u.rng);
+                       break;
+
                default:
                        rc = crypto_register_skcipher(&alg->alg.u.cipher);
                        break;
@@ -1064,6 +1070,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
                        crypto_unregister_aead(&alg->alg.u.aead);
                        break;
 
+               case CRYPTO_ALG_TYPE_RNG:
+                       crypto_unregister_rng(&alg->alg.u.rng);
+                       break;
+
                default:
                        crypto_unregister_skcipher(&alg->alg.u.cipher);
                }
@@ -1122,6 +1132,69 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
                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
  */
@@ -1291,6 +1364,18 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
                        .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)
        core_dev->dev->core_dev = core_dev;
        core_dev->dev->is_revb = is_revb;
        core_dev->device = dev;
+       mutex_init(&core_dev->rng_lock);
        spin_lock_init(&core_dev->lock);
        INIT_LIST_HEAD(&core_dev->dev->alg_list);
        ratelimit_default_init(&core_dev->dev->aead_ratelimit);
@@ -1439,6 +1525,7 @@ static int crypto4xx_remove(struct platform_device *ofdev)
        tasklet_kill(&core_dev->tasklet);
        /* Un-register with Linux CryptoAPI */
        crypto4xx_unregister_alg(core_dev->dev);
+       mutex_destroy(&core_dev->rng_lock);
        /* Free all allocated memory */
        crypto4xx_stop_all(core_dev);
 
index e2ca56722f077242a0a356d14e15638db48ab49c..18df695ca6b10f42a7276ee03ce3107a08e6f092 100644 (file)
 #define __CRYPTO4XX_CORE_H__
 
 #include <linux/ratelimit.h>
+#include <linux/mutex.h>
 #include <crypto/internal/hash.h>
 #include <crypto/internal/aead.h>
+#include <crypto/internal/rng.h>
 #include <crypto/internal/skcipher.h>
 #include "crypto4xx_reg_def.h"
 #include "crypto4xx_sa.h"
@@ -119,6 +121,7 @@ struct crypto4xx_core_device {
        u32 irq;
        struct tasklet_struct tasklet;
        spinlock_t lock;
+       struct mutex rng_lock;
 };
 
 struct crypto4xx_ctx {
@@ -143,6 +146,7 @@ struct crypto4xx_alg_common {
                struct skcipher_alg cipher;
                struct ahash_alg hash;
                struct aead_alg aead;
+               struct rng_alg rng;
        } u;
 };
 
index 472331787e04dda4f9e942c8c7159d61e7be078c..80c67490bbf6c327a23ebc0e847f56291161980a 100644 (file)
 #define CRYPTO4XX_ENDIAN_CFG                   0x000600d8
 
 #define CRYPTO4XX_PRNG_STAT                    0x00070000
+#define CRYPTO4XX_PRNG_STAT_BUSY               0x1
 #define CRYPTO4XX_PRNG_CTRL                    0x00070004
 #define CRYPTO4XX_PRNG_SEED_L                  0x00070008
 #define CRYPTO4XX_PRNG_SEED_H                  0x0007000c