register with the hwrng subsystem to provide entropy to the kernel.

Signed-off-by: Kim Phillips <[EMAIL PROTECTED]>
---
 drivers/crypto/Kconfig   |    1 +
 drivers/crypto/talitos.c |  136 ++++++++++++++++++++++++++++++++++++++--------
 drivers/crypto/talitos.h |   13 ++++-
 3 files changed, 126 insertions(+), 24 deletions(-)

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 98d96df..249c135 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -178,6 +178,7 @@ config CRYPTO_DEV_TALITOS
        tristate "Talitos Freescale Security Engine (SEC)"
        select CRYPTO_ALGAPI
        select CRYPTO_AUTHENC
+       select HW_RANDOM
        depends on FSL_SOC
        help
          Say 'Y' here to use the Freescale Security Engine (SEC)
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 64ddad2..e123312 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -124,6 +124,9 @@ struct talitos_private {
 
        /* list of registered algorithms */
        struct list_head alg_list;
+
+       /* hwrng device */
+       struct hwrng rng;
 };
 
 /*
@@ -523,8 +526,8 @@ static void talitos_error(unsigned long data)
                        }
                }
        }
-       if (reset_dev || isr & ~TALITOS_ISR_CHERR) {
-               dev_err(dev, "done overflow or internal time out error: "
+       if (reset_dev || isr & ~TALITOS_ISR_CHERR || isr_lo) {
+               dev_err(dev, "done overflow, internal time out, or rngu error: "
                        "ISR 0x%08x_%08x\n", isr, isr_lo);
 
                /* purge request queues */
@@ -549,7 +552,7 @@ static irqreturn_t talitos_interrupt(int irq, void *data)
        out_be32(priv->reg + TALITOS_ICR, isr);
        out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
 
-       if (unlikely(isr & ~TALITOS_ISR_CHDONE))
+       if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo))
                talitos_error((unsigned long)data);
        else
                if (likely(isr & TALITOS_ISR_CHDONE))
@@ -559,6 +562,80 @@ static irqreturn_t talitos_interrupt(int irq, void *data)
 }
 
 /*
+ * hwrng
+ */
+static int talitos_rng_data_present(struct hwrng *rng, int wait)
+{
+       struct device *dev = (struct device *)rng->priv;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       u32 ofl;
+       int i;
+
+       for (i = 0; i < 20; i++) {
+               ofl = in_be32(priv->reg + TALITOS_RNGUSR_LO) &
+                     TALITOS_RNGUSR_LO_OFL;
+               if (ofl || !wait)
+                       break;
+               udelay(10);
+       }
+
+       return !!ofl;
+}
+
+static int talitos_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       struct device *dev = (struct device *)rng->priv;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+
+       /* rng fifo requires 64-bit accesses */
+       *data = in_be32(priv->reg + TALITOS_RNGU_FIFO);
+       *data = in_be32(priv->reg + TALITOS_RNGU_FIFO_LO);
+
+       return sizeof(u32);
+}
+
+static int talitos_rng_init(struct hwrng *rng)
+{
+       struct device *dev = (struct device *)rng->priv;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       unsigned int timeout = TALITOS_TIMEOUT;
+
+       setbits32(priv->reg + TALITOS_RNGURCR_LO, TALITOS_RNGURCR_LO_SR);
+       while (!(in_be32(priv->reg + TALITOS_RNGUSR_LO) & TALITOS_RNGUSR_LO_RD)
+              && --timeout)
+               cpu_relax();
+       if (timeout == 0) {
+               dev_err(dev, "failed to reset rng hw\n");
+               return -ENODEV;
+       }
+
+       /* start generating */
+       setbits32(priv->reg + TALITOS_RNGUDSR_LO, 0);
+
+       return 0;
+}
+
+static int talitos_register_rng(struct device *dev)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+
+       priv->rng.name          = dev_driver_string(dev),
+       priv->rng.init          = talitos_rng_init,
+       priv->rng.data_present  = talitos_rng_data_present,
+       priv->rng.data_read     = talitos_rng_data_read,
+       priv->rng.priv          = (unsigned long)dev;
+
+       return hwrng_register(&priv->rng);
+}
+
+static void talitos_unregister_rng(struct device *dev)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+
+       hwrng_unregister(&priv->rng);
+}
+
+/*
  * crypto alg
  */
 #define TALITOS_CRA_PRIORITY           3000
@@ -1094,6 +1171,26 @@ static int talitos_cra_init(struct crypto_tfm *tfm)
        return 0;
 }
 
