In order to give CAAM-generated random data highest quarlity raiting (999), replace current code that uses DRNG with code that fetches data straight out of TRNG used to seed aforementioned DRNG. Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> Cc: Chris Healy <cphealy@xxxxxxxxx> Cc: Lucas Stach <l.stach@xxxxxxxxxxxxxx> Cc: Horia Geantă <horia.geanta@xxxxxxx> Cc: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> Cc: Iuliana Prodan <iuliana.prodan@xxxxxxx> Cc: linux-imx@xxxxxxx Cc: linux-crypto@xxxxxxxxxxxxxxx Cc: linux-kernel@xxxxxxxxxxxxxxx --- drivers/crypto/caam/Kconfig | 17 +- drivers/crypto/caam/Makefile | 2 +- drivers/crypto/caam/caamrng.c | 351 ---------------------------------- drivers/crypto/caam/ctrl.c | 6 + drivers/crypto/caam/intern.h | 9 +- drivers/crypto/caam/jr.c | 2 - drivers/crypto/caam/regs.h | 7 +- drivers/crypto/caam/trng.c | 89 +++++++++ 8 files changed, 111 insertions(+), 372 deletions(-) delete mode 100644 drivers/crypto/caam/caamrng.c create mode 100644 drivers/crypto/caam/trng.c diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 137ed3df0c74..22116a8e2ff3 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -31,6 +31,14 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG Selecting this will enable printing of various debug information in the CAAM driver. +config CRYPTO_DEV_FSL_CAAM_RNG_API + bool "Register caam device for hwrng API" + default y + select HW_RANDOM + help + Selecting this will register the hardware TRNG to + the hw_random API for suppying the kernel entropy pool. + menuconfig CRYPTO_DEV_FSL_CAAM_JR tristate "Freescale CAAM Job Ring driver backend" default y @@ -138,15 +146,6 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API Supported cryptographic primitives: encryption, decryption, signature and verification. -config CRYPTO_DEV_FSL_CAAM_RNG_API - bool "Register caam device for hwrng API" - default y - select CRYPTO_RNG - select HW_RANDOM - help - Selecting this will register the SEC4 hardware rng to - the hw_random API for suppying the kernel entropy pool. - endif # CRYPTO_DEV_FSL_CAAM_JR endif # CRYPTO_DEV_FSL_CAAM diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 68d5cc0f28e2..04884fc087f9 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -15,11 +15,11 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o caam-y := ctrl.o +caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += trng.o caam_jr-y := jr.o key_gen.o caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o -caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c deleted file mode 100644 index 70ddfbf90ac7..000000000000 --- a/drivers/crypto/caam/caamrng.c +++ /dev/null @@ -1,351 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * caam - Freescale FSL CAAM support for hw_random - * - * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2018-2019 NXP - * - * Based on caamalg.c crypto API driver. - * - * relationship between job descriptors to shared descriptors: - * - * --------------- -------------- - * | JobDesc #0 |-------------------->| ShareDesc | - * | *(buffer 0) | |------------->| (generate) | - * --------------- | | (move) | - * | | (store) | - * --------------- | -------------- - * | JobDesc #1 |------| - * | *(buffer 1) | - * --------------- - * - * A job desc looks like this: - * - * --------------------- - * | Header | - * | ShareDesc Pointer | - * | SEQ_OUT_PTR | - * | (output buffer) | - * --------------------- - * - * The SharedDesc never changes, and each job descriptor points to one of two - * buffers for each device, from which the data will be copied into the - * requested destination - */ - -#include <linux/hw_random.h> -#include <linux/completion.h> -#include <linux/atomic.h> - -#include "compat.h" - -#include "regs.h" -#include "intern.h" -#include "desc_constr.h" -#include "jr.h" -#include "error.h" - -/* - * Maximum buffer size: maximum number of random, cache-aligned bytes that - * will be generated and moved to seq out ptr (extlen not allowed) - */ -#define RN_BUF_SIZE (0xffff / L1_CACHE_BYTES * \ - L1_CACHE_BYTES) - -/* length of descriptors */ -#define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ_MAX * 2) -#define DESC_RNG_LEN (3 * CAAM_CMD_SZ) - -/* Buffer, its dma address and lock */ -struct buf_data { - u8 buf[RN_BUF_SIZE] ____cacheline_aligned; - dma_addr_t addr; - struct completion filled; - u32 hw_desc[DESC_JOB_O_LEN]; -#define BUF_NOT_EMPTY 0 -#define BUF_EMPTY 1 -#define BUF_PENDING 2 /* Empty, but with job pending --don't submit another */ - atomic_t empty; -}; - -/* rng per-device context */ -struct caam_rng_ctx { - struct device *jrdev; - dma_addr_t sh_desc_dma; - u32 sh_desc[DESC_RNG_LEN]; - unsigned int cur_buf_idx; - int current_buf; - struct buf_data bufs[2]; -}; - -static struct caam_rng_ctx *rng_ctx; - -/* - * Variable used to avoid double free of resources in case - * algorithm registration was unsuccessful - */ -static bool init_done; - -static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd) -{ - if (bd->addr) - dma_unmap_single(jrdev, bd->addr, RN_BUF_SIZE, - DMA_FROM_DEVICE); -} - -static inline void rng_unmap_ctx(struct caam_rng_ctx *ctx) -{ - struct device *jrdev = ctx->jrdev; - - if (ctx->sh_desc_dma) - dma_unmap_single(jrdev, ctx->sh_desc_dma, - desc_bytes(ctx->sh_desc), DMA_TO_DEVICE); - rng_unmap_buf(jrdev, &ctx->bufs[0]); - rng_unmap_buf(jrdev, &ctx->bufs[1]); -} - -static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context) -{ - struct buf_data *bd; - - bd = container_of(desc, struct buf_data, hw_desc[0]); - - if (err) - caam_jr_strstatus(jrdev, err); - - atomic_set(&bd->empty, BUF_NOT_EMPTY); - complete(&bd->filled); - - /* Buffer refilled, invalidate cache */ - dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE); - - print_hex_dump_debug("rng refreshed buf@: ", DUMP_PREFIX_ADDRESS, 16, 4, - bd->buf, RN_BUF_SIZE, 1); -} - -static inline int submit_job(struct caam_rng_ctx *ctx, int to_current) -{ - struct buf_data *bd = &ctx->bufs[!(to_current ^ ctx->current_buf)]; - struct device *jrdev = ctx->jrdev; - u32 *desc = bd->hw_desc; - int err; - - dev_dbg(jrdev, "submitting job %d\n", !(to_current ^ ctx->current_buf)); - init_completion(&bd->filled); - err = caam_jr_enqueue(jrdev, desc, rng_done, ctx); - if (err) - complete(&bd->filled); /* don't wait on failed job*/ - else - atomic_inc(&bd->empty); /* note if pending */ - - return err; -} - -static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait) -{ - struct caam_rng_ctx *ctx = rng_ctx; - struct buf_data *bd = &ctx->bufs[ctx->current_buf]; - int next_buf_idx, copied_idx; - int err; - - if (atomic_read(&bd->empty)) { - /* try to submit job if there wasn't one */ - if (atomic_read(&bd->empty) == BUF_EMPTY) { - err = submit_job(ctx, 1); - /* if can't submit job, can't even wait */ - if (err) - return 0; - } - /* no immediate data, so exit if not waiting */ - if (!wait) - return 0; - - /* waiting for pending job */ - if (atomic_read(&bd->empty)) - wait_for_completion(&bd->filled); - } - - next_buf_idx = ctx->cur_buf_idx + max; - dev_dbg(ctx->jrdev, "%s: start reading at buffer %d, idx %d\n", - __func__, ctx->current_buf, ctx->cur_buf_idx); - - /* if enough data in current buffer */ - if (next_buf_idx < RN_BUF_SIZE) { - memcpy(data, bd->buf + ctx->cur_buf_idx, max); - ctx->cur_buf_idx = next_buf_idx; - return max; - } - - /* else, copy what's left... */ - copied_idx = RN_BUF_SIZE - ctx->cur_buf_idx; - memcpy(data, bd->buf + ctx->cur_buf_idx, copied_idx); - ctx->cur_buf_idx = 0; - atomic_set(&bd->empty, BUF_EMPTY); - - /* ...refill... */ - submit_job(ctx, 1); - - /* and use next buffer */ - ctx->current_buf = !ctx->current_buf; - dev_dbg(ctx->jrdev, "switched to buffer %d\n", ctx->current_buf); - - /* since there already is some data read, don't wait */ - return copied_idx + caam_read(rng, data + copied_idx, - max - copied_idx, false); -} - -static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx) -{ - struct device *jrdev = ctx->jrdev; - u32 *desc = ctx->sh_desc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Generate random bytes */ - append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG | - OP_ALG_PR_ON); - - /* Store bytes */ - append_seq_fifo_store(desc, RN_BUF_SIZE, FIFOST_TYPE_RNGSTORE); - - ctx->sh_desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } - - print_hex_dump_debug("rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4, - desc, desc_bytes(desc), 1); - - return 0; -} - -static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id) -{ - struct device *jrdev = ctx->jrdev; - struct buf_data *bd = &ctx->bufs[buf_id]; - u32 *desc = bd->hw_desc; - int sh_len = desc_len(ctx->sh_desc); - - init_job_desc_shared(desc, ctx->sh_desc_dma, sh_len, HDR_SHARE_DEFER | - HDR_REVERSE); - - bd->addr = dma_map_single(jrdev, bd->buf, RN_BUF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(jrdev, bd->addr)) { - dev_err(jrdev, "unable to map dst\n"); - return -ENOMEM; - } - - append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0); - - print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4, - desc, desc_bytes(desc), 1); - - return 0; -} - -static void caam_cleanup(struct hwrng *rng) -{ - int i; - struct buf_data *bd; - - for (i = 0; i < 2; i++) { - bd = &rng_ctx->bufs[i]; - if (atomic_read(&bd->empty) == BUF_PENDING) - wait_for_completion(&bd->filled); - } - - rng_unmap_ctx(rng_ctx); -} - -static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) -{ - struct buf_data *bd = &ctx->bufs[buf_id]; - int err; - - err = rng_create_job_desc(ctx, buf_id); - if (err) - return err; - - atomic_set(&bd->empty, BUF_EMPTY); - submit_job(ctx, buf_id == ctx->current_buf); - wait_for_completion(&bd->filled); - - return 0; -} - -static int caam_init_rng(struct caam_rng_ctx *ctx, struct device *jrdev) -{ - int err; - - ctx->jrdev = jrdev; - - err = rng_create_sh_desc(ctx); - if (err) - return err; - - ctx->current_buf = 0; - ctx->cur_buf_idx = 0; - - err = caam_init_buf(ctx, 0); - if (err) - return err; - - return caam_init_buf(ctx, 1); -} - -static struct hwrng caam_rng = { - .name = "rng-caam", - .cleanup = caam_cleanup, - .read = caam_read, -}; - -void caam_rng_exit(void) -{ - if (!init_done) - return; - - caam_jr_free(rng_ctx->jrdev); - hwrng_unregister(&caam_rng); - kfree(rng_ctx); -} - -int caam_rng_init(struct device *ctrldev) -{ - struct device *dev; - struct caam_drv_private *priv = dev_get_drvdata(ctrldev); - int err; - init_done = false; - - if (!caam_has_rng(priv)) - return 0; - - dev = caam_jr_alloc(); - if (IS_ERR(dev)) { - pr_err("Job Ring Device allocation for transform failed\n"); - return PTR_ERR(dev); - } - rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL); - if (!rng_ctx) { - err = -ENOMEM; - goto free_caam_alloc; - } - err = caam_init_rng(rng_ctx, dev); - if (err) - goto free_rng_ctx; - - dev_info(dev, "registering rng-caam\n"); - - err = hwrng_register(&caam_rng); - if (!err) { - init_done = true; - return err; - } - -free_rng_ctx: - kfree(rng_ctx); -free_caam_alloc: - caam_jr_free(dev); - return err; -} diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 8054ec29d35a..adbdef06bcf9 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -907,6 +907,12 @@ static int caam_probe(struct platform_device *pdev) &ctrlpriv->ctl_tdsk_wrap); #endif + ret = caam_trng_register(dev); + if (ret) { + dev_err(dev, "Failed to register HWRNG interface\n"); + return ret; + } + ret = devm_of_platform_populate(dev); if (ret) dev_err(dev, "JR platform devices creation error\n"); diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index f815e1ad4608..54bb04aa86bd 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -174,20 +174,15 @@ static inline void caam_pkc_exit(void) #ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API -int caam_rng_init(struct device *dev); -void caam_rng_exit(void); +int caam_trng_register(struct device *dev); #else -static inline int caam_rng_init(struct device *dev) +static inline int caam_trng_register(struct device *dev) { return 0; } -static inline void caam_rng_exit(void) -{ -} - #endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */ #ifdef CONFIG_CAAM_QI diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index fc97cde27059..c745b7044fe6 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -37,7 +37,6 @@ static void register_algs(struct device *dev) caam_algapi_init(dev); caam_algapi_hash_init(dev); caam_pkc_init(dev); - caam_rng_init(dev); caam_qi_algapi_init(dev); algs_unlock: @@ -53,7 +52,6 @@ static void unregister_algs(void) caam_qi_algapi_exit(); - caam_rng_exit(); caam_pkc_exit(); caam_algapi_hash_exit(); caam_algapi_exit(); diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index fe1f8c1409fd..262399387e27 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -488,6 +488,7 @@ struct rngtst { /* RNG4 TRNG test registers */ struct rng4tst { #define RTMCTL_ACC BIT(5) /* TRNG access mode */ +#define RTMCTL_ENT_VAL BIT(10) #define RTMCTL_PRGM BIT(16) /* 1 -> program mode, 0 -> run mode */ #define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0 /* use von Neumann data in both entropy shifter and @@ -521,7 +522,9 @@ struct rng4tst { u32 rtfrqmax; /* PRGM=1: freq. count max. limit register */ u32 rtfrqcnt; /* PRGM=0: freq. count register */ }; - u32 rsvd1[40]; + u32 rsvd1[8]; + u32 rtent[16]; /* RTENT0 - RTENT15 */ + u32 rsvd2[16]; /* RTPKRCNTn */ #define RDSTA_SKVT 0x80000000 #define RDSTA_SKVN 0x40000000 #define RDSTA_PR0 BIT(4) @@ -530,7 +533,7 @@ struct rng4tst { #define RDSTA_IF1 0x00000002 #define RDSTA_IFMASK (RDSTA_PR1 | RDSTA_PR0 | RDSTA_IF1 | RDSTA_IF0) u32 rdsta; - u32 rsvd2[15]; + u32 rsvd3[15]; }; /* diff --git a/drivers/crypto/caam/trng.c b/drivers/crypto/caam/trng.c new file mode 100644 index 000000000000..881fe588a229 --- /dev/null +++ b/drivers/crypto/caam/trng.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * hw_random interface for TRNG generator in CAAM RNG block + * + * Copyright 2019 Zodiac Inflight Innovations + * + */ + +#include <linux/hw_random.h> + +#include "compat.h" +#include "regs.h" +#include "intern.h" + +struct caam_trng_ctx { + struct rng4tst __iomem *r4tst; + struct hwrng rng; +}; + +static bool caam_trng_busy(struct caam_trng_ctx *ctx) +{ + return !(rd_reg32(&ctx->r4tst->rtmctl) & RTMCTL_ENT_VAL); +} + +static int caam_trng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + struct caam_trng_ctx *ctx = (void *)rng->priv; + u32 rtent[ARRAY_SIZE(ctx->r4tst->rtent)]; + size_t residue = max; + + if (!wait) + return 0; + + clrsetbits_32(&ctx->r4tst->rtmctl, 0, RTMCTL_ACC); + + do { + const size_t chunk = min(residue, sizeof(rtent)); + unsigned int i; + + do { + /* + * It takes about 70 ms to finish on i.MX6 and + * i.MX8MQ + */ + msleep(70); + } while (caam_trng_busy(ctx)); + + for (i = 0; i < DIV_ROUND_UP(chunk, sizeof(u32)); i++) + rtent[i] = rd_reg32(&ctx->r4tst->rtent[i]); + + memcpy(data, rtent, chunk); + + residue -= chunk; + data += chunk; + } while (residue); + + clrsetbits_32(&ctx->r4tst->rtmctl, RTMCTL_ACC, 0); + + return max; +} + +int caam_trng_register(struct device *ctrldev) +{ + struct caam_drv_private *priv = dev_get_drvdata(ctrldev); + + if (caam_has_rng(priv)) { + struct caam_trng_ctx *ctx; + int err; + + ctx = devm_kzalloc(ctrldev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->r4tst = &priv->ctrl->r4tst[0]; + + ctx->rng.name = "trng-caam"; + ctx->rng.read = caam_trng_read; + ctx->rng.priv = (unsigned long)ctx; + ctx->rng.quality = 999; + + dev_info(ctrldev, "registering %s\n", ctx->rng.name); + + err = devm_hwrng_register(ctrldev, &ctx->rng); + if (err) + return err; + } + + return 0; +} -- 2.21.0