drivers/char/hw_random/xgene-rng.c

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

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/xgene-rng.c
Extension
.c
Size
10764 bytes
Lines
389
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 xgene_rng_dev {
	u32 irq;
	void  __iomem *csr_base;
	u32 revision;
	u32 datum_size;
	u32 failure_cnt;	/* Failure count last minute */
	unsigned long failure_ts;/* First failure timestamp */
	struct timer_list failure_timer;
	struct device *dev;
};

static void xgene_rng_expired_timer(struct timer_list *t)
{
	struct xgene_rng_dev *ctx = timer_container_of(ctx, t, failure_timer);

	/* Clear failure counter as timer expired */
	disable_irq(ctx->irq);
	ctx->failure_cnt = 0;
	timer_delete(&ctx->failure_timer);
	enable_irq(ctx->irq);
}

static void xgene_rng_start_timer(struct xgene_rng_dev *ctx)
{
	ctx->failure_timer.expires = jiffies + 120 * HZ;
	add_timer(&ctx->failure_timer);
}

/*
 * Initialize or reinit free running oscillators (FROs)
 */
static void xgene_rng_init_fro(struct xgene_rng_dev *ctx, u32 fro_val)
{
	writel(fro_val, ctx->csr_base + RNG_FRODETUNE);
	writel(0x00000000, ctx->csr_base + RNG_ALARMMASK);
	writel(0x00000000, ctx->csr_base + RNG_ALARMSTOP);
	writel(0xFFFFFFFF, ctx->csr_base + RNG_FROENABLE);
}

static void xgene_rng_chk_overflow(struct xgene_rng_dev *ctx)
{
	u32 val;

	val = readl(ctx->csr_base + RNG_INTR_STS_ACK);
	if (val & MONOBIT_FAIL_MASK)
		/*
		 * LFSR detected an out-of-bounds number of 1s after
		 * checking 20,000 bits (test T1 as specified in the
		 * AIS-31 standard)
		 */
		dev_err(ctx->dev, "test monobit failure error 0x%08X\n", val);
	if (val & POKER_FAIL_MASK)
		/*
		 * LFSR detected an out-of-bounds value in at least one
		 * of the 16 poker_count_X counters or an out of bounds sum
		 * of squares value after checking 20,000 bits (test T2 as
		 * specified in the AIS-31 standard)
		 */
		dev_err(ctx->dev, "test poker failure error 0x%08X\n", val);
	if (val & LONG_RUN_FAIL_MASK)
		/*
		 * LFSR detected a sequence of 34 identical bits
		 * (test T4 as specified in the AIS-31 standard)
		 */
		dev_err(ctx->dev, "test long run failure error 0x%08X\n", val);
	if (val & RUN_FAIL_MASK)
		/*
		 * LFSR detected an outof-bounds value for at least one
		 * of the running counters after checking 20,000 bits
		 * (test T3 as specified in the AIS-31 standard)
		 */
		dev_err(ctx->dev, "test run failure error 0x%08X\n", val);
	if (val & NOISE_FAIL_MASK)
		/* LFSR detected a sequence of 48 identical bits */
		dev_err(ctx->dev, "noise failure error 0x%08X\n", val);
	if (val & STUCK_OUT_MASK)
		/*
		 * Detected output data registers generated same value twice
		 * in a row
		 */
		dev_err(ctx->dev, "stuck out failure error 0x%08X\n", val);

	if (val & SHUTDOWN_OFLO_MASK) {
		u32 frostopped;

		/* FROs shut down after a second error event. Try recover. */
		if (++ctx->failure_cnt == 1) {
			/* 1st time, just recover */
			ctx->failure_ts = jiffies;
			frostopped = readl(ctx->csr_base + RNG_ALARMSTOP);

Annotation

Implementation Notes