Message ID | 20230707115242.3411259-1-clabbe@baylibre.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [RFC/RFT] crypto: rk3288: enable support for TRNG | expand |
Hi, On Fri Jul 7, 2023 at 1:52 PM CEST, Corentin Labbe wrote: > The rockchip IP has a TRNG which could be used as a hwrng. > Since TRNG is only failling rngtests on rk3328 and does not work on > rk3288, the TRNG is enabled only on rk3399 via a variant. > But this is not a surprise since when vendor tried to add support for TRNG upstream, > rk3288 was not handled, and rk3328 was added "disabled", so I conclude > this is a known problem. > Anyway the quality of rk3399 TRNG is low, so a dedicated kconfig option > is done to not enabled it by default. > > Signed-off-by: Corentin Labbe <clabbe@baylibre.com> > --- > Hello > > All rk3288 compatible crypto IP have a TRNG and supporting it was awaited for > some time (https://bugzilla.kernel.org/show_bug.cgi?id=216502) > > I has some problem with this one, it was the first time I hit so many 100% failure on rngtest. > > I finally bisected a RNG_SAMPLE value (1200) which lead to "only" 50-70% failure. > The calcul of fail rate is done with (FIPS 140-2 successes/FIPS 140-2 failures) of rngtest. > Since it is the first time I hit that case, does setting rng_quality to 300 is > what to do (using the worst succes rate of 30%) ? > > But I am really puzzled why vendor default is to use RNG_SAMPLE=100 which is total failure (according to rngtest). > Unfortunatly all my try to have more answer from them seems to have been forwarded to /dev/null. > > Thanks > Regards I tested this on a rk3399-rock-pi-4b with the following results: # uname -a Linux rockpi-bookworm 6.4.3-dirty #83 SMP PREEMPT Wed Jul 12 09:07:12 CEST 2023 aarch64 GNU/Linux # sudo ls -l /dev/hwrng crw------- 1 root root 10, 183 Jan 18 09:52 /dev/hwrng # cat /sys/devices/virtual/misc/hw_random/rng_current Rockchip rk3288 TRNG # sudo dd if=/dev/hwrng count=100 bs=2048 | rngtest rngtest 5 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... 100+0 records in 100+0 records out 204800 bytes (205 kB, 200 KiB) copied, 10.1847 s, 20.1 kB/s rngtest: entropy source drained rngtest: bits received from input: 1638400 rngtest: FIPS 140-2 successes: 54 rngtest: FIPS 140-2 failures: 27 rngtest: FIPS 140-2(2001-10-10) Monobit: 27 rngtest: FIPS 140-2(2001-10-10) Poker: 3 rngtest: FIPS 140-2(2001-10-10) Runs: 1 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=94.195; avg=159.504; max=195.252)Kibits/s rngtest: FIPS tests speed: (min=17.826; avg=25.180; max=38.377)Mibits/s rngtest: Program run time: 10221628 microseconds # sudo dd if=/dev/hwrng count=200 bs=2048 | rngtest rngtest 5 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... 200+0 records in 200+0 records out 409600 bytes (410 kB, 400 KiB) copied, 20.2624 s, 20.2 kB/s rngtest: entropy source drained rngtest: bits received from input: 3276800 rngtest: FIPS 140-2 successes: 115 rngtest: FIPS 140-2 failures: 48 rngtest: FIPS 140-2(2001-10-10) Monobit: 48 rngtest: FIPS 140-2(2001-10-10) Poker: 1 rngtest: FIPS 140-2(2001-10-10) Runs: 0 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=94.636; avg=159.621; max=195.400)Kibits/s rngtest: FIPS tests speed: (min=25.031; avg=27.258; max=28.639)Mibits/s rngtest: Program run time: 20297102 microseconds Tested-by: Folker Schwesinger <dev@folker-schwesinger.de> Kind regards, Folker > drivers/crypto/Kconfig | 8 ++ > drivers/crypto/rockchip/Makefile | 1 + > drivers/crypto/rockchip/rk3288_crypto.c | 18 +++- > drivers/crypto/rockchip/rk3288_crypto.h | 18 ++++ > drivers/crypto/rockchip/rk3288_crypto_ahash.c | 2 + > .../crypto/rockchip/rk3288_crypto_skcipher.c | 2 + > drivers/crypto/rockchip/rk3288_crypto_trng.c | 92 +++++++++++++++++++ > 7 files changed, 140 insertions(+), 1 deletion(-) > create mode 100644 drivers/crypto/rockchip/rk3288_crypto_trng.c > > diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig > index 44e44b8d9ce6..7226d441686c 100644 > --- a/drivers/crypto/Kconfig > +++ b/drivers/crypto/Kconfig > @@ -650,6 +650,14 @@ config CRYPTO_DEV_ROCKCHIP > This driver interfaces with the hardware crypto accelerator. > Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode. > > +config CRYPTO_DEV_ROCKCHIP_TRNG > + bool "Support for Rockchip TRNG" > + depends on CRYPTO_DEV_ROCKCHIP > + select HW_RANDOM > + help > + Select this option if you want to provide kernel-side support for > + the True Random Number Generator found in the Crypto IP. > + > config CRYPTO_DEV_ROCKCHIP_DEBUG > bool "Enable Rockchip crypto stats" > depends on CRYPTO_DEV_ROCKCHIP > diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile > index 785277aca71e..11910f0e6a62 100644 > --- a/drivers/crypto/rockchip/Makefile > +++ b/drivers/crypto/rockchip/Makefile > @@ -3,3 +3,4 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o > rk_crypto-objs := rk3288_crypto.o \ > rk3288_crypto_skcipher.o \ > rk3288_crypto_ahash.o > +rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG) += rk3288_crypto_trng.o > diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c > index 9f6ba770a90a..880e4db812a2 100644 > --- a/drivers/crypto/rockchip/rk3288_crypto.c > +++ b/drivers/crypto/rockchip/rk3288_crypto.c > @@ -40,15 +40,18 @@ static const struct rk_variant rk3288_variant = { > .num_clks = 4, > .rkclks = { > { "sclk", 150000000}, > - } > + }, > + .trng = false, > }; > > static const struct rk_variant rk3328_variant = { > .num_clks = 3, > + .trng = false, > }; > > static const struct rk_variant rk3399_variant = { > .num_clks = 3, > + .trng = true, > }; > > static int rk_crypto_get_clks(struct rk_crypto_info *dev) > @@ -195,6 +198,10 @@ static int rk_crypto_debugfs_show(struct seq_file *seq, void *v) > seq_printf(seq, "%s %s requests: %lu\n", > dev_driver_string(dd->dev), dev_name(dd->dev), > dd->nreq); > +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG > + seq_printf(seq, "HWRNG: %lu %lu\n", > + dd->hwrng_stat_req, dd->hwrng_stat_bytes); > +#endif > } > spin_unlock(&rocklist.lock); > > @@ -381,6 +388,10 @@ static int rk_crypto_probe(struct platform_device *pdev) > dev_err(dev, "Fail to register crypto algorithms"); > goto err_register_alg; > } > +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG > + if (crypto_info->variant->trng) > + rk3288_hwrng_register(crypto_info); > +#endif > > register_debugfs(crypto_info); > } > @@ -411,6 +422,11 @@ static int rk_crypto_remove(struct platform_device *pdev) > #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG > debugfs_remove_recursive(rocklist.dbgfs_dir); > #endif > +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG > + if (crypto_tmp->variant->trng) > + rk3288_hwrng_unregister(crypto_tmp); > +#endif > + > rk_crypto_unregister(); > } > rk_crypto_pm_exit(crypto_tmp); > diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h > index b2695258cade..016c3b72c19c 100644 > --- a/drivers/crypto/rockchip/rk3288_crypto.h > +++ b/drivers/crypto/rockchip/rk3288_crypto.h > @@ -9,6 +9,7 @@ > #include <linux/interrupt.h> > #include <linux/debugfs.h> > #include <linux/delay.h> > +#include <linux/hw_random.h> > #include <linux/pm_runtime.h> > #include <linux/scatterlist.h> > #include <crypto/engine.h> > @@ -183,6 +184,16 @@ > #define RK_CRYPTO_HASH_DOUT_6 0x01a4 > #define RK_CRYPTO_HASH_DOUT_7 0x01a8 > > +#define RK_CRYPTO_TRNG_CTRL 0x0200 > +#define RK_CRYPTO_OSC_ENABLE BIT(16) > +#define RK_CRYPTO_TRNG_DOUT_0 0x0204 > +/* sample < 1000 lead to 100% failure on rngtest, > + * using more than 1200 does not increase success. > + */ > +#define RK_CRYPTO_RNG_SAMPLE 1200 > + > +#define RK_CRYPTO_MAX_TRNG_BYTE 32 > + > #define CRYPTO_READ(dev, offset) \ > readl_relaxed(((dev)->reg + (offset))) > #define CRYPTO_WRITE(dev, offset, val) \ > @@ -212,6 +223,7 @@ struct rk_clks { > struct rk_variant { > int num_clks; > struct rk_clks rkclks[RK_MAX_CLKS]; > + bool trng; > }; > > struct rk_crypto_info { > @@ -222,11 +234,15 @@ struct rk_crypto_info { > struct reset_control *rst; > void __iomem *reg; > int irq; > + struct mutex lock; > + struct hwrng hwrng; > const struct rk_variant *variant; > unsigned long nreq; > struct crypto_engine *engine; > struct completion complete; > int status; > + unsigned long hwrng_stat_req; > + unsigned long hwrng_stat_bytes; > }; > > /* the private variable of hash */ > @@ -288,3 +304,5 @@ extern struct rk_crypto_tmp rk_ahash_md5; > > struct rk_crypto_info *get_rk_crypto(void); > #endif > +int rk3288_hwrng_register(struct rk_crypto_info *rk); > +void rk3288_hwrng_unregister(struct rk_crypto_info *rk); > diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c > index a78ff3dcd0b1..67ed3a54bc7b 100644 > --- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c > +++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c > @@ -287,6 +287,7 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq) > goto theend; > } > > + mutex_lock(&rkc->lock); > rk_ahash_reg_init(areq, rkc); > > while (sg) { > @@ -321,6 +322,7 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq) > } > > theend: > + mutex_unlock(&rkc->lock); > pm_runtime_put_autosuspend(rkc->dev); > > local_bh_disable(); > diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c > index 59069457582b..304c2c44fea0 100644 > --- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c > +++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c > @@ -357,6 +357,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req) > } > } > err = 0; > + mutex_unlock(&rkc->lock); > rk_cipher_hw_init(rkc, areq); > if (ivsize) { > if (ivsize == DES_BLOCK_SIZE) > @@ -372,6 +373,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req) > crypto_dma_start(rkc, sgs, sgd, todo / 4); > wait_for_completion_interruptible_timeout(&rkc->complete, > msecs_to_jiffies(2000)); > + mutex_unlock(&rkc->lock); > if (!rkc->status) { > dev_err(rkc->dev, "DMA timeout\n"); > err = -EFAULT; > diff --git a/drivers/crypto/rockchip/rk3288_crypto_trng.c b/drivers/crypto/rockchip/rk3288_crypto_trng.c > new file mode 100644 > index 000000000000..7a0e1300d0e8 > --- /dev/null > +++ b/drivers/crypto/rockchip/rk3288_crypto_trng.c > @@ -0,0 +1,92 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * rk3288_crypto_trng.c - hardware cryptographic offloader for rockchip > + * > + * Copyright (C) 2022-2023 Corentin Labbe <clabbe@baylibre.com> > + * > + * This file handle the TRNG > + */ > +#include "rk3288_crypto.h" > +#include <linux/hw_random.h> > +#include <linux/iopoll.h> > +#include <linux/pm_runtime.h> > + > +static int rk3288_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) > +{ > + struct rk_crypto_info *rk; > + unsigned int todo; > + int err = 0; > + int i; > + u32 v; > + > + rk = container_of(hwrng, struct rk_crypto_info, hwrng); > + > + todo = min_t(size_t, max, RK_CRYPTO_MAX_TRNG_BYTE); > + > +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG > + rk->hwrng_stat_req++; > + rk->hwrng_stat_bytes += todo; > +#endif > + > + err = pm_runtime_resume_and_get(rk->dev); > + if (err < 0) > + goto err_pm; > + > + mutex_lock(&rk->lock); > + > +#define HIWORD_UPDATE(val, mask, shift) \ > + ((val) << (shift) | (mask) << ((shift) + 16)) > + v = RK_CRYPTO_OSC_ENABLE | RK_CRYPTO_RNG_SAMPLE; > + CRYPTO_WRITE(rk, RK_CRYPTO_TRNG_CTRL, v); > + > + v = HIWORD_UPDATE(RK_CRYPTO_TRNG_START, RK_CRYPTO_TRNG_START, 0); > + CRYPTO_WRITE(rk, RK_CRYPTO_CTRL, v); > + wmb(); > + > + err = readl_poll_timeout(rk->reg + RK_CRYPTO_CTRL, v, > + !(v & RK_CRYPTO_TRNG_START), > + 100, 2000); > + if (err) { > + dev_err(rk->dev, "HWRNG read timeout"); > + goto readfail; > + } > + > + for (i = 0; i < todo / 4; i++) { > + v = readl(rk->reg + RK_CRYPTO_TRNG_DOUT_0 + i * 4); > + put_unaligned_le32(v, data + i * 4); > + } > + > + err = todo; > + > + v = HIWORD_UPDATE(0, RK_CRYPTO_TRNG_START, 0); > + CRYPTO_WRITE(rk, RK_CRYPTO_CTRL, v); > + > +readfail: > + mutex_unlock(&rk->lock); > + > + pm_runtime_put(rk->dev); > + > +err_pm: > + return err; > +} > + > +int rk3288_hwrng_register(struct rk_crypto_info *rk) > +{ > + int ret; > + > + dev_info(rk->dev, "Register TRNG with sample=%d\n", RK_CRYPTO_RNG_SAMPLE); > + > + rk->hwrng.name = "Rockchip rk3288 TRNG"; > + rk->hwrng.read = rk3288_trng_read; > + rk->hwrng.quality = 300; > + > + ret = hwrng_register(&rk->hwrng); > + if (ret) > + dev_err(rk->dev, "Fail to register the TRNG\n"); > + return ret; > +} > + > +void rk3288_hwrng_unregister(struct rk_crypto_info *rk) > +{ > + hwrng_unregister(&rk->hwrng); > +}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 44e44b8d9ce6..7226d441686c 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -650,6 +650,14 @@ config CRYPTO_DEV_ROCKCHIP This driver interfaces with the hardware crypto accelerator. Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode. +config CRYPTO_DEV_ROCKCHIP_TRNG + bool "Support for Rockchip TRNG" + depends on CRYPTO_DEV_ROCKCHIP + select HW_RANDOM + help + Select this option if you want to provide kernel-side support for + the True Random Number Generator found in the Crypto IP. + config CRYPTO_DEV_ROCKCHIP_DEBUG bool "Enable Rockchip crypto stats" depends on CRYPTO_DEV_ROCKCHIP diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile index 785277aca71e..11910f0e6a62 100644 --- a/drivers/crypto/rockchip/Makefile +++ b/drivers/crypto/rockchip/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o rk_crypto-objs := rk3288_crypto.o \ rk3288_crypto_skcipher.o \ rk3288_crypto_ahash.o +rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG) += rk3288_crypto_trng.o diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c index 9f6ba770a90a..880e4db812a2 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.c +++ b/drivers/crypto/rockchip/rk3288_crypto.c @@ -40,15 +40,18 @@ static const struct rk_variant rk3288_variant = { .num_clks = 4, .rkclks = { { "sclk", 150000000}, - } + }, + .trng = false, }; static const struct rk_variant rk3328_variant = { .num_clks = 3, + .trng = false, }; static const struct rk_variant rk3399_variant = { .num_clks = 3, + .trng = true, }; static int rk_crypto_get_clks(struct rk_crypto_info *dev) @@ -195,6 +198,10 @@ static int rk_crypto_debugfs_show(struct seq_file *seq, void *v) seq_printf(seq, "%s %s requests: %lu\n", dev_driver_string(dd->dev), dev_name(dd->dev), dd->nreq); +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG + seq_printf(seq, "HWRNG: %lu %lu\n", + dd->hwrng_stat_req, dd->hwrng_stat_bytes); +#endif } spin_unlock(&rocklist.lock); @@ -381,6 +388,10 @@ static int rk_crypto_probe(struct platform_device *pdev) dev_err(dev, "Fail to register crypto algorithms"); goto err_register_alg; } +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG + if (crypto_info->variant->trng) + rk3288_hwrng_register(crypto_info); +#endif register_debugfs(crypto_info); } @@ -411,6 +422,11 @@ static int rk_crypto_remove(struct platform_device *pdev) #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG debugfs_remove_recursive(rocklist.dbgfs_dir); #endif +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG + if (crypto_tmp->variant->trng) + rk3288_hwrng_unregister(crypto_tmp); +#endif + rk_crypto_unregister(); } rk_crypto_pm_exit(crypto_tmp); diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h index b2695258cade..016c3b72c19c 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.h +++ b/drivers/crypto/rockchip/rk3288_crypto.h @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/debugfs.h> #include <linux/delay.h> +#include <linux/hw_random.h> #include <linux/pm_runtime.h> #include <linux/scatterlist.h> #include <crypto/engine.h> @@ -183,6 +184,16 @@ #define RK_CRYPTO_HASH_DOUT_6 0x01a4 #define RK_CRYPTO_HASH_DOUT_7 0x01a8 +#define RK_CRYPTO_TRNG_CTRL 0x0200 +#define RK_CRYPTO_OSC_ENABLE BIT(16) +#define RK_CRYPTO_TRNG_DOUT_0 0x0204 +/* sample < 1000 lead to 100% failure on rngtest, + * using more than 1200 does not increase success. + */ +#define RK_CRYPTO_RNG_SAMPLE 1200 + +#define RK_CRYPTO_MAX_TRNG_BYTE 32 + #define CRYPTO_READ(dev, offset) \ readl_relaxed(((dev)->reg + (offset))) #define CRYPTO_WRITE(dev, offset, val) \ @@ -212,6 +223,7 @@ struct rk_clks { struct rk_variant { int num_clks; struct rk_clks rkclks[RK_MAX_CLKS]; + bool trng; }; struct rk_crypto_info { @@ -222,11 +234,15 @@ struct rk_crypto_info { struct reset_control *rst; void __iomem *reg; int irq; + struct mutex lock; + struct hwrng hwrng; const struct rk_variant *variant; unsigned long nreq; struct crypto_engine *engine; struct completion complete; int status; + unsigned long hwrng_stat_req; + unsigned long hwrng_stat_bytes; }; /* the private variable of hash */ @@ -288,3 +304,5 @@ extern struct rk_crypto_tmp rk_ahash_md5; struct rk_crypto_info *get_rk_crypto(void); #endif +int rk3288_hwrng_register(struct rk_crypto_info *rk); +void rk3288_hwrng_unregister(struct rk_crypto_info *rk); diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c index a78ff3dcd0b1..67ed3a54bc7b 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c +++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c @@ -287,6 +287,7 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq) goto theend; } + mutex_lock(&rkc->lock); rk_ahash_reg_init(areq, rkc); while (sg) { @@ -321,6 +322,7 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq) } theend: + mutex_unlock(&rkc->lock); pm_runtime_put_autosuspend(rkc->dev); local_bh_disable(); diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c index 59069457582b..304c2c44fea0 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c @@ -357,6 +357,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req) } } err = 0; + mutex_unlock(&rkc->lock); rk_cipher_hw_init(rkc, areq); if (ivsize) { if (ivsize == DES_BLOCK_SIZE) @@ -372,6 +373,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req) crypto_dma_start(rkc, sgs, sgd, todo / 4); wait_for_completion_interruptible_timeout(&rkc->complete, msecs_to_jiffies(2000)); + mutex_unlock(&rkc->lock); if (!rkc->status) { dev_err(rkc->dev, "DMA timeout\n"); err = -EFAULT; diff --git a/drivers/crypto/rockchip/rk3288_crypto_trng.c b/drivers/crypto/rockchip/rk3288_crypto_trng.c new file mode 100644 index 000000000000..7a0e1300d0e8 --- /dev/null +++ b/drivers/crypto/rockchip/rk3288_crypto_trng.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rk3288_crypto_trng.c - hardware cryptographic offloader for rockchip + * + * Copyright (C) 2022-2023 Corentin Labbe <clabbe@baylibre.com> + * + * This file handle the TRNG + */ +#include "rk3288_crypto.h" +#include <linux/hw_random.h> +#include <linux/iopoll.h> +#include <linux/pm_runtime.h> + +static int rk3288_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) +{ + struct rk_crypto_info *rk; + unsigned int todo; + int err = 0; + int i; + u32 v; + + rk = container_of(hwrng, struct rk_crypto_info, hwrng); + + todo = min_t(size_t, max, RK_CRYPTO_MAX_TRNG_BYTE); + +#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG + rk->hwrng_stat_req++; + rk->hwrng_stat_bytes += todo; +#endif + + err = pm_runtime_resume_and_get(rk->dev); + if (err < 0) + goto err_pm; + + mutex_lock(&rk->lock); + +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + v = RK_CRYPTO_OSC_ENABLE | RK_CRYPTO_RNG_SAMPLE; + CRYPTO_WRITE(rk, RK_CRYPTO_TRNG_CTRL, v); + + v = HIWORD_UPDATE(RK_CRYPTO_TRNG_START, RK_CRYPTO_TRNG_START, 0); + CRYPTO_WRITE(rk, RK_CRYPTO_CTRL, v); + wmb(); + + err = readl_poll_timeout(rk->reg + RK_CRYPTO_CTRL, v, + !(v & RK_CRYPTO_TRNG_START), + 100, 2000); + if (err) { + dev_err(rk->dev, "HWRNG read timeout"); + goto readfail; + } + + for (i = 0; i < todo / 4; i++) { + v = readl(rk->reg + RK_CRYPTO_TRNG_DOUT_0 + i * 4); + put_unaligned_le32(v, data + i * 4); + } + + err = todo; + + v = HIWORD_UPDATE(0, RK_CRYPTO_TRNG_START, 0); + CRYPTO_WRITE(rk, RK_CRYPTO_CTRL, v); + +readfail: + mutex_unlock(&rk->lock); + + pm_runtime_put(rk->dev); + +err_pm: + return err; +} + +int rk3288_hwrng_register(struct rk_crypto_info *rk) +{ + int ret; + + dev_info(rk->dev, "Register TRNG with sample=%d\n", RK_CRYPTO_RNG_SAMPLE); + + rk->hwrng.name = "Rockchip rk3288 TRNG"; + rk->hwrng.read = rk3288_trng_read; + rk->hwrng.quality = 300; + + ret = hwrng_register(&rk->hwrng); + if (ret) + dev_err(rk->dev, "Fail to register the TRNG\n"); + return ret; +} + +void rk3288_hwrng_unregister(struct rk_crypto_info *rk) +{ + hwrng_unregister(&rk->hwrng); +}
The rockchip IP has a TRNG which could be used as a hwrng. Since TRNG is only failling rngtests on rk3328 and does not work on rk3288, the TRNG is enabled only on rk3399 via a variant. But this is not a surprise since when vendor tried to add support for TRNG upstream, rk3288 was not handled, and rk3328 was added "disabled", so I conclude this is a known problem. Anyway the quality of rk3399 TRNG is low, so a dedicated kconfig option is done to not enabled it by default. Signed-off-by: Corentin Labbe <clabbe@baylibre.com> --- Hello All rk3288 compatible crypto IP have a TRNG and supporting it was awaited for some time (https://bugzilla.kernel.org/show_bug.cgi?id=216502) I has some problem with this one, it was the first time I hit so many 100% failure on rngtest. I finally bisected a RNG_SAMPLE value (1200) which lead to "only" 50-70% failure. The calcul of fail rate is done with (FIPS 140-2 successes/FIPS 140-2 failures) of rngtest. Since it is the first time I hit that case, does setting rng_quality to 300 is what to do (using the worst succes rate of 30%) ? But I am really puzzled why vendor default is to use RNG_SAMPLE=100 which is total failure (according to rngtest). Unfortunatly all my try to have more answer from them seems to have been forwarded to /dev/null. Thanks Regards drivers/crypto/Kconfig | 8 ++ drivers/crypto/rockchip/Makefile | 1 + drivers/crypto/rockchip/rk3288_crypto.c | 18 +++- drivers/crypto/rockchip/rk3288_crypto.h | 18 ++++ drivers/crypto/rockchip/rk3288_crypto_ahash.c | 2 + .../crypto/rockchip/rk3288_crypto_skcipher.c | 2 + drivers/crypto/rockchip/rk3288_crypto_trng.c | 92 +++++++++++++++++++ 7 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 drivers/crypto/rockchip/rk3288_crypto_trng.c