MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Niagara2 RNG driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
/* In multi-socket situations, the hypervisor might need to *queueuptheRNGcontrolregisterwriteifit'sforaunit *thatisonacpusocketotherthantheoneweareexecutingon. * *Wepollherewaitingforasuccessfulreadofthatcontrol *registertomakesurethewritehasbeenactuallyperformed.
*/ staticunsignedlong n2rng_control_settle_v2(struct n2rng *np, int unit)
{ unsignedlong ra = __pa(&np->scratch_control[0]);
return n2rng_generic_read_control_v2(ra, unit);
}
staticunsignedlong n2rng_write_ctl_one(struct n2rng *np, int unit, unsignedlong state, unsignedlong control_ra, unsignedlong watchdog_timeout, unsignedlong *ticks)
{ unsignedlong hv_err;
/* Just try to see if we can successfully access the control register *oftheRNGonthedomainonwhichwearecurrentlyexecuting.
*/ staticint n2rng_try_read_ctl(struct n2rng *np)
{ unsignedlong hv_err; unsignedlong x;
if (np->hvapi_major == 1) {
hv_err = sun4v_rng_get_diag_ctl();
} else { /* We purposefully give invalid arguments, HV_NOACCESS *ishigherprioritythantheerrorswe'dgetfrom *theseothercases,andthat'stheerrorweare *trulyinterestedin.
*/
hv_err = sun4v_rng_ctl_read_v2(0UL, ~0UL, &x, &x, &x, &x); switch (hv_err) { case HV_EWOULDBLOCK: case HV_ENOACCESS: break; default:
hv_err = HV_EOK; break;
}
}
return n2rng_hv_err_trans(hv_err);
}
static u64 n2rng_control_default(struct n2rng *np, int ctl)
{
u64 val = 0;
if (np->data->chip_version == 1) {
val = ((2 << RNG_v1_CTL_ASEL_SHIFT) |
(N2RNG_ACCUM_CYCLES_DEFAULT << RNG_v1_CTL_WAIT_SHIFT) |
RNG_CTL_LFSR);
staticint n2rng_grab_diag_control(struct n2rng *np)
{ int i, busy_count, err = -ENODEV;
busy_count = 0; for (i = 0; i < 100; i++) {
err = n2rng_try_read_ctl(np); if (err != -EAGAIN) break;
if (++busy_count > 100) {
dev_err(&np->op->dev, "Grab diag control timeout.\n"); return -ENODEV;
}
udelay(1);
}
return err;
}
staticint n2rng_init_control(struct n2rng *np)
{ int err = n2rng_grab_diag_control(np);
/* Not in the control domain, that's OK we are only a consumer *oftheRNGdata,wedon'tsetupandprogramit.
*/ if (err == -EPERM) return0; if (err) return err;
if (!(np->flags & N2RNG_FLAG_READY)) {
len = 0;
} elseif (np->flags & N2RNG_FLAG_BUFFER_VALID) {
np->flags &= ~N2RNG_FLAG_BUFFER_VALID;
*data = np->buffer;
len = 4;
} else { int err = n2rng_generic_read_data(ra); if (!err) {
np->flags |= N2RNG_FLAG_BUFFER_VALID;
np->buffer = np->test_data >> 32;
*data = np->test_data & 0xffffffff;
len = 4;
} else {
dev_err(&np->op->dev, "RNG error, retesting\n");
np->flags &= ~N2RNG_FLAG_READY; if (!(np->flags & N2RNG_FLAG_SHUTDOWN))
schedule_delayed_work(&np->work, 0);
len = 0;
}
}
return len;
}
/* On a guest node, just make sure we can read random data properly. *Ifacontrolnoderebootsorreloadsit'sn2rngdriver,thiswon't *workduringthattime.Sowehavetokeepprobinguntilthedevice *becomesusable.
*/ staticint n2rng_guest_check(struct n2rng *np)
{ unsignedlong ra = __pa(&np->test_data);
switch (np->data->id) { case N2_n2_rng: case N2_vf_rng: case N2_kt_rng: case N2_m4_rng: /* yes, m4 uses the old value */
val = RNG_v1_SELFTEST_VAL; break; default:
val = RNG_v2_SELFTEST_VAL; break;
}
matches = 0; for (limit = 0; limit < SELFTEST_LOOPS_MAX; limit++) {
matches += n2rng_test_buffer_find(np, val); if (matches >= SELFTEST_MATCH_GOAL) break;
val = advance_polynomial(SELFTEST_POLY, val, 1);
}
err = 0; if (limit >= SELFTEST_LOOPS_MAX) {
err = -ENODEV;
dev_err(&np->op->dev, "Selftest failed on unit %lu\n", unit);
n2rng_dump_test_buffer(np);
} else
dev_info(&np->op->dev, "Selftest passed on unit %lu\n", unit);
err = n2rng_entropy_diag_read(np, unit, np->test_control,
HV_RNG_STATE_HEALTHCHECK,
np->test_buffer, sizeof(np->test_buffer),
&np->units[unit].control[0],
np->hv_state); if (err) return err;
return n2rng_check_selftest_buffer(np, unit);
}
staticint n2rng_control_check(struct n2rng *np)
{ int i;
for (i = 0; i < np->num_units; i++) { int err = n2rng_control_selftest(np, i); if (err) return err;
} return0;
}
/* The sanity checks passed, install the final configuration into the *chip,it'sreadytouse.
*/ staticint n2rng_control_configure_units(struct n2rng *np)
{ int unit, err;
err = 0; for (unit = 0; unit < np->num_units; unit++) { struct n2rng_unit *up = &np->units[unit]; unsignedlong ctl_ra = __pa(&up->control[0]); int esrc;
u64 base, shift;
/* XXX This isn't the best. We should fetch a bunch *XXXofwordsusingeachentropysourcecombinedXXX *witheachVCOsetting,andseewhichcombinations *XXXgivethebestrandomdata.
*/ for (esrc = 0; esrc < 3; esrc++)
up->control[esrc] = base |
(esrc << shift) |
(RNG_CTL_ES1 << esrc);
up->control[3] = base |
(RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3);
err = n2rng_generic_write_control(np, ctl_ra, unit,
HV_RNG_STATE_CONFIGURED); if (err) break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.