14625Sgm89044 /*
24625Sgm89044 * CDDL HEADER START
34625Sgm89044 *
44625Sgm89044 * The contents of this file are subject to the terms of the
54625Sgm89044 * Common Development and Distribution License (the "License").
64625Sgm89044 * You may not use this file except in compliance with the License.
74625Sgm89044 *
84625Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94625Sgm89044 * or http://www.opensolaris.org/os/licensing.
104625Sgm89044 * See the License for the specific language governing permissions
114625Sgm89044 * and limitations under the License.
124625Sgm89044 *
134625Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each
144625Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154625Sgm89044 * If applicable, add the following below this CDDL HEADER, with the
164625Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying
174625Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner]
184625Sgm89044 *
194625Sgm89044 * CDDL HEADER END
204625Sgm89044 */
214625Sgm89044 /*
22*8008STodd.Welke@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
234625Sgm89044 * Use is subject to license terms.
244625Sgm89044 */
254625Sgm89044
264625Sgm89044 #include <sys/types.h>
274625Sgm89044 #include <sys/sysmacros.h>
284625Sgm89044 #include <sys/modctl.h>
294625Sgm89044 #include <sys/conf.h>
304625Sgm89044 #include <sys/devops.h>
314625Sgm89044 #include <sys/cmn_err.h>
324625Sgm89044 #include <sys/kmem.h>
334625Sgm89044 #include <sys/stat.h>
344625Sgm89044 #include <sys/open.h>
354625Sgm89044 #include <sys/file.h>
364625Sgm89044 #include <sys/ddi.h>
374625Sgm89044 #include <sys/sunddi.h>
384625Sgm89044 #include <sys/cpuvar.h>
394625Sgm89044 #include <sys/disp.h>
404625Sgm89044 #include <sys/hsvc.h>
414625Sgm89044 #include <sys/machsystm.h>
424625Sgm89044 #include <sys/param.h>
434625Sgm89044 #include <sys/hypervisor_api.h>
444625Sgm89044 #include <sys/n2rng.h>
454625Sgm89044
464625Sgm89044 /*
474625Sgm89044 * There are 3 noise cells each with its own oscillator, and each
484625Sgm89044 * oscillator can be set to 4 different bias setttings. The bias
494625Sgm89044 * setting controls the nominal frequency of the oscillator. The 3
504625Sgm89044 * and 4 and hardcoded throughout this file.
514625Sgm89044 */
524625Sgm89044
534625Sgm89044 #define BITS_IN(type) (8 * sizeof (type))
544625Sgm89044 #define EXTRACTBIT64(val, bit) (((val) >> (bit)) & 1UL)
554625Sgm89044
564625Sgm89044 /*
574625Sgm89044 * Policy settings
584625Sgm89044 */
594625Sgm89044 /* Log2 of the number of bits */
604625Sgm89044 #define SETTLECYCLES 1000000
614625Sgm89044 #define NORMAL_BYPASS 1
624625Sgm89044 #define NUMOSC 3
634625Sgm89044 #define LOG2_DATA_WORDS 15
644625Sgm89044 #define DATA_WORDS (1 << LOG2_DATA_WORDS)
654625Sgm89044
664625Sgm89044 #define ENTROPY_PASS_VALUE 150000000ULL
674625Sgm89044
684625Sgm89044 /*
694625Sgm89044 * There is a hardware bug that causes the RNG_DATA register to
704625Sgm89044 * occasionally be read one cycle before the specifed time.
714625Sgm89044 * LOGIC_TEST_EXPECTED_M1 is the value one cycle before
724625Sgm89044 * LOGIC_TEST_CYCLES. And there is a second bug that causes the read
734625Sgm89044 * to be delayed. We have seen delays of about 150 cycles, but do not
744625Sgm89044 * know that maximum that could possibly occur.
754625Sgm89044 *
764625Sgm89044 * We collect LOGIC_TEST_WORDS words using a diagnostic read with all
774625Sgm89044 * entropy turned off. The first one we skip, becuase we have no
784625Sgm89044 * knowledge of the time since the last read. We check that the
794625Sgm89044 * remaining values fall in the window of values that should occur
804625Sgm89044 * between LOGIC_TEST_CYCLES - 1 and LOGIC_TEST_CYCLES +
814625Sgm89044 * LOGIC_TEST_BUG_MAX. As further protecion against false positives,
824625Sgm89044 * we report success if the the number of mismatches does not exceed
834625Sgm89044 * LOGIC_TEST_ERRORS_ALLOWED.
845650Stwelke *
855650Stwelke * When running on maramba systems, delays as high as 20000 were observed
865650Stwelke * LOGIC_TEST_BUG_MAX was increased to twice this observed value since all
875650Stwelke * that matters is that the hardware is indeed generating the expected values
885650Stwelke * in diag mode. The code was also modified to exit as soon as the required
895650Stwelke * number of matches is detected.
904625Sgm89044 */
914625Sgm89044
925650Stwelke #define LOGIC_TEST_CYCLES 38859
935650Stwelke #define LOGIC_TEST_EXPECTED_M1 0xb8820c7bd387e32cULL
945650Stwelke #define LOGIC_TEST_BUG_MAX 40000
955650Stwelke #define LOGIC_TEST_WORDS 8 /* includes first one, unused */
964625Sgm89044 #define LOGIC_TEST_ERRORS_ALLOWED 1
975650Stwelke #define LOGIC_TEST_MATCHES_NEEDED (LOGIC_TEST_WORDS - 1 - \
985650Stwelke LOGIC_TEST_ERRORS_ALLOWED)
995650Stwelke
1004625Sgm89044 #define RNG_POLY 0x231dcee91262b8a3ULL
1014625Sgm89044 #define ENTDIVISOR (((1ULL << LOG_VAL_SCALE) + 500ULL) / 1000ULL)
1024625Sgm89044
1034625Sgm89044 #define ENCODEBIAS(osc, bias) (((bias) & 0x3) << (2 * (osc)))
1044625Sgm89044 #define EXTRACTBIAS(blob, osc) (((blob) >> (2 * (osc))) & 0x3)
1054625Sgm89044
1064625Sgm89044 extern int n2rng_herr2kerr(uint64_t hv_errcode);
1074625Sgm89044
1084625Sgm89044
1094625Sgm89044 /*
1104625Sgm89044 * Each value is a representation of the polynomail bit_i * x^i, where
1114625Sgm89044 * i=0 corresponds to the least significant bit of the word. The
1124625Sgm89044 * modulus polynomial is x^64 + the interpretation of poly. Out is
1134625Sgm89044 * set to in * x^exp mod moduluspolynomial. This corresponds to
1144625Sgm89044 * running the LFSR exp cycles. This implemenation directly simulates
1154625Sgm89044 * the lfsr. It's running time is O(exp), but the constant is small.
1164625Sgm89044 * (This code was taken verbatim from Legion.)
1174625Sgm89044 */
1184625Sgm89044 static void
lfsr64_adv_seq(uint64_t poly,uint64_t in,uint64_t exp,uint64_t * out)1194625Sgm89044 lfsr64_adv_seq(uint64_t poly, uint64_t in, uint64_t exp, uint64_t *out)
1204625Sgm89044 {
1214625Sgm89044 int i;
1224625Sgm89044 uint64_t res = in;
1234625Sgm89044
1244625Sgm89044 for (i = 0; i < exp; i++) {
1254625Sgm89044 if (res & 0x8000000000000000ULL) {
1264625Sgm89044 res = (res << 1) ^ poly;
1274625Sgm89044 } else {
1284625Sgm89044 res <<= 1;
1294625Sgm89044 }
1304625Sgm89044 }
1314625Sgm89044
1324625Sgm89044 *out = res;
1334625Sgm89044 }
1344625Sgm89044
1354625Sgm89044 int
n2rng_logic_test(n2rng_t * n2rng,int rngid)1365650Stwelke n2rng_logic_test(n2rng_t *n2rng, int rngid)
1374625Sgm89044 {
1384625Sgm89044 n2rng_setup_t logictest;
1395268Stwelke uint64_t buffer[LOGIC_TEST_WORDS];
1404625Sgm89044 uint64_t reg;
1414625Sgm89044 int rv;
1424625Sgm89044 int i, j;
1434625Sgm89044 int correctcount = 0;
1445650Stwelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
1455650Stwelke int cycles[LOGIC_TEST_WORDS] =
1465650Stwelke {0, 0, 0, 0, 0, 0, 0, 0};
1474625Sgm89044
1484625Sgm89044 /*
1494625Sgm89044 * This test runs the RNG with no entropy for
1504625Sgm89044 * LOGIC_TEST_CYCLES cycles. Ideally the value would be be
1514625Sgm89044 * LOGIC_TEST_RESULT, but because of the RNG bug, the actual
1524625Sgm89044 * register read may be delayed by upto LOGIC_TEST_BUG_MAX
1534625Sgm89044 * cycles. So we simulate over that window, and a match
1544625Sgm89044 * occurs, we report success.
1554625Sgm89044 */
1564625Sgm89044
1574625Sgm89044 logictest.ctlwds[0].word = 0;
1584625Sgm89044 logictest.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
1594625Sgm89044 logictest.ctlwds[1] = logictest.ctlwds[0];
1604625Sgm89044 logictest.ctlwds[2] = logictest.ctlwds[0];
1614625Sgm89044 logictest.ctlwds[3] = logictest.ctlwds[0];
1624625Sgm89044 logictest.ctlwds[3].fields.rnc_mode = 1;
1634625Sgm89044 logictest.ctlwds[3].fields.rnc_cnt = LOGIC_TEST_CYCLES - 2;
1644625Sgm89044
1654625Sgm89044 /* read LOGIC_TEST_WORDS 64-bit words */
1665650Stwelke rv = n2rng_collect_diag_bits(n2rng, rngid, &logictest, buffer,
1674625Sgm89044 LOGIC_TEST_WORDS * sizeof (uint64_t),
1685650Stwelke &rng->n_preferred_config, rng->n_rng_state);
1694625Sgm89044 if (rv) {
1705650Stwelke cmn_err(CE_WARN, "n2rng: n2rng_collect_diag_bits failed with "
1715650Stwelke "0x%x on rng(%d)", rv, rngid);
1724625Sgm89044 return (rv);
1734625Sgm89044 }
1744625Sgm89044
1754625Sgm89044 reg = LOGIC_TEST_EXPECTED_M1;
1764625Sgm89044 for (i = 0; i <= LOGIC_TEST_BUG_MAX; i++) {
1774625Sgm89044 for (j = 1; j < LOGIC_TEST_WORDS; ++j) {
1784625Sgm89044 if (buffer[j] == reg) {
1794625Sgm89044 ++correctcount;
1805650Stwelke cycles[j] = i;
1814625Sgm89044 }
1824625Sgm89044 }
1835650Stwelke /* exit loop if we have already found enough matches */
1845650Stwelke if (correctcount >= LOGIC_TEST_MATCHES_NEEDED) {
1855650Stwelke break;
1865650Stwelke }
1874625Sgm89044 /* advance reg by one step */
1884625Sgm89044 lfsr64_adv_seq(RNG_POLY, reg, 1, ®);
1894625Sgm89044 }
1904625Sgm89044
1915650Stwelke if (correctcount < LOGIC_TEST_MATCHES_NEEDED) {
192*8008STodd.Welke@Sun.COM /*
193*8008STodd.Welke@Sun.COM * Don't log a warning here since the calling routine will
194*8008STodd.Welke@Sun.COM * retry and log it's own warning if the retry fails.
195*8008STodd.Welke@Sun.COM */
196*8008STodd.Welke@Sun.COM DBG2(n2rng, DHEALTH, "n2rng: logic error on rng(%d), only %d "
1975650Stwelke "matches found", rngid, correctcount);
1985650Stwelke for (i = 0; i < LOGIC_TEST_WORDS; i++) {
1995650Stwelke DBG3(n2rng, DHEALTH, "buffer[%d] %016llx, cycles = %d",
2005650Stwelke i, buffer[i], cycles[i]);
2015650Stwelke }
2024625Sgm89044 return (EIO);
2035650Stwelke } else {
2045650Stwelke DBG3(n2rng, DHEALTH, "n2rng: rng(%d) logic test passed, "
2055650Stwelke "%d matches in %d cycles", rngid, correctcount, i);
2065650Stwelke for (i = 0; i < LOGIC_TEST_WORDS; i++) {
2075650Stwelke DBG3(n2rng, DCHATTY, "buffer[%d] %016llx, cycles = %d",
2085650Stwelke i, buffer[i], cycles[i]);
2095650Stwelke }
2104625Sgm89044 }
2114625Sgm89044
2124625Sgm89044 return (0);
2134625Sgm89044 }
2144625Sgm89044
2154625Sgm89044
2164625Sgm89044 /*
2174625Sgm89044 * gets the metric for the specified state.
2184625Sgm89044 */
2194625Sgm89044 int
n2rng_collect_metrics(n2rng_t * n2rng,int rngid,n2rng_setup_t * setupp,n2rng_setup_t * exit_setupp,uint64_t exit_state,n2rng_osc_perf_t * metricp)2205650Stwelke n2rng_collect_metrics(n2rng_t *n2rng, int rngid, n2rng_setup_t *setupp,
2214625Sgm89044 n2rng_setup_t *exit_setupp,
2224625Sgm89044 uint64_t exit_state, n2rng_osc_perf_t *metricp)
2234625Sgm89044 {
2244625Sgm89044 int rv;
2254625Sgm89044 int bufsize;
2264625Sgm89044 uint64_t *buffer = NULL;
2274625Sgm89044
2284625Sgm89044
2294625Sgm89044 bufsize = DATA_WORDS * sizeof (uint64_t);
2304625Sgm89044 buffer = (uint64_t *)contig_mem_alloc_align(bufsize,
2314625Sgm89044 CONTIG_ALIGNMENT);
2324625Sgm89044 if (buffer == NULL) {
2334625Sgm89044 return (ENOMEM);
2344625Sgm89044 }
2354625Sgm89044
2365650Stwelke rv = n2rng_collect_diag_bits(n2rng, rngid, setupp, buffer, bufsize,
2374625Sgm89044 exit_setupp, exit_state);
2384625Sgm89044 if (rv) {
2394625Sgm89044 cmn_err(CE_WARN,
2404625Sgm89044 "n2rng: n2rng_collect_bits returns 0x%x", rv);
2414625Sgm89044 } else {
2424625Sgm89044 n2rng_renyi_entropy(buffer, LOG2_DATA_WORDS, metricp);
2434625Sgm89044 }
2444625Sgm89044
2454625Sgm89044 contig_mem_free(buffer, bufsize);
2464625Sgm89044
2474625Sgm89044 return (rv);
2484625Sgm89044 }
2494625Sgm89044
2504625Sgm89044
2514625Sgm89044 /*
2524625Sgm89044 * Fills in table with the performance of each oscillator at each
2534625Sgm89044 * bias setting. A particular datum goes in table[osc][bias].
2544625Sgm89044 */
2554625Sgm89044 int
collect_rng_perf(n2rng_t * n2rng,int rngid,n2rng_osc_perf_table_t ptable)2565650Stwelke collect_rng_perf(n2rng_t *n2rng, int rngid, n2rng_osc_perf_table_t ptable)
2574625Sgm89044 {
2584625Sgm89044 int bias;
2594625Sgm89044 int osc;
2604625Sgm89044 n2rng_setup_t rngstate;
2614625Sgm89044 int rv;
2625650Stwelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
2634625Sgm89044
2644625Sgm89044 rngstate.ctlwds[0].word = 0;
2654625Sgm89044 rngstate.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
2664625Sgm89044 rngstate.ctlwds[1] = rngstate.ctlwds[0];
2674625Sgm89044 rngstate.ctlwds[2] = rngstate.ctlwds[0];
2684625Sgm89044 rngstate.ctlwds[3] = rngstate.ctlwds[0];
2694625Sgm89044
2704625Sgm89044 for (osc = 0; osc < N2RNG_NOSC; osc++) {
2714625Sgm89044 rngstate.ctlwds[3].fields.rnc_selbits = 1 << osc;
2724625Sgm89044 for (bias = 0; bias < N2RNG_NBIASES; bias++) {
2734625Sgm89044 rngstate.ctlwds[3].fields.rnc_vcoctl = bias;
2745650Stwelke rv = n2rng_collect_metrics(n2rng, rngid, &rngstate,
2755650Stwelke &rng->n_preferred_config, rng->n_rng_state,
2764625Sgm89044 &(ptable[osc][bias]));
2774625Sgm89044 if (rv) {
2784625Sgm89044 return (rv);
2794625Sgm89044 }
2804625Sgm89044 }
2814625Sgm89044 }
2824625Sgm89044
2834625Sgm89044 return (rv);
2844625Sgm89044 }
2854625Sgm89044
2864625Sgm89044 /*
2874625Sgm89044 * The following 2 functions test the performance of each noise cell
2884625Sgm89044 * and select the bias settings. They implement the following
2894625Sgm89044 * policies:
2904625Sgm89044 *
2914625Sgm89044 * 1. No two cells may be set to the same bias. (Cells with the same bias,
2924625Sgm89044 * which controls frequency, may beat together, with long
2934625Sgm89044 * runs of no entropy as a pair when they are nearly synchronized.)
2944625Sgm89044 * 2. The entropy of each cell is determined (for now) by the Renyi H2
2954625Sgm89044 * entropy of a collection of samples of raw bits.
2964625Sgm89044 * 3. The selected configuration is the one that has the largest total
2974625Sgm89044 * entropy, computed as stated above.
2984625Sgm89044 * 4. The delay is hard coded.
2994625Sgm89044 */
3004625Sgm89044
3014625Sgm89044
3024625Sgm89044 /*
3034625Sgm89044 * Finds the preferred configuration from perf data. Sets the
3044625Sgm89044 * preferred configuration in the n2rng structure.
3054625Sgm89044 */
3064625Sgm89044 int
n2rng_noise_gen_preferred(n2rng_t * n2rng,int rngid)3075650Stwelke n2rng_noise_gen_preferred(n2rng_t *n2rng, int rngid)
3084625Sgm89044 {
3094625Sgm89044 int rv;
3104625Sgm89044 int rventropy = 0; /* EIO if entropy is too low */
3114625Sgm89044 int b0, b1, b2;
3124625Sgm89044 int osc;
3134625Sgm89044 int bset;
3144625Sgm89044 n2rng_osc_perf_t *candidates[N2RNG_NOSC];
3154625Sgm89044 uint64_t bestcellentropy[N2RNG_NOSC] = {0};
3164625Sgm89044 uint64_t bestentropy = 0;
3174625Sgm89044 n2rng_ctl_t rng_ctl = {0};
3184625Sgm89044 int i;
3195650Stwelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
3204625Sgm89044
3215650Stwelke rv = collect_rng_perf(n2rng, rngid, rng->n_perftable);
3224625Sgm89044 if (rv) {
3234625Sgm89044 return (rv);
3244625Sgm89044 }
3254625Sgm89044
3264625Sgm89044 /*
3274625Sgm89044 * bset is the bias setting of all 3 oscillators packed into a
3284625Sgm89044 * word, 2 bits for each: b2:b1:b0. First we set up an
3295650Stwelke * arbitrary assignment, because in an earlier version of
3304625Sgm89044 * this code, there were cases where the assignment would
3314625Sgm89044 * never happen. Also, that way we don't need to prove
3324625Sgm89044 * assignment to prove we never have uninitalized variables,
3334625Sgm89044 * and hence it might avoid lint warnings.
3344625Sgm89044 *
3354625Sgm89044 * This block of code picks the "best" setting of the biases,
3364625Sgm89044 * where "best" is defined by the rules in the big comment
3374625Sgm89044 * block above.
3384625Sgm89044 *
3394625Sgm89044 * There are only 24 possible combinations such that no two
3404625Sgm89044 * oscillators get the same bias. We just do a brute force
3414625Sgm89044 * exhaustive search of the entire space.
3424625Sgm89044 */
3434625Sgm89044 bset = ENCODEBIAS(2, 2) | ENCODEBIAS(1, 1) | ENCODEBIAS(0, 0);
3444625Sgm89044 for (b0 = 0; b0 < N2RNG_NBIASES; b0++) {
3455650Stwelke candidates[0] = &rng->n_perftable[0][b0];
3464625Sgm89044 for (b1 = 0; b1 < N2RNG_NBIASES; b1++) {
3474625Sgm89044 if (b0 == b1) continue;
3485650Stwelke candidates[1] = &rng->n_perftable[1][b1];
3494625Sgm89044 for (b2 = 0; b2 < N2RNG_NBIASES; b2++) {
3504625Sgm89044 uint64_t totalentropy = 0;
3514625Sgm89044
3524625Sgm89044 if (b0 == b2 || b1 == b2) continue;
3535650Stwelke candidates[2] = &rng->n_perftable[2][b2];
3544625Sgm89044 for (i = 0; i < N2RNG_NOSC; i++) {
3554625Sgm89044 totalentropy += candidates[i]->H2;
3564625Sgm89044 }
3574625Sgm89044 if (totalentropy > bestentropy) {
3584625Sgm89044 bestentropy = totalentropy;
3594625Sgm89044 bset = ENCODEBIAS(0, b0) |
3604625Sgm89044 ENCODEBIAS(1, b1) |
3614625Sgm89044 ENCODEBIAS(2, b2);
3624625Sgm89044 for (i = 0; i < N2RNG_NOSC; i++) {
3634625Sgm89044 bestcellentropy[i] =
3644625Sgm89044 candidates[i]->H2;
3654625Sgm89044 }
3664625Sgm89044
3674625Sgm89044 }
3684625Sgm89044
3694625Sgm89044 }
3704625Sgm89044 }
3714625Sgm89044 }
3724625Sgm89044
3734625Sgm89044 if (bestentropy < ENTROPY_PASS_VALUE) {
3744625Sgm89044 cmn_err(CE_WARN,
3754625Sgm89044 "n2rng: RNG hardware producing insufficient "
3764625Sgm89044 "entropy (producing %ld, need %lld)",
3774625Sgm89044 bestentropy, ENTROPY_PASS_VALUE);
3784625Sgm89044 rventropy = EIO;
3794625Sgm89044 }
3804625Sgm89044
3814625Sgm89044 /*
3824625Sgm89044 * Set up fields of control words that will be the same for all
3834625Sgm89044 * osciallators and for final value that selects all
3844625Sgm89044 * oscillators.
3854625Sgm89044 */
3865650Stwelke rng_ctl.fields.rnc_cnt = n2rng->n_ctl_data->n_accumulate_cycles;
3874625Sgm89044 rng_ctl.fields.rnc_mode = 1; /* set normal mode */
3884625Sgm89044 rng_ctl.fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
3894625Sgm89044
3904625Sgm89044
3914625Sgm89044 /*
3924625Sgm89044 * Now set the oscillator biases.
3934625Sgm89044 */
3944625Sgm89044 for (osc = 0; osc < N2RNG_NOSC; osc++) {
3954625Sgm89044 rng_ctl.fields.rnc_selbits = 1 << osc;
3964625Sgm89044 rng_ctl.fields.rnc_vcoctl = EXTRACTBIAS(bset, osc);
3975650Stwelke rng->n_preferred_config.ctlwds[osc] = rng_ctl;
3984625Sgm89044 }
3994625Sgm89044
4005650Stwelke rng_ctl.fields.rnc_cnt = n2rng->n_ctl_data->n_accumulate_cycles;
4014625Sgm89044 rng_ctl.fields.rnc_vcoctl = 0;
4024625Sgm89044 rng_ctl.fields.rnc_selbits = 0x7;
4035650Stwelke rng->n_preferred_config.ctlwds[3] = rng_ctl;
4044625Sgm89044
4054625Sgm89044 if (rventropy == 0) {
4064625Sgm89044
4075650Stwelke /* Save bias and entropy results for kstats */
4085650Stwelke for (i = 0; i < N2RNG_NOSC; i++) {
4095650Stwelke rng->n_bias_info[i].bias =
4105650Stwelke (uint64_t)EXTRACTBIAS(bset, i);
4115650Stwelke rng->n_bias_info[i].entropy =
4125650Stwelke (uint64_t)(bestcellentropy[i] / ENTDIVISOR);
4135650Stwelke DBG4(n2rng, DCHATTY,
4145650Stwelke "n2rng_noise_gen_preferred: rng %d cell %d bias "
4155650Stwelke "%ld: %ld", rngid, i, rng->n_bias_info[i].bias,
4165650Stwelke rng->n_bias_info[i].entropy);
4175650Stwelke }
4185650Stwelke } else {
4195650Stwelke
4205650Stwelke /* Clear bias and entropy results for kstats */
4215650Stwelke for (i = 0; i < N2RNG_NOSC; i++) {
4225650Stwelke rng->n_bias_info[i].bias = 0;
4235650Stwelke rng->n_bias_info[i].entropy = 0;
4245650Stwelke }
4254625Sgm89044 }
4264625Sgm89044
4274625Sgm89044 return (rv ? rv : rventropy);
4284625Sgm89044 }
4294625Sgm89044
4304625Sgm89044 /*
4314625Sgm89044 * Do a logic test, then find and set the best bias confuration
4324625Sgm89044 * (failing if insufficient entropy is generated, then set state to
4335650Stwelke * configured. This function should only be called when running in
4345650Stwelke * the control domain.
4354625Sgm89044 */
4364625Sgm89044 int
n2rng_do_health_check(n2rng_t * n2rng,int rngid)4375650Stwelke n2rng_do_health_check(n2rng_t *n2rng, int rngid)
4384625Sgm89044 {
4395650Stwelke int rv = EIO;
4405650Stwelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
4415650Stwelke int attempts;
4424625Sgm89044
4435650Stwelke for (attempts = 0;
4445650Stwelke (attempts < RNG_MAX_LOGIC_TEST_ATTEMPTS) && rv; attempts++) {
4455650Stwelke rv = n2rng_logic_test(n2rng, rngid);
4464625Sgm89044 }
4474625Sgm89044
4484625Sgm89044 if (rv) {
4495650Stwelke cmn_err(CE_WARN, "n2rng: n2rng_logic_test failed %d attempts",
4505650Stwelke RNG_MAX_LOGIC_TEST_ATTEMPTS);
4515650Stwelke goto errorexit;
4525650Stwelke } else if (attempts > 1) {
4535650Stwelke DBG1(n2rng, DHEALTH,
4545650Stwelke "n2rng: n2rng_logic_test failed %d attempts",
4555650Stwelke attempts - 1);
4565650Stwelke goto errorexit;
4575650Stwelke }
4585650Stwelke
4595650Stwelke rv = n2rng_noise_gen_preferred(n2rng, rngid);
4605650Stwelke if (rv) {
4615650Stwelke DBG0(n2rng, DHEALTH,
4625650Stwelke "n2rng: n2rng_noise_gen_preferred failed");
4635650Stwelke goto errorexit;
4644625Sgm89044 }
4654625Sgm89044
4664625Sgm89044 /* Push the selected config into HW */
4675650Stwelke rv = n2rng_collect_diag_bits(n2rng, rngid, NULL, NULL, 0,
4685650Stwelke &rng->n_preferred_config, CTL_STATE_CONFIGURED);
4694625Sgm89044 if (rv) {
4705650Stwelke DBG0(n2rng, DHEALTH,
4715650Stwelke "n2rng: n2rng_collect_diag_bits failed");
4725650Stwelke goto errorexit;
4734625Sgm89044 }
4744625Sgm89044
4755650Stwelke return (rv);
4765650Stwelke
4775650Stwelke errorexit:
4785650Stwelke /* Push the selected config into HW with an error state */
4795650Stwelke (void) n2rng_collect_diag_bits(n2rng, rngid, NULL, NULL, 0,
4805650Stwelke &rng->n_preferred_config, CTL_STATE_ERROR);
4814625Sgm89044
4824625Sgm89044 return (rv);
4834625Sgm89044 }
484