n2rng_entp_setup.c revision 741c280d5486676df48cd5d5e8ed8d92eac714a8
fec509a05ddbf645268fe2e537314def7d1b67c8gm * CDDL HEADER START
fec509a05ddbf645268fe2e537314def7d1b67c8gm * The contents of this file are subject to the terms of the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Common Development and Distribution License (the "License").
fec509a05ddbf645268fe2e537314def7d1b67c8gm * You may not use this file except in compliance with the License.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fec509a05ddbf645268fe2e537314def7d1b67c8gm * See the License for the specific language governing permissions
fec509a05ddbf645268fe2e537314def7d1b67c8gm * and limitations under the License.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * When distributing Covered Code, include this CDDL HEADER in each
fec509a05ddbf645268fe2e537314def7d1b67c8gm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * If applicable, add the following below this CDDL HEADER, with the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * fields enclosed by brackets "[]" replaced with your own identifying
fec509a05ddbf645268fe2e537314def7d1b67c8gm * information: Portions Copyright [yyyy] [name of copyright owner]
fec509a05ddbf645268fe2e537314def7d1b67c8gm * CDDL HEADER END
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Use is subject to license terms.
fec509a05ddbf645268fe2e537314def7d1b67c8gm#pragma ident "%Z%%M% %I% %E% SMI"
fec509a05ddbf645268fe2e537314def7d1b67c8gm * There are 3 noise cells each with its own oscillator, and each
fec509a05ddbf645268fe2e537314def7d1b67c8gm * oscillator can be set to 4 different bias setttings. The bias
fec509a05ddbf645268fe2e537314def7d1b67c8gm * setting controls the nominal frequency of the oscillator. The 3
fec509a05ddbf645268fe2e537314def7d1b67c8gm * and 4 and hardcoded throughout this file.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Policy settings
fec509a05ddbf645268fe2e537314def7d1b67c8gm/* Log2 of the number of bits */
fec509a05ddbf645268fe2e537314def7d1b67c8gm * There is a hardware bug that causes the RNG_DATA register to
fec509a05ddbf645268fe2e537314def7d1b67c8gm * occasionally be read one cycle before the specifed time.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * LOGIC_TEST_EXPECTED_M1 is the value one cycle before
fec509a05ddbf645268fe2e537314def7d1b67c8gm * LOGIC_TEST_CYCLES. And there is a second bug that causes the read
fec509a05ddbf645268fe2e537314def7d1b67c8gm * to be delayed. We have seen delays of about 150 cycles, but do not
fec509a05ddbf645268fe2e537314def7d1b67c8gm * know that maximum that could possibly occur.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * We collect LOGIC_TEST_WORDS words using a diagnostic read with all
fec509a05ddbf645268fe2e537314def7d1b67c8gm * entropy turned off. The first one we skip, becuase we have no
fec509a05ddbf645268fe2e537314def7d1b67c8gm * knowledge of the time since the last read. We check that the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * remaining values fall in the window of values that should occur
fec509a05ddbf645268fe2e537314def7d1b67c8gm * between LOGIC_TEST_CYCLES - 1 and LOGIC_TEST_CYCLES +
fec509a05ddbf645268fe2e537314def7d1b67c8gm * LOGIC_TEST_BUG_MAX. As further protecion against false positives,
fec509a05ddbf645268fe2e537314def7d1b67c8gm * we report success if the the number of mismatches does not exceed
fec509a05ddbf645268fe2e537314def7d1b67c8gm * LOGIC_TEST_ERRORS_ALLOWED.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * When running on maramba systems, delays as high as 20000 were observed
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * LOGIC_TEST_BUG_MAX was increased to twice this observed value since all
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * that matters is that the hardware is indeed generating the expected values
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * in diag mode. The code was also modified to exit as soon as the required
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * number of matches is detected.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_WORDS 8 /* includes first one, unused */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_MATCHES_NEEDED (LOGIC_TEST_WORDS - 1 - \
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define ENTDIVISOR (((1ULL << LOG_VAL_SCALE) + 500ULL) / 1000ULL)
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define ENCODEBIAS(osc, bias) (((bias) & 0x3) << (2 * (osc)))
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define EXTRACTBIAS(blob, osc) (((blob) >> (2 * (osc))) & 0x3)
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Each value is a representation of the polynomail bit_i * x^i, where
fec509a05ddbf645268fe2e537314def7d1b67c8gm * i=0 corresponds to the least significant bit of the word. The
fec509a05ddbf645268fe2e537314def7d1b67c8gm * modulus polynomial is x^64 + the interpretation of poly. Out is
fec509a05ddbf645268fe2e537314def7d1b67c8gm * set to in * x^exp mod moduluspolynomial. This corresponds to
fec509a05ddbf645268fe2e537314def7d1b67c8gm * running the LFSR exp cycles. This implemenation directly simulates
fec509a05ddbf645268fe2e537314def7d1b67c8gm * the lfsr. It's running time is O(exp), but the constant is small.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * (This code was taken verbatim from Legion.)
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void
fec509a05ddbf645268fe2e537314def7d1b67c8gmlfsr64_adv_seq(uint64_t poly, uint64_t in, uint64_t exp, uint64_t *out)
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < exp; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke {0, 0, 0, 0, 0, 0, 0, 0};
fec509a05ddbf645268fe2e537314def7d1b67c8gm * This test runs the RNG with no entropy for
fec509a05ddbf645268fe2e537314def7d1b67c8gm * LOGIC_TEST_CYCLES cycles. Ideally the value would be be
fec509a05ddbf645268fe2e537314def7d1b67c8gm * LOGIC_TEST_RESULT, but because of the RNG bug, the actual
fec509a05ddbf645268fe2e537314def7d1b67c8gm * register read may be delayed by upto LOGIC_TEST_BUG_MAX
fec509a05ddbf645268fe2e537314def7d1b67c8gm * cycles. So we simulate over that window, and a match
fec509a05ddbf645268fe2e537314def7d1b67c8gm * occurs, we report success.
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[3].fields.rnc_cnt = LOGIC_TEST_CYCLES - 2;
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* read LOGIC_TEST_WORDS 64-bit words */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_diag_bits(n2rng, rngid, &logictest, buffer,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: n2rng_collect_diag_bits failed with "
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i <= LOGIC_TEST_BUG_MAX; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* exit loop if we have already found enough matches */
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* advance reg by one step */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: logic error on rng(%d), only %d "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < LOGIC_TEST_WORDS; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG3(n2rng, DHEALTH, "buffer[%d] %016llx, cycles = %d",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG3(n2rng, DHEALTH, "n2rng: rng(%d) logic test passed, "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < LOGIC_TEST_WORDS; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG3(n2rng, DCHATTY, "buffer[%d] %016llx, cycles = %d",
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (0);
fec509a05ddbf645268fe2e537314def7d1b67c8gm * gets the metric for the specified state.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_collect_metrics(n2rng_t *n2rng, int rngid, n2rng_setup_t *setupp,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_diag_bits(n2rng, rngid, setupp, buffer, bufsize,
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Fills in table with the performance of each oscillator at each
fec509a05ddbf645268fe2e537314def7d1b67c8gm * bias setting. A particular datum goes in table[osc][bias].
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkecollect_rng_perf(n2rng_t *n2rng, int rngid, n2rng_osc_perf_table_t ptable)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm * The following 2 functions test the performance of each noise cell
fec509a05ddbf645268fe2e537314def7d1b67c8gm * and select the bias settings. They implement the following
fec509a05ddbf645268fe2e537314def7d1b67c8gm * policies:
fec509a05ddbf645268fe2e537314def7d1b67c8gm * 1. No two cells may be set to the same bias. (Cells with the same bias,
fec509a05ddbf645268fe2e537314def7d1b67c8gm * which controls frequency, may beat together, with long
fec509a05ddbf645268fe2e537314def7d1b67c8gm * runs of no entropy as a pair when they are nearly synchronized.)
fec509a05ddbf645268fe2e537314def7d1b67c8gm * 2. The entropy of each cell is determined (for now) by the Renyi H2
fec509a05ddbf645268fe2e537314def7d1b67c8gm * entropy of a collection of samples of raw bits.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * 3. The selected configuration is the one that has the largest total
fec509a05ddbf645268fe2e537314def7d1b67c8gm * entropy, computed as stated above.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * 4. The delay is hard coded.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Finds the preferred configuration from perf data. Sets the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * preferred configuration in the n2rng structure.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = collect_rng_perf(n2rng, rngid, rng->n_perftable);
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm * bset is the bias setting of all 3 oscillators packed into a
fec509a05ddbf645268fe2e537314def7d1b67c8gm * word, 2 bits for each: b2:b1:b0. First we set up an
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * arbitrary assignment, because in an earlier version of
fec509a05ddbf645268fe2e537314def7d1b67c8gm * this code, there were cases where the assignment would
fec509a05ddbf645268fe2e537314def7d1b67c8gm * never happen. Also, that way we don't need to prove
fec509a05ddbf645268fe2e537314def7d1b67c8gm * assignment to prove we never have uninitalized variables,
fec509a05ddbf645268fe2e537314def7d1b67c8gm * and hence it might avoid lint warnings.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * This block of code picks the "best" setting of the biases,
fec509a05ddbf645268fe2e537314def7d1b67c8gm * where "best" is defined by the rules in the big comment
fec509a05ddbf645268fe2e537314def7d1b67c8gm * block above.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * There are only 24 possible combinations such that no two
fec509a05ddbf645268fe2e537314def7d1b67c8gm * oscillators get the same bias. We just do a brute force
fec509a05ddbf645268fe2e537314def7d1b67c8gm * exhaustive search of the entire space.
fec509a05ddbf645268fe2e537314def7d1b67c8gm bset = ENCODEBIAS(2, 2) | ENCODEBIAS(1, 1) | ENCODEBIAS(0, 0);
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < N2RNG_NOSC; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < N2RNG_NOSC; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm "n2rng: RNG hardware producing insufficient "
fec509a05ddbf645268fe2e537314def7d1b67c8gm "entropy (producing %ld, need %lld)",
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Set up fields of control words that will be the same for all
fec509a05ddbf645268fe2e537314def7d1b67c8gm * osciallators and for final value that selects all
fec509a05ddbf645268fe2e537314def7d1b67c8gm * oscillators.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_ctl.fields.rnc_cnt = n2rng->n_ctl_data->n_accumulate_cycles;
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Now set the oscillator biases.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_ctl.fields.rnc_cnt = n2rng->n_ctl_data->n_accumulate_cycles;
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rventropy == 0) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Save bias and entropy results for kstats */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < N2RNG_NOSC; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng_noise_gen_preferred: rng %d cell %d bias "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Clear bias and entropy results for kstats */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < N2RNG_NOSC; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Do a logic test, then find and set the best bias confuration
fec509a05ddbf645268fe2e537314def7d1b67c8gm * (failing if insufficient entropy is generated, then set state to
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * configured. This function should only be called when running in
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke * the control domain.
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (attempts < RNG_MAX_LOGIC_TEST_ATTEMPTS) && rv; attempts++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: n2rng_logic_test failed %d attempts",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng: n2rng_logic_test failed %d attempts",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng: n2rng_noise_gen_preferred failed");
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Push the selected config into HW */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_diag_bits(n2rng, rngid, NULL, NULL, 0,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng: n2rng_collect_diag_bits failed");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Push the selected config into HW with an error state */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (void) n2rng_collect_diag_bits(n2rng, rngid, NULL, NULL, 0,
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);