Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Rework hifn(4) RNG logic.



details:   https://anonhg.NetBSD.org/src/rev/104def41f882
branches:  trunk
changeset: 932823:104def41f882
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun May 17 00:54:05 2020 +0000

description:
Rework hifn(4) RNG logic.

Previously we would read 34 bits of entropy into the pool and stop,
never to try again.  This change finishes the conversion to an
on-demand source, although we still use a callout to (a) try again in
another second if the 7811 FIFO was emptied, and (b) wait at least
0.4 sec after we start the RNG to read anything from it as the
alleged documentation allegedly recommends.

diffstat:

 sys/dev/pci/hifn7751.c    |  120 ++++++++++++++++++++++++---------------------
 sys/dev/pci/hifn7751var.h |    6 +-
 2 files changed, 67 insertions(+), 59 deletions(-)

diffs (221 lines):

diff -r 221b1a32816d -r 104def41f882 sys/dev/pci/hifn7751.c
--- a/sys/dev/pci/hifn7751.c    Sun May 17 00:53:09 2020 +0000
+++ b/sys/dev/pci/hifn7751.c    Sun May 17 00:54:05 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: hifn7751.c,v 1.71 2020/05/17 00:53:09 riastradh Exp $  */
+/*     $NetBSD: hifn7751.c,v 1.72 2020/05/17 00:54:05 riastradh Exp $  */
 /*     $OpenBSD: hifn7751.c,v 1.179 2020/01/11 21:34:03 cheloha Exp $  */
 
 /*
@@ -47,7 +47,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hifn7751.c,v 1.71 2020/05/17 00:53:09 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hifn7751.c,v 1.72 2020/05/17 00:54:05 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/cprng.h>
@@ -119,8 +119,8 @@
 static int     hifn_dmamap_load_dst(struct hifn_softc *,
                                     struct hifn_command *);
 static int     hifn_init_pubrng(struct hifn_softc *);
-static void    hifn_rng(void *);
-static void    hifn_rng_locked(void *);
+static void    hifn_rng(struct hifn_softc *);
+static void    hifn_rng_intr(void *);
 static void    hifn_tick(void *);
 static void    hifn_abort(struct hifn_softc *);
 static void    hifn_alloc_slot(struct hifn_softc *, int *, int *, int *,
@@ -535,10 +535,25 @@
 hifn_rng_get(size_t bytes, void *priv)
 {
        struct hifn_softc *sc = priv;
+       struct timeval delta = {0, 400000};
+       struct timeval now, oktime, wait;
+
+       /*
+        * Wait until 0.4 seconds after we start up the RNG to read
+        * anything out of it.  If the time hasn't elapsed, schedule a
+        * callout later on.
+        */
+       microtime(&now);
 
        mutex_enter(&sc->sc_mtx);
-       sc->sc_rng_need = bytes;
-       callout_reset(&sc->sc_rngto, 0, hifn_rng, sc);
+       sc->sc_rng_needbits = MAX(sc->sc_rng_needbits, NBBY*bytes);
+       timeradd(&sc->sc_rngboottime, &delta, &oktime);
+       if (timercmp(&oktime, &now, <=)) {
+               hifn_rng(sc);
+       } else if (!callout_pending(&sc->sc_rngto)) {
+               timersub(&oktime, &now, &wait);
+               callout_schedule(&sc->sc_rngto, MAX(1, tvtohz(&wait)));
+       }
        mutex_exit(&sc->sc_mtx);
 }
 
@@ -591,16 +606,12 @@
                 * data that meet their worst-case estimate of 0.06
                 * bits of random data per output register bit.
                 */
-               DELAY(4000);
-
-               if (hz >= 100)
-                       sc->sc_rnghz = hz / 100;
-               else
-                       sc->sc_rnghz = 1;
+               microtime(&sc->sc_rngboottime);
                callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
+               callout_setfunc(&sc->sc_rngto, hifn_rng_intr, sc);
                rndsource_setcb(&sc->sc_rnd_source, hifn_rng_get, sc);
                rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
-                   RND_TYPE_RNG, RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB);
+                   RND_TYPE_RNG, RND_FLAG_DEFAULT|RND_FLAG_HASCB);
        }
 
        /* Enable public key engine, if available */
@@ -614,25 +625,20 @@
 }
 
 static void