+/*
+ * given the alg's descriptor header template, determine whether descriptor
+ * type and primary/secondary execution units required match the hw
+ * capabilities description provided in the device tree node.
+ */
+static int hw_supports(struct device *dev, __be32 desc_hdr_template)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = (1 << DESC_TYPE(desc_hdr_template) & priv->desc_types) &&
+             (1 << PRIMARY_EU(desc_hdr_template) & priv->exec_units);
+
+       if (SECONDARY_EU(desc_hdr_template))
+               ret = ret && (1 << SECONDARY_EU(desc_hdr_template)
+                             & priv->exec_units);
+
+       return ret;
+}
+
 static int __devexit talitos_remove(struct of_device *ofdev)
 {
        struct device *dev = &ofdev->dev;
@@ -1107,6 +1204,9 @@ static int __devexit talitos_remove(struct of_device 
*ofdev)
                kfree(t_alg);
        }
 
+       if (hw_supports(dev, DESC_HDR_SEL0_RNG))
+               talitos_unregister_rng(dev);
+
        kfree(priv->tail);
        kfree(priv->head);
 
@@ -1167,26 +1267,6 @@ static struct talitos_crypto_alg 
*talitos_alg_alloc(struct device *dev,
        return t_alg;
 }
 
-/*
- * given the alg's descriptor header template, determine whether descriptor
- * type and primary/secondary execution units required match the hw
- * capabilities description provided in the device tree node.
- */
-static int hw_supports(struct device *dev, __be32 desc_hdr_template)
-{
-       struct talitos_private *priv = dev_get_drvdata(dev);
-       int ret;
-
-       ret = (1 << DESC_TYPE(desc_hdr_template) & priv->desc_types) &&
-             (1 << PRIMARY_EU(desc_hdr_template) & priv->exec_units);
-
-       if (SECONDARY_EU(desc_hdr_template))
-               ret = ret && (1 << SECONDARY_EU(desc_hdr_template)
-                             & priv->exec_units);
-
-       return ret;
-}
-
 static int talitos_probe(struct of_device *ofdev,
                         const struct of_device_id *match)
 {
@@ -1309,6 +1389,16 @@ static int talitos_probe(struct of_device *ofdev,
                goto err_out;
        }
 
+       /* register the RNG, if available */
+       if (hw_supports(dev, DESC_HDR_SEL0_RNG)) {
+               err = talitos_register_rng(dev);
+               if (err) {
+                       dev_err(dev, "failed to register hwrng: %d\n", err);
+                       goto err_out;
+               } else
+                       dev_info(dev, "hwrng\n");
+       }
+
        /* register crypto algorithms the device supports */
        INIT_LIST_HEAD(&priv->alg_list);
 
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
index 27deb65..de0e377 100644
--- a/drivers/crypto/talitos.h
+++ b/drivers/crypto/talitos.h
@@ -39,7 +39,7 @@
 #define TALITOS_IMR                    0x1008  /* interrupt mask register */
 #define   TALITOS_IMR_INIT             0x10fff /* enable channel IRQs */
 #define TALITOS_IMR_LO                 0x100C
-#define   TALITOS_IMR_LO_INIT          0x0     /* disable execution unit IRQs*/
+#define   TALITOS_IMR_LO_INIT          0x20000 /* allow RNGU error IRQs */
 #define TALITOS_ISR                    0x1010  /* interrupt status register */
 #define   TALITOS_ISR_CHERR            0xaa    /* channel errors mask */
 #define   TALITOS_ISR_CHDONE           0x55    /* channel done mask */
@@ -106,6 +106,17 @@
 #define TALITOS_AFEUISR_LO             0x8034
 #define TALITOS_RNGUISR                        0xa030 /* random number unit */
 #define TALITOS_RNGUISR_LO             0xa034
+#define TALITOS_RNGUSR                 0xa028 /* rng status */
+#define TALITOS_RNGUSR_LO              0xa02c
+#define   TALITOS_RNGUSR_LO_RD         0x1     /* reset done */
+#define   TALITOS_RNGUSR_LO_OFL                0xff0000/* output FIFO length */
+#define TALITOS_RNGUDSR                        0xa010  /* data size */
+#define TALITOS_RNGUDSR_LO             0xa014
+#define TALITOS_RNGU_FIFO              0xa800  /* output FIFO */
+#define TALITOS_RNGU_FIFO_LO           0xa804  /* output FIFO */
+#define TALITOS_RNGURCR                        0xa018  /* reset control */
+#define TALITOS_RNGURCR_LO             0xa01c
+#define   TALITOS_RNGURCR_LO_SR                0x1     /* software reset */
 #define TALITOS_PKEUISR                        0xc030 /* public key unit */
 #define TALITOS_PKEUISR_LO             0xc034
 #define TALITOS_KEUISR                 0xe030 /* kasumi unit */
-- 
1.5.6.rc2.26.g8c37

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to