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

From: Michal Vokáč
Date: Tue Jan 18 2022 - 09:28:08 EST


From: Petr Benes <petr.benes@xxxxxxxxx>

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@xxxxxxxxx
Signed-off-by: Petr Benes <petr.benes@xxxxxxxxx>
Signed-off-by: Michal Vokáč <michal.vokac@xxxxxxxxx>
---
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 --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;

--
2.25.1