-hifn_rng_locked(void *vsc)
+hifn_rng(struct hifn_softc *sc)
 {
-       struct hifn_softc *sc = vsc;
-       uint32_t num[64];
-       uint32_t sts;
-       int i;
-       size_t got, gotent;
-
-       if (sc->sc_rng_need < 1) {
-               callout_stop(&sc->sc_rngto);
-               return;
-       }
+       uint32_t entropybits;
+
+       KASSERT(mutex_owned(&sc->sc_mtx));
 
        if (sc->sc_flags & HIFN_IS_7811) {
-               for (i = 0; i < 5; i++) {       /* XXX why 5? */
+               while (sc->sc_rng_needbits) {
+                       uint32_t num[2];
+                       uint32_t sts;
+
                        sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS);
                        if (sts & HIFN_7811_RNGSTS_UFL) {
-                               printf("%s: RNG underflow: disabling\n",
-                                   device_xname(sc->sc_dv));
+                               device_printf(sc->sc_dv, "RNG underflow\n");
                                return;
                        }
                        if ((sts & HIFN_7811_RNGSTS_RDY) == 0)
@@ -644,23 +650,18 @@
                         */
                        num[0] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
                        num[1] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
-                       got = 2 * sizeof(num[0]);
-                       gotent = (got * NBBY) / HIFN_RNG_BITSPER;
-                       rnd_add_data(&sc->sc_rnd_source, num, got, gotent);
-                       sc->sc_rng_need -= gotent;
+#ifdef HIFN_DEBUG
+                       if (hifn_debug >= 2)
+                               hexdump(printf, "hifn", num, sizeof num);
+#endif
+                       entropybits = NBBY*sizeof(num)/HIFN_RNG_BITSPER;
+                       rnd_add_data(&sc->sc_rnd_source, num, sizeof(num),
+                           entropybits);
+                       entropybits = MAX(entropybits, 1);
+                       entropybits = MIN(entropybits, sc->sc_rng_needbits);
+                       sc->sc_rng_needbits -= entropybits;
                }
        } else {
-               int nwords = 0;
-
-               if (sc->sc_rng_need) {
-                       nwords = (sc->sc_rng_need * NBBY) / HIFN_RNG_BITSPER;
-                       nwords = MIN((int)__arraycount(num), nwords);
-               }
-
-               if (nwords < 2) {
-                       nwords = 2;
-               }
-
                /*
                 * We must be *extremely* careful here.  The Hifn
                 * 795x differ from the published 6500 RNG design
@@ -681,30 +682,37 @@
                 * read must require at least one PCI cycle, and
                 * RNG_Clk is at least PCI_Clk, this is safe.
                 */
-               for (i = 0 ; i < nwords * 8; i++) {
-                       volatile uint32_t regtmp;
-                       regtmp = READ_REG_1(sc, HIFN_1_RNG_DATA);
-                       num[i / 8] = regtmp;
+               while (sc->sc_rng_needbits) {
+                       uint32_t num[64];
+                       unsigned i;
+
+                       for (i = 0; i < 8*__arraycount(num); i++)
+                               num[i/8] = READ_REG_1(sc, HIFN_1_RNG_DATA);
+#ifdef HIFN_DEBUG
+                       if (hifn_debug >= 2)
+                               hexdump(printf, "hifn", num, sizeof num);
+#endif
+                       entropybits = NBBY*sizeof(num)/HIFN_RNG_BITSPER;
+                       rnd_add_data(&sc->sc_rnd_source, num, sizeof num,
+                           entropybits);
+                       entropybits = MAX(entropybits, 1);
+                       entropybits = MIN(entropybits, sc->sc_rng_needbits);
+                       sc->sc_rng_needbits -= entropybits;
                }
-
-               got = nwords * sizeof(num[0]);
-               gotent = (got * NBBY) / HIFN_RNG_BITSPER;
-               rnd_add_data(&sc->sc_rnd_source, num, got, gotent);
-               sc->sc_rng_need -= gotent;
        }
 
-       if (sc->sc_rng_need > 0) {
-               callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc);
-       }
+       /* If we still need more, try again in another second.  */
+       if (sc->sc_rng_needbits)
+               callout_schedule(&sc->sc_rngto, hz);
 }
 
 static void
-hifn_rng(void *vsc)
+hifn_rng_intr(void *vsc)
 {
        struct hifn_softc *sc = vsc;
 
        mutex_spin_enter(&sc->sc_mtx);
-       hifn_rng_locked(vsc);
+       hifn_rng(sc);
        mutex_spin_exit(&sc->sc_mtx);
 }
 
diff -r 221b1a32816d -r 104def41f882 sys/dev/pci/hifn7751var.h
--- a/sys/dev/pci/hifn7751var.h Sun May 17 00:53:09 2020 +0000
+++ b/sys/dev/pci/hifn7751var.h Sun May 17 00:54:05 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: hifn7751var.h,v 1.16 2020/05/17 00:53:09 riastradh Exp $       */
+/*     $NetBSD: hifn7751var.h,v 1.17 2020/05/17 00:54:05 riastradh Exp $       */
 /*     $OpenBSD: hifn7751var.h,v 1.54 2020/01/11 21:34:04 cheloha Exp $        */
 
 /*
@@ -156,11 +156,11 @@
 #define        HIFN_HAS_AES            0x20    /* includes AES support */
 #define        HIFN_IS_7956            0x40    /* Hifn 7955/7956 part */
 
+       struct timeval          sc_rngboottime; /* time we flipped RNG on */
        struct callout          sc_rngto;       /* rng timeout */
        struct callout          sc_tickto;      /* led-clear timeout */
        krndsource_t            sc_rnd_source;
-       int                     sc_rnghz;
-       int                     sc_rng_need;    /* how many bytes wanted */
+       unsigned                sc_rng_needbits; /* how many bits wanted */
        int                     sc_c_busy;      /* command ring busy */
        int                     sc_s_busy;      /* source data ring busy */
        int                     sc_d_busy;      /* destination data ring busy */



Home | Main Index | Thread Index | Old Index