コード例 #1
0
ファイル: exynos-rng.c プロジェクト: AK101111/linux
static int exynos_read(struct hwrng *rng, void *buf,
					size_t max, bool wait)
{
	struct exynos_rng *exynos_rng = container_of(rng,
						struct exynos_rng, rng);
	u32 *data = buf;
	int retry = 100;
	int ret = 4;

	pm_runtime_get_sync(exynos_rng->dev);

	exynos_rng_writel(exynos_rng, PRNG_START, 0);

	while (!(exynos_rng_readl(exynos_rng,
			EXYNOS_PRNG_STATUS_OFFSET) & PRNG_DONE) && --retry)
		cpu_relax();
	if (!retry) {
		ret = -ETIMEDOUT;
		goto out;
	}

	exynos_rng_writel(exynos_rng, PRNG_DONE, EXYNOS_PRNG_STATUS_OFFSET);

	*data = exynos_rng_readl(exynos_rng, EXYNOS_PRNG_OUT1_OFFSET);

out:
	pm_runtime_mark_last_busy(exynos_rng->dev);
	pm_runtime_put_sync_autosuspend(exynos_rng->dev);

	return ret;
}
コード例 #2
0
ファイル: exynos-rng.c プロジェクト: AlexShiLucky/linux
static int exynos_rng_set_seed(struct exynos_rng_dev *rng,
			       const u8 *seed, unsigned int slen)
{
	u32 val;
	int i;

	/* Round seed length because loop iterates over full register size */
	slen = ALIGN_DOWN(slen, 4);

	if (slen < EXYNOS_RNG_SEED_SIZE)
		return -EINVAL;

	for (i = 0; i < slen ; i += 4) {
		unsigned int seed_reg = (i / 4) % EXYNOS_RNG_SEED_REGS;

		val = seed[i] << 24;
		val |= seed[i + 1] << 16;
		val |= seed[i + 2] << 8;
		val |= seed[i + 3] << 0;

		exynos_rng_writel(rng, val, EXYNOS_RNG_SEED(seed_reg));
	}

	val = exynos_rng_readl(rng, EXYNOS_RNG_STATUS);
	if (!(val & EXYNOS_RNG_STATUS_SEED_SETTING_DONE)) {
		dev_warn(rng->dev, "Seed setting not finished\n");
		return -EIO;
	}

	rng->last_seeding = jiffies;
	rng->bytes_seeding = 0;

	return 0;
}
コード例 #3
0
ファイル: exynos-rng.c プロジェクト: AlexShiLucky/linux
/*
 * Start the engine and poll for finish.  Then read from output registers
 * filling the 'dst' buffer up to 'dlen' bytes or up to size of generated
 * random data (EXYNOS_RNG_SEED_SIZE).
 *
 * On success: return 0 and store number of read bytes under 'read' address.
 * On error: return -ERRNO.
 */
static int exynos_rng_get_random(struct exynos_rng_dev *rng,
				 u8 *dst, unsigned int dlen,
				 unsigned int *read)
{
	int retry = EXYNOS_RNG_WAIT_RETRIES;

	if (rng->type == EXYNOS_PRNG_EXYNOS4) {
		exynos_rng_writel(rng, EXYNOS_RNG_CONTROL_START,
				  EXYNOS_RNG_CONTROL);
	} else if (rng->type == EXYNOS_PRNG_EXYNOS5) {
		exynos_rng_writel(rng, EXYNOS_RNG_GEN_PRNG,
				  EXYNOS_RNG_SEED_CONF);
	}

	while (!(exynos_rng_readl(rng,
			EXYNOS_RNG_STATUS) & EXYNOS_RNG_STATUS_RNG_DONE) && --retry)
		cpu_relax();

	if (!retry)
		return -ETIMEDOUT;

	/* Clear status bit */
	exynos_rng_writel(rng, EXYNOS_RNG_STATUS_RNG_DONE,
			  EXYNOS_RNG_STATUS);
	*read = min_t(size_t, dlen, EXYNOS_RNG_SEED_SIZE);
	memcpy_fromio(dst, rng->mem + EXYNOS_RNG_OUT_BASE, *read);
	rng->bytes_seeding += *read;

	return 0;
}
コード例 #4
0
ファイル: exynos-rng.c プロジェクト: AK101111/linux
static int exynos_rng_configure(struct exynos_rng *exynos_rng)
{
	int i;
	int ret = 0;

	for (i = 0 ; i < 5 ; i++)
		exynos_rng_writel(exynos_rng, jiffies,
				EXYNOS_PRNG_SEED_OFFSET + 4*i);

	if (!(exynos_rng_readl(exynos_rng, EXYNOS_PRNG_STATUS_OFFSET)
						 & SEED_SETTING_DONE))
		ret = -EIO;

	return ret;
}