drivers/char/hw_random/stm32-rng.c

Source file repositories/reference/linux-study-clean/drivers/char/hw_random/stm32-rng.c

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/stm32-rng.c
Extension
.c
Size
16203 bytes
Lines
613
Domain
Driver Families
Bucket
drivers/char
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct stm32_rng_data {
	uint	max_clock_rate;
	uint	nb_clock;
	u32	cr;
	u32	nscr;
	u32	htcr;
	bool	has_cond_reset;
};

/**
 * struct stm32_rng_config - RNG configuration data
 *
 * @cr:			RNG configuration. 0 means default hardware RNG configuration
 * @nscr:		Noise sources control configuration.
 * @htcr:		Health tests configuration.
 */
struct stm32_rng_config {
	u32 cr;
	u32 nscr;
	u32 htcr;
};

struct stm32_rng_private {
	struct hwrng rng;
	struct device *dev;
	void __iomem *base;
	struct clk_bulk_data *clk_bulk;
	struct reset_control *rst;
	struct stm32_rng_config pm_conf;
	const struct stm32_rng_data *data;
	bool ced;
	bool lock_conf;
};

/*
 * Extracts from the STM32 RNG specification when RNG supports CONDRST.
 *
 * When a noise source (or seed) error occurs, the RNG stops generating
 * random numbers and sets to “1” both SEIS and SECS bits to indicate
 * that a seed error occurred. (...)
 *
 * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
 * description for details). This step is needed only if SECS is set.
 * Indeed, when SEIS is set and SECS is cleared it means RNG performed
 * the reset automatically (auto-reset).
 * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
 * to be cleared in the RNG_CR register, then confirm that SEIS is
 * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
 * the RNG_SR register.
 * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
 * cleared by RNG. The random number generation is now back to normal.
 */
static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_private *priv)
{
	struct device *dev = priv->dev;
	u32 sr = readl_relaxed(priv->base + RNG_SR);
	u32 cr = readl_relaxed(priv->base + RNG_CR);
	int err;

	if (sr & RNG_SR_SECS) {
		/* Conceal by resetting the subsystem (step 1.) */
		writel_relaxed(cr | RNG_CR_CONDRST, priv->base + RNG_CR);
		writel_relaxed(cr & ~RNG_CR_CONDRST, priv->base + RNG_CR);
	} else {
		/* RNG auto-reset (step 2.) */
		writel_relaxed(sr & ~RNG_SR_SEIS, priv->base + RNG_SR);
		goto end;
	}

	err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_CR, cr, !(cr & RNG_CR_CONDRST), 10,
						100000);
	if (err) {
		dev_err(dev, "%s: timeout %x\n", __func__, sr);
		return err;
	}

	/* Check SEIS is cleared (step 2.) */
	if (readl_relaxed(priv->base + RNG_SR) & RNG_SR_SEIS)
		return -EINVAL;

	err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 10,
						100000);
	if (err) {
		dev_err(dev, "%s: timeout %x\n", __func__, sr);
		return err;
	}

end:
	return 0;
}

Annotation

Implementation Notes