fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * CDDL HEADER START
fec509a05ddbf645268fe2e537314def7d1b67c8gm *
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 *
fec509a05ddbf645268fe2e537314def7d1b67c8gm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fec509a05ddbf645268fe2e537314def7d1b67c8gm * or http://www.opensolaris.org/os/licensing.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * See the License for the specific language governing permissions
fec509a05ddbf645268fe2e537314def7d1b67c8gm * and limitations under the License.
fec509a05ddbf645268fe2e537314def7d1b67c8gm *
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 *
fec509a05ddbf645268fe2e537314def7d1b67c8gm * CDDL HEADER END
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
6e6cd25b8e73b6af1141b2f34fb186474fe7b9dbTodd Welke * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Use is subject to license terms.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/types.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/sysmacros.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/modctl.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/conf.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/devops.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/cmn_err.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/kmem.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/stat.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/open.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/file.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/ddi.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/sunddi.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/cpuvar.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/disp.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/hsvc.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/machsystm.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/param.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/hypervisor_api.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm#include <sys/n2rng.h>
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
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 */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define BITS_IN(type) (8 * sizeof (type))
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define EXTRACTBIT64(val, bit) (((val) >> (bit)) & 1UL)
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Policy settings
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm/* Log2 of the number of bits */
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define SETTLECYCLES 1000000
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define NORMAL_BYPASS 1
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define NUMOSC 3
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define LOG2_DATA_WORDS 15
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define DATA_WORDS (1 << LOG2_DATA_WORDS)
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define ENTROPY_PASS_VALUE 150000000ULL
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
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 *
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 *
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.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_CYCLES 38859
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_EXPECTED_M1 0xb8820c7bd387e32cULL
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_BUG_MAX 40000
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_WORDS 8 /* includes first one, unused */
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define LOGIC_TEST_ERRORS_ALLOWED 1
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke#define LOGIC_TEST_MATCHES_NEEDED (LOGIC_TEST_WORDS - 1 - \
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke LOGIC_TEST_ERRORS_ALLOWED)
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define RNG_POLY 0x231dcee91262b8a3ULL
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define ENTDIVISOR (((1ULL << LOG_VAL_SCALE) + 500ULL) / 1000ULL)
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define ENCODEBIAS(osc, bias) (((bias) & 0x3) << (2 * (osc)))
fec509a05ddbf645268fe2e537314def7d1b67c8gm#define EXTRACTBIAS(blob, osc) (((blob) >> (2 * (osc))) & 0x3)
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmextern int n2rng_herr2kerr(uint64_t hv_errcode);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
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.)
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmstatic void
fec509a05ddbf645268fe2e537314def7d1b67c8gmlfsr64_adv_seq(uint64_t poly, uint64_t in, uint64_t exp, uint64_t *out)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int i;
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t res = in;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < exp; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (res & 0x8000000000000000ULL) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm res = (res << 1) ^ poly;
fec509a05ddbf645268fe2e537314def7d1b67c8gm } else {
fec509a05ddbf645268fe2e537314def7d1b67c8gm res <<= 1;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm *out = res;
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_logic_test(n2rng_t *n2rng, int rngid)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_setup_t logictest;
802b83c445ef5ffc9777155491dfe4fcd9793946twelke uint64_t buffer[LOGIC_TEST_WORDS];
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t reg;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rv;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int i, j;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int correctcount = 0;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke int cycles[LOGIC_TEST_WORDS] =
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke {0, 0, 0, 0, 0, 0, 0, 0};
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /*
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 */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[0].word = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[1] = logictest.ctlwds[0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[2] = logictest.ctlwds[0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[3] = logictest.ctlwds[0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[3].fields.rnc_mode = 1;
fec509a05ddbf645268fe2e537314def7d1b67c8gm logictest.ctlwds[3].fields.rnc_cnt = LOGIC_TEST_CYCLES - 2;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* read LOGIC_TEST_WORDS 64-bit words */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_diag_bits(n2rng, rngid, &logictest, buffer,
fec509a05ddbf645268fe2e537314def7d1b67c8gm LOGIC_TEST_WORDS * sizeof (uint64_t),
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke &rng->n_preferred_config, rng->n_rng_state);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: n2rng_collect_diag_bits failed with "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "0x%x on rng(%d)", rv, rngid);
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm reg = LOGIC_TEST_EXPECTED_M1;
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i <= LOGIC_TEST_BUG_MAX; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (j = 1; j < LOGIC_TEST_WORDS; ++j) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (buffer[j] == reg) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm ++correctcount;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cycles[j] = i;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* exit loop if we have already found enough matches */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (correctcount >= LOGIC_TEST_MATCHES_NEEDED) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke break;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* advance reg by one step */
fec509a05ddbf645268fe2e537314def7d1b67c8gm lfsr64_adv_seq(RNG_POLY, reg, 1, &reg);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke if (correctcount < LOGIC_TEST_MATCHES_NEEDED) {
6e6cd25b8e73b6af1141b2f34fb186474fe7b9dbTodd Welke /*
6e6cd25b8e73b6af1141b2f34fb186474fe7b9dbTodd Welke * Don't log a warning here since the calling routine will
6e6cd25b8e73b6af1141b2f34fb186474fe7b9dbTodd Welke * retry and log it's own warning if the retry fails.
6e6cd25b8e73b6af1141b2f34fb186474fe7b9dbTodd Welke */
6e6cd25b8e73b6af1141b2f34fb186474fe7b9dbTodd Welke DBG2(n2rng, DHEALTH, "n2rng: logic error on rng(%d), only %d "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "matches found", rngid, correctcount);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < LOGIC_TEST_WORDS; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG3(n2rng, DHEALTH, "buffer[%d] %016llx, cycles = %d",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke i, buffer[i], cycles[i]);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (EIO);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG3(n2rng, DHEALTH, "n2rng: rng(%d) logic test passed, "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "%d matches in %d cycles", rngid, correctcount, i);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < LOGIC_TEST_WORDS; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG3(n2rng, DCHATTY, "buffer[%d] %016llx, cycles = %d",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke i, buffer[i], cycles[i]);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (0);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * gets the metric for the specified state.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_collect_metrics(n2rng_t *n2rng, int rngid, n2rng_setup_t *setupp,
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_setup_t *exit_setupp,
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t exit_state, n2rng_osc_perf_t *metricp)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rv;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int bufsize;
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t *buffer = NULL;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm bufsize = DATA_WORDS * sizeof (uint64_t);
fec509a05ddbf645268fe2e537314def7d1b67c8gm buffer = (uint64_t *)contig_mem_alloc_align(bufsize,
fec509a05ddbf645268fe2e537314def7d1b67c8gm CONTIG_ALIGNMENT);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (buffer == NULL) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (ENOMEM);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_diag_bits(n2rng, rngid, setupp, buffer, bufsize,
fec509a05ddbf645268fe2e537314def7d1b67c8gm exit_setupp, exit_state);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm cmn_err(CE_WARN,
fec509a05ddbf645268fe2e537314def7d1b67c8gm "n2rng: n2rng_collect_bits returns 0x%x", rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm } else {
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_renyi_entropy(buffer, LOG2_DATA_WORDS, metricp);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm contig_mem_free(buffer, bufsize);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Fills in table with the performance of each oscillator at each
fec509a05ddbf645268fe2e537314def7d1b67c8gm * bias setting. A particular datum goes in table[osc][bias].
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkecollect_rng_perf(n2rng_t *n2rng, int rngid, n2rng_osc_perf_table_t ptable)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int bias;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int osc;
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_setup_t rngstate;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rv;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[0].word = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[0].fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[1] = rngstate.ctlwds[0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[2] = rngstate.ctlwds[0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[3] = rngstate.ctlwds[0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (osc = 0; osc < N2RNG_NOSC; osc++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[3].fields.rnc_selbits = 1 << osc;
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (bias = 0; bias < N2RNG_NBIASES; bias++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm rngstate.ctlwds[3].fields.rnc_vcoctl = bias;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_metrics(n2rng, rngid, &rngstate,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke &rng->n_preferred_config, rng->n_rng_state,
fec509a05ddbf645268fe2e537314def7d1b67c8gm &(ptable[osc][bias]));
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
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 *
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 */
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Finds the preferred configuration from perf data. Sets the
fec509a05ddbf645268fe2e537314def7d1b67c8gm * preferred configuration in the n2rng structure.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_noise_gen_preferred(n2rng_t *n2rng, int rngid)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rv;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int rventropy = 0; /* EIO if entropy is too low */
fec509a05ddbf645268fe2e537314def7d1b67c8gm int b0, b1, b2;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int osc;
fec509a05ddbf645268fe2e537314def7d1b67c8gm int bset;
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_osc_perf_t *candidates[N2RNG_NOSC];
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t bestcellentropy[N2RNG_NOSC] = {0};
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t bestentropy = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm n2rng_ctl_t rng_ctl = {0};
fec509a05ddbf645268fe2e537314def7d1b67c8gm int i;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = collect_rng_perf(n2rng, rngid, rng->n_perftable);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /*
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 *
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 *
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 */
fec509a05ddbf645268fe2e537314def7d1b67c8gm bset = ENCODEBIAS(2, 2) | ENCODEBIAS(1, 1) | ENCODEBIAS(0, 0);
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (b0 = 0; b0 < N2RNG_NBIASES; b0++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke candidates[0] = &rng->n_perftable[0][b0];
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (b1 = 0; b1 < N2RNG_NBIASES; b1++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (b0 == b1) continue;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke candidates[1] = &rng->n_perftable[1][b1];
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (b2 = 0; b2 < N2RNG_NBIASES; b2++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm uint64_t totalentropy = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (b0 == b2 || b1 == b2) continue;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke candidates[2] = &rng->n_perftable[2][b2];
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < N2RNG_NOSC; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm totalentropy += candidates[i]->H2;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (totalentropy > bestentropy) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm bestentropy = totalentropy;
fec509a05ddbf645268fe2e537314def7d1b67c8gm bset = ENCODEBIAS(0, b0) |
fec509a05ddbf645268fe2e537314def7d1b67c8gm ENCODEBIAS(1, b1) |
fec509a05ddbf645268fe2e537314def7d1b67c8gm ENCODEBIAS(2, b2);
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (i = 0; i < N2RNG_NOSC; i++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm bestcellentropy[i] =
fec509a05ddbf645268fe2e537314def7d1b67c8gm candidates[i]->H2;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (bestentropy < ENTROPY_PASS_VALUE) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm cmn_err(CE_WARN,
fec509a05ddbf645268fe2e537314def7d1b67c8gm "n2rng: RNG hardware producing insufficient "
fec509a05ddbf645268fe2e537314def7d1b67c8gm "entropy (producing %ld, need %lld)",
fec509a05ddbf645268fe2e537314def7d1b67c8gm bestentropy, ENTROPY_PASS_VALUE);
fec509a05ddbf645268fe2e537314def7d1b67c8gm rventropy = EIO;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /*
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.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_ctl.fields.rnc_cnt = n2rng->n_ctl_data->n_accumulate_cycles;
fec509a05ddbf645268fe2e537314def7d1b67c8gm rng_ctl.fields.rnc_mode = 1; /* set normal mode */
fec509a05ddbf645268fe2e537314def7d1b67c8gm rng_ctl.fields.rnc_anlg_sel = N2RNG_NOANALOGOUT;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /*
fec509a05ddbf645268fe2e537314def7d1b67c8gm * Now set the oscillator biases.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gm for (osc = 0; osc < N2RNG_NOSC; osc++) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm rng_ctl.fields.rnc_selbits = 1 << osc;
fec509a05ddbf645268fe2e537314def7d1b67c8gm rng_ctl.fields.rnc_vcoctl = EXTRACTBIAS(bset, osc);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_preferred_config.ctlwds[osc] = rng_ctl;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_ctl.fields.rnc_cnt = n2rng->n_ctl_data->n_accumulate_cycles;
fec509a05ddbf645268fe2e537314def7d1b67c8gm rng_ctl.fields.rnc_vcoctl = 0;
fec509a05ddbf645268fe2e537314def7d1b67c8gm rng_ctl.fields.rnc_selbits = 0x7;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_preferred_config.ctlwds[3] = rng_ctl;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rventropy == 0) {
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Save bias and entropy results for kstats */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < N2RNG_NOSC; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_bias_info[i].bias =
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (uint64_t)EXTRACTBIAS(bset, i);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_bias_info[i].entropy =
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (uint64_t)(bestcellentropy[i] / ENTDIVISOR);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG4(n2rng, DCHATTY,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng_noise_gen_preferred: rng %d cell %d bias "
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "%ld: %ld", rngid, i, rng->n_bias_info[i].bias,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_bias_info[i].entropy);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Clear bias and entropy results for kstats */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (i = 0; i < N2RNG_NOSC; i++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_bias_info[i].bias = 0;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng->n_bias_info[i].entropy = 0;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv ? rv : rventropy);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm/*
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.
fec509a05ddbf645268fe2e537314def7d1b67c8gm */
fec509a05ddbf645268fe2e537314def7d1b67c8gmint
741c280d5486676df48cd5d5e8ed8d92eac714a8twelken2rng_do_health_check(n2rng_t *n2rng, int rngid)
fec509a05ddbf645268fe2e537314def7d1b67c8gm{
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke int rv = EIO;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rng_entry_t *rng = &n2rng->n_ctl_data->n_rngs[rngid];
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke int attempts;
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke for (attempts = 0;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (attempts < RNG_MAX_LOGIC_TEST_ATTEMPTS) && rv; attempts++) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_logic_test(n2rng, rngid);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke cmn_err(CE_WARN, "n2rng: n2rng_logic_test failed %d attempts",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke RNG_MAX_LOGIC_TEST_ATTEMPTS);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke goto errorexit;
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke } else if (attempts > 1) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG1(n2rng, DHEALTH,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng: n2rng_logic_test failed %d attempts",
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke attempts - 1);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke goto errorexit;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_noise_gen_preferred(n2rng, rngid);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG0(n2rng, DHEALTH,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng: n2rng_noise_gen_preferred failed");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke goto errorexit;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm /* Push the selected config into HW */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke rv = n2rng_collect_diag_bits(n2rng, rngid, NULL, NULL, 0,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke &rng->n_preferred_config, CTL_STATE_CONFIGURED);
fec509a05ddbf645268fe2e537314def7d1b67c8gm if (rv) {
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke DBG0(n2rng, DHEALTH,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke "n2rng: n2rng_collect_diag_bits failed");
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke goto errorexit;
fec509a05ddbf645268fe2e537314def7d1b67c8gm }
fec509a05ddbf645268fe2e537314def7d1b67c8gm
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke return (rv);
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke
741c280d5486676df48cd5d5e8ed8d92eac714a8twelkeerrorexit:
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke /* Push the selected config into HW with an error state */
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke (void) n2rng_collect_diag_bits(n2rng, rngid, NULL, NULL, 0,
741c280d5486676df48cd5d5e8ed8d92eac714a8twelke &rng->n_preferred_config, CTL_STATE_ERROR);
fec509a05ddbf645268fe2e537314def7d1b67c8gm
fec509a05ddbf645268fe2e537314def7d1b67c8gm return (rv);
fec509a05ddbf645268fe2e537314def7d1b67c8gm}