Commit 6d01d851 authored by Alexander Sverdlin's avatar Alexander Sverdlin Committed by Herbert Xu
Browse files

hwrng: ks-sa - Add minimum sleep time before ready-polling



Current polling timeout is 25 us. The hardware is currently configured to
harvest the entropy for 81920 us. This leads to timeouts even during
blocking read (wait=1).

Log snippet:
[    5.727589] [<c040ffcc>] (ks_sa_rng_probe) from [<c04181e8>] (platform_drv_probe+0x58/0xb4)
...
[    5.727805] hwrng: no data available
...
[   13.157016] random: systemd: uninitialized urandom read (16 bytes read)
[   13.157033] systemd[1]: Initializing machine ID from random generator.
...
[   15.848770] random: fast init done
...
[   15.848807] random: crng init done

After the patch:
[    6.223534] random: systemd: uninitialized urandom read (16 bytes read)
[    6.223551] systemd[1]: Initializing machine ID from random generator.
...
[    6.876075] random: fast init done
...
[    6.954200] random: systemd: uninitialized urandom read (16 bytes read)
[    6.955244] random: systemd: uninitialized urandom read (16 bytes read)
...
[    7.121948] random: crng init done

Signed-off-by: default avatarAlexander Sverdlin <alexander.sverdlin@nokia.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 698b2227
Loading
Loading
Loading
Loading
+38 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/timekeeping.h>


#define SA_CMD_STATUS_OFS			0x8
#define SA_CMD_STATUS_OFS			0x8


@@ -85,13 +86,36 @@ struct ks_sa_rng {
	struct clk	*clk;
	struct clk	*clk;
	struct regmap	*regmap_cfg;
	struct regmap	*regmap_cfg;
	struct trng_regs __iomem *reg_rng;
	struct trng_regs __iomem *reg_rng;
	u64 ready_ts;
	unsigned int refill_delay_ns;
};
};


static unsigned int cycles_to_ns(unsigned long clk_rate, unsigned int cycles)
{
	return DIV_ROUND_UP_ULL((TRNG_DEF_CLK_DIV_CYCLES + 1) * 1000000000ull *
				cycles, clk_rate);
}

static unsigned int startup_delay_ns(unsigned long clk_rate)
{
	if (!TRNG_DEF_STARTUP_CYCLES)
		return cycles_to_ns(clk_rate, BIT(24));
	return cycles_to_ns(clk_rate, 256 * TRNG_DEF_STARTUP_CYCLES);
}

static unsigned int refill_delay_ns(unsigned long clk_rate)
{
	if (!TRNG_DEF_MAX_REFILL_CYCLES)
		return cycles_to_ns(clk_rate, BIT(24));
	return cycles_to_ns(clk_rate, 256 * TRNG_DEF_MAX_REFILL_CYCLES);
}

static int ks_sa_rng_init(struct hwrng *rng)
static int ks_sa_rng_init(struct hwrng *rng)
{
{
	u32 value;
	u32 value;
	struct device *dev = (struct device *)rng->priv;
	struct device *dev = (struct device *)rng->priv;
	struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
	struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
	unsigned long clk_rate = clk_get_rate(ks_sa_rng->clk);


	/* Enable RNG module */
	/* Enable RNG module */
	regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
	regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
@@ -120,6 +144,10 @@ static int ks_sa_rng_init(struct hwrng *rng)
	value |= TRNG_CNTL_REG_TRNG_ENABLE;
	value |= TRNG_CNTL_REG_TRNG_ENABLE;
	writel(value, &ks_sa_rng->reg_rng->control);
	writel(value, &ks_sa_rng->reg_rng->control);


	ks_sa_rng->refill_delay_ns = refill_delay_ns(clk_rate);
	ks_sa_rng->ready_ts = ktime_get_ns() +
			      startup_delay_ns(clk_rate);

	return 0;
	return 0;
}
}


@@ -144,6 +172,7 @@ static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)
	data[1] = readl(&ks_sa_rng->reg_rng->output_h);
	data[1] = readl(&ks_sa_rng->reg_rng->output_h);


	writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);
	writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);
	ks_sa_rng->ready_ts = ktime_get_ns() + ks_sa_rng->refill_delay_ns;


	return sizeof(u32) * 2;
	return sizeof(u32) * 2;
}
}
@@ -152,10 +181,19 @@ static int ks_sa_rng_data_present(struct hwrng *rng, int wait)
{
{
	struct device *dev = (struct device *)rng->priv;
	struct device *dev = (struct device *)rng->priv;
	struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
	struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
	u64 now = ktime_get_ns();


	u32	ready;
	u32	ready;
	int	j;
	int	j;


	if (wait && now < ks_sa_rng->ready_ts) {
		/* Max delay expected here is 81920000 ns */
		unsigned long min_delay =
			DIV_ROUND_UP((u32)(ks_sa_rng->ready_ts - now), 1000);

		usleep_range(min_delay, min_delay + SA_RNG_DATA_RETRY_DELAY);
	}

	for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {
	for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {
		ready = readl(&ks_sa_rng->reg_rng->status);
		ready = readl(&ks_sa_rng->reg_rng->status);
		ready &= TRNG_STATUS_REG_READY;
		ready &= TRNG_STATUS_REG_READY;