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