diff mbox series

[RFC,v2] crypto: caam - restore retry count after HW RNG failure

Message ID 20220118141811.110618-1-michal.vokac@ysoft.com (mailing list archive)
State RFC
Delegated to: Herbert Xu
Headers show
Series [RFC,v2] crypto: caam - restore retry count after HW RNG failure | expand

Commit Message

Michal Vokáč Jan. 18, 2022, 2:18 p.m. UTC
From: Petr Benes <petr.benes@ysoft.com>

Each time TRNG generates entropy, statistical tests are run.
If they fail, RETRY_COUNT value is decremented. Once it
reaches 0, HW RNG returns an error, and needs to be reset.
RETRY_COUNT could be programmed in RTSCMISC register and is
set to 1 by default. Hence, we are left without hwrng after
the first error, which could happen even under normal
conditions.

Cc: petrben@gmail.com
Signed-off-by: Petr Benes <petr.benes@ysoft.com>
Signed-off-by: Michal Vokáč <michal.vokac@ysoft.com>
---
v2:
- Export caam_reinstantiate_rng to fix build error.

 drivers/crypto/caam/caamrng.c | 42 ++++++++++++++++++++++++++++++++---
 drivers/crypto/caam/ctrl.c    | 14 ++++++++++++
 drivers/crypto/caam/ctrl.h    |  2 ++
 3 files changed, 55 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index 77d048dfe5d0..2be5584ae591 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -21,6 +21,7 @@ 
 #include "desc_constr.h"
 #include "jr.h"
 #include "error.h"
+#include "ctrl.h"
 
 #define CAAM_RNG_MAX_FIFO_STORE_SIZE	16
 
@@ -113,6 +114,35 @@  static int caam_rng_read_one(struct device *jrdev,
 	return err ?: (ret ?: len);
 }
 
+static void caam_rng_retry_reset(struct caam_rng_ctx *context)
+{
+	struct device *ctrldev = context->ctrldev;
+	struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
+	struct caam_ctrl __iomem *ctrl;
+	struct rng4tst __iomem *r4tst;
+	u32 __iomem *rtstatus;
+	u32 retry_count;
+
+	ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
+	r4tst = &ctrl->r4tst[0];
+
+	/*
+	 * There is unfortunately no member for RTSTATUS register in
+	 * struct rng4tst and the structure doesn't look stable
+	 */
+	rtstatus = (u32 *)((char *)&ctrl->r4tst[0] + 0x3C);
+	retry_count = (rd_reg32(rtstatus) >> 16) & 0xf;
+	dev_dbg(ctrldev, "CAAM RNG retry count %d\n", retry_count);
+	if (retry_count == 0) {
+		dev_err(ctrldev, "CAAM RNG resetting retry count to 1\n");
+		clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM | RTMCTL_ACC);
+		wr_reg32(&r4tst->rtscmisc, (rd_reg32(&r4tst->rtscmisc) & 0x7f) | (1 << 16));
+		clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM | RTMCTL_ACC,
+				RTMCTL_SAMP_MODE_RAW_ES_SC);
+		caam_reinstantiate_rng(ctrldev);
+	}
+}
+
 static void caam_rng_fill_async(struct caam_rng_ctx *ctx)
 {
 	struct scatterlist sg[1];
@@ -129,8 +159,10 @@  static void caam_rng_fill_async(struct caam_rng_ctx *ctx)
 				sg[0].length,
 				ctx->desc_async,
 				&done);
-	if (len < 0)
+	if (len < 0) {
+		caam_rng_retry_reset(ctx);
 		return;
+	}
 
 	kfifo_dma_in_finish(&ctx->fifo, len);
 }
@@ -145,13 +177,17 @@  static void caam_rng_worker(struct work_struct *work)
 static int caam_read(struct hwrng *rng, void *dst, size_t max, bool wait)
 {
 	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
-	int out;
+	int out, ret;
 
 	if (wait) {
 		struct completion done;
 
-		return caam_rng_read_one(ctx->jrdev, dst, max,
+		ret = caam_rng_read_one(ctx->jrdev, dst, max,
 					 ctx->desc_sync, &done);
+		if (ret < 0)
+			caam_rng_retry_reset(ctx);
+
+		return ret;
 	}
 
 	out = kfifo_out(&ctx->fifo, dst, max);
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index ca0361b2dbb0..6feb828b6a56 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -339,6 +339,20 @@  static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
 	return devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng, ctrldev);
 }
 
+/*
+ * caam_reinstantiate_rng - reinstantiates RNG. Intended for a case when RNG falls into
+ *			    HW error condition. That happens if TRNG fails statistical
+ *			    check and RTY_CNT value set in RTSCMISC decrements to zero.
+ *			    It is exported to caamrng.c
+ * @ctrldev - pointer to device
+ */
+
+int caam_reinstantiate_rng(struct device *ctrldev)
+{
+	return instantiate_rng(ctrldev, 0, 0);
+}
+EXPORT_SYMBOL(caam_reinstantiate_rng);
+
 /*
  * kick_trng - sets the various parameters for enabling the initialization
  *	       of the RNG4 block in CAAM
diff --git a/drivers/crypto/caam/ctrl.h b/drivers/crypto/caam/ctrl.h
index f3ecd67922a7..26ff5a49a865 100644
--- a/drivers/crypto/caam/ctrl.h
+++ b/drivers/crypto/caam/ctrl.h
@@ -8,6 +8,8 @@ 
 #ifndef CTRL_H
 #define CTRL_H
 
+int caam_reinstantiate_rng(struct device *ctrldev);
+
 /* Prototypes for backend-level services exposed to APIs */
 extern bool caam_dpaa2;