Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwrng: bcm2835 - Fix hwrng throughput regression

The last RCU stall fix caused a massive throughput regression of the
hwrng on Raspberry Pi 0 - 3. hwrng_msleep doesn't sleep precisely enough
and usleep_range doesn't allow scheduling. So try to restore the
best possible throughput by introducing hwrng_yield which interruptable
sleeps for one jiffy.

Some performance measurements on Raspberry Pi 3B+ (arm64/defconfig):

sudo dd if=/dev/hwrng of=/dev/null count=1 bs=10000

cpu_relax ~138025 Bytes / sec
hwrng_msleep(1000) ~13 Bytes / sec
hwrng_yield ~2510 Bytes / sec

Fixes: 96cb9d055445 ("hwrng: bcm2835 - use hwrng_msleep() instead of cpu_relax()")
Link: https://lore.kernel.org/linux-arm-kernel/bc97ece5-44a3-4c4e-77da-2db3eb66b128@gmx.net/
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Stefan Wahren and committed by
Herbert Xu
b58a3600 c9779501

+8 -1
+1 -1
drivers/char/hw_random/bcm2835-rng.c
··· 70 70 while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) { 71 71 if (!wait) 72 72 return 0; 73 - hwrng_msleep(rng, 1000); 73 + hwrng_yield(rng); 74 74 } 75 75 76 76 num_words = rng_readl(priv, RNG_STATUS) >> 24;
+6
drivers/char/hw_random/core.c
··· 678 678 } 679 679 EXPORT_SYMBOL_GPL(hwrng_msleep); 680 680 681 + long hwrng_yield(struct hwrng *rng) 682 + { 683 + return wait_for_completion_interruptible_timeout(&rng->dying, 1); 684 + } 685 + EXPORT_SYMBOL_GPL(hwrng_yield); 686 + 681 687 static int __init hwrng_modinit(void) 682 688 { 683 689 int ret;
+1
include/linux/hw_random.h
··· 63 63 extern void devm_hwrng_unregister(struct device *dve, struct hwrng *rng); 64 64 65 65 extern long hwrng_msleep(struct hwrng *rng, unsigned int msecs); 66 + extern long hwrng_yield(struct hwrng *rng); 66 67 67 68 #endif /* LINUX_HWRANDOM_H_ */