Skip to content

Commit

Permalink
hwrng: bcm2835 - sleep more intelligently
Browse files Browse the repository at this point in the history
While waiting for random data, use sleeps that are proportional
to the amount of data expected. Prevent indefinite waits by
giving up if nothing is received for a second.

See: #5390

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
  • Loading branch information
pelwell committed Mar 27, 2023
1 parent f9c90df commit 6a825ed
Showing 1 changed file with 14 additions and 6 deletions.
20 changes: 14 additions & 6 deletions drivers/char/hw_random/bcm2835-rng.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/printk.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/delay.h>

#define RNG_CTRL 0x0
#define RNG_STATUS 0x4
Expand All @@ -28,6 +29,9 @@

#define RNG_INT_OFF 0x1

#define RNG_FIFO_WORDS 4
#define RNG_US_PER_WORD 34 /* Tuned for throughput */

struct bcm2835_rng_priv {
struct hwrng rng;
void __iomem *base;
Expand Down Expand Up @@ -64,19 +68,23 @@ static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val,
static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max,
bool wait)
{
u32 retries = 1000000/(RNG_FIFO_WORDS * RNG_US_PER_WORD);
struct bcm2835_rng_priv *priv = to_rng_priv(rng);
u32 max_words = max / sizeof(u32);
u32 num_words, count;

while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) {
if (!wait)
num_words = rng_readl(priv, RNG_STATUS) >> 24;

while (!num_words) {
if (!wait || !retries)
return 0;
hwrng_msleep(rng, 1000);
retries--;
usleep_range((u32)RNG_US_PER_WORD,
(u32)RNG_US_PER_WORD * RNG_FIFO_WORDS);
num_words = rng_readl(priv, RNG_STATUS) >> 24;
}

num_words = rng_readl(priv, RNG_STATUS) >> 24;
if (num_words > max_words)
num_words = max_words;
num_words = min(num_words, max_words);

for (count = 0; count < num_words; count++)
((u32 *)buf)[count] = rng_readl(priv, RNG_DATA);
Expand Down

0 comments on commit 6a825ed

Please sign in to comment.