drivers/char/hw_random/n2-drv.c

Source file repositories/reference/linux-study-clean/drivers/char/hw_random/n2-drv.c

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/n2-drv.c
Extension
.c
Size
20682 bytes
Lines
865
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

if (hv_err == HV_EBUSY) {
			if (++busy >= N2RNG_BUSY_LIMIT)
				break;

			udelay(1);
		} else if (hv_err == HV_EWOULDBLOCK) {
			if (++block >= N2RNG_BLOCK_LIMIT)
				break;

			__delay(ticks);
		} else
			break;
	}

	return hv_err;
}

/* In multi-socket situations, the hypervisor might need to
 * queue up the RNG control register write if it's for a unit
 * that is on a cpu socket other than the one we are executing on.
 *
 * We poll here waiting for a successful read of that control
 * register to make sure the write has been actually performed.
 */
static unsigned long n2rng_control_settle_v2(struct n2rng *np, int unit)
{
	unsigned long ra = __pa(&np->scratch_control[0]);

	return n2rng_generic_read_control_v2(ra, unit);
}

static unsigned long n2rng_write_ctl_one(struct n2rng *np, int unit,
					 unsigned long state,
					 unsigned long control_ra,
					 unsigned long watchdog_timeout,
					 unsigned long *ticks)
{
	unsigned long hv_err;

	if (np->hvapi_major == 1) {
		hv_err = sun4v_rng_ctl_write_v1(control_ra, state,
						watchdog_timeout, ticks);
	} else {
		hv_err = sun4v_rng_ctl_write_v2(control_ra, state,
						watchdog_timeout, unit);
		if (hv_err == HV_EOK)
			hv_err = n2rng_control_settle_v2(np, unit);
		*ticks = N2RNG_ACCUM_CYCLES_DEFAULT;
	}

	return hv_err;
}

static int n2rng_generic_read_data(unsigned long data_ra)
{
	unsigned long ticks, hv_err;
	int block = 0, hcheck = 0;

	while (1) {
		hv_err = sun4v_rng_data_read(data_ra, &ticks);
		if (hv_err == HV_EOK)
			return 0;

		if (hv_err == HV_EWOULDBLOCK) {
			if (++block >= N2RNG_BLOCK_LIMIT)
				return -EWOULDBLOCK;
			__delay(ticks);
		} else if (hv_err == HV_ENOACCESS) {
			return -EPERM;
		} else if (hv_err == HV_EIO) {
			if (++hcheck >= N2RNG_HCHECK_LIMIT)
				return -EIO;
			udelay(10000);
		} else
			return -ENODEV;
	}
}

static unsigned long n2rng_read_diag_data_one(struct n2rng *np,
					      unsigned long unit,
					      unsigned long data_ra,
					      unsigned long data_len,
					      unsigned long *ticks)
{
	unsigned long hv_err;

	if (np->hvapi_major == 1) {
		hv_err = sun4v_rng_data_read_diag_v1(data_ra, data_len, ticks);
	} else {
		hv_err = sun4v_rng_data_read_diag_v2(data_ra, data_len,

Annotation

Implementation Notes