[PATCH 4/4] crypto/talitos: add hwrng support

Kim Phillips kim.phillips at freescale.com
Tue Jun 17 02:10:53 EST 2008


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

Signed-off-by: Kim Phillips <kim.phillips at freescale.com>
---
 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




More information about the Linuxppc-dev mailing list