Module Name:    src
Committed By:   riastradh
Date:           Sun May 17 00:54:05 UTC 2020

Modified Files:
        src/sys/dev/pci: hifn7751.c hifn7751var.h

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.71 -r1.72 src/sys/dev/pci/hifn7751.c
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/pci/hifn7751var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/hifn7751.c
diff -u src/sys/dev/pci/hifn7751.c:1.71 src/sys/dev/pci/hifn7751.c:1.72
--- src/sys/dev/pci/hifn7751.c:1.71	Sun May 17 00:53:09 2020
+++ src/sys/dev/pci/hifn7751.c	Sun May 17 00:54:05 2020
@@ -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_src(struct h
 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 @@ static void
 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 @@ hifn_init_pubrng(struct hifn_softc *sc)
 		 * 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 @@ hifn_init_pubrng(struct hifn_softc *sc)
 }
 
 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;
+	uint32_t entropybits;
 
-	if (sc->sc_rng_need < 1) {
-		callout_stop(&sc->sc_rngto);
-		return;
-	}
+	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 @@ hifn_rng_locked(void *vsc)
 			 */
 			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 @@ hifn_rng_locked(void *vsc)
 		 * 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;
 
-		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;
+			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;
+		}
 	}
 
-	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);
 }
 

Index: src/sys/dev/pci/hifn7751var.h
diff -u src/sys/dev/pci/hifn7751var.h:1.16 src/sys/dev/pci/hifn7751var.h:1.17
--- src/sys/dev/pci/hifn7751var.h:1.16	Sun May 17 00:53:09 2020
+++ src/sys/dev/pci/hifn7751var.h	Sun May 17 00:54:05 2020
@@ -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 @@ struct hifn_softc {
 #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 */

Reply via email to