xref: /onnv-gate/usr/src/uts/sun4v/io/n2rng/n2rng_entp_setup.c (revision 8008:90797bd3884c)
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, &reg);
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