Module Name:    src
Committed By:   tls
Date:           Thu Jun 13 00:55:01 UTC 2013

Modified Files:
        src/sys/arch/arm/broadcom: bcm2835_rng.c
        src/sys/dev: rndpseudo.c
        src/sys/dev/pci: amdpm.c amdpm_smbus.c amdpmvar.h hifn7751.c
            hifn7751var.h ubsec.c ubsecvar.h
        src/sys/dev/scsipi: sd.c
        src/sys/kern: kern_rndpool.c kern_rndq.c subr_cprng.c
        src/sys/sys: rnd.h

Log Message:
Convert the entropy pool framework from pseudo-callout-driven to
soft interrupt driven operation.

Add a polling mode of operation -- now we can ask hardware random number
generators to top us up just when we need it (bcm2835_rng and amdpm
converted as examples).

Fix a stall noticed with repeated reads from /dev/random while testing.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/broadcom/bcm2835_rng.c
cvs rdiff -u -r1.11 -r1.12 src/sys/dev/rndpseudo.c
cvs rdiff -u -r1.36 -r1.37 src/sys/dev/pci/amdpm.c
cvs rdiff -u -r1.19 -r1.20 src/sys/dev/pci/amdpm_smbus.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/pci/amdpmvar.h \
    src/sys/dev/pci/hifn7751var.h
cvs rdiff -u -r1.51 -r1.52 src/sys/dev/pci/hifn7751.c
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/pci/ubsec.c
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/pci/ubsecvar.h
cvs rdiff -u -r1.300 -r1.301 src/sys/dev/scsipi/sd.c
cvs rdiff -u -r1.2 -r1.3 src/sys/kern/kern_rndpool.c
cvs rdiff -u -r1.10 -r1.11 src/sys/kern/kern_rndq.c
cvs rdiff -u -r1.16 -r1.17 src/sys/kern/subr_cprng.c
cvs rdiff -u -r1.35 -r1.36 src/sys/sys/rnd.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/arch/arm/broadcom/bcm2835_rng.c
diff -u src/sys/arch/arm/broadcom/bcm2835_rng.c:1.3 src/sys/arch/arm/broadcom/bcm2835_rng.c:1.4
--- src/sys/arch/arm/broadcom/bcm2835_rng.c:1.3	Fri Feb  1 16:10:16 2013
+++ src/sys/arch/arm/broadcom/bcm2835_rng.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: bcm2835_rng.c,v 1.3 2013/02/01 16:10:16 skrll Exp $ */
+/*	$NetBSD: bcm2835_rng.c,v 1.4 2013/06/13 00:55:01 tls Exp $ */
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_rng.c,v 1.3 2013/02/01 16:10:16 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_rng.c,v 1.4 2013/06/13 00:55:01 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -38,6 +38,7 @@ __KERNEL_RCSID(0, "$NetBSD: bcm2835_rng.
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/rnd.h>
+#include <sys/atomic.h>
 
 #include <arm/broadcom/bcm_amba.h>
 #include <arm/broadcom/bcm2835reg.h>
@@ -59,16 +60,16 @@ struct bcm2835rng_softc {
 	bus_space_handle_t sc_ioh;
 
 	krndsource_t sc_rnd;
-	callout_t sc_tick;
+
+	kmutex_t sc_mutex;
 
 	uint32_t sc_data[RNG_DATA_MAX];
 };
 
+static void bcmrng_get(size_t, void *);
 static int bcmrng_match(device_t, cfdata_t, void *);
 static void bcmrng_attach(device_t, device_t, void *);
 
-static void bcmrng_tick(void *);
-
 CFATTACH_DECL_NEW(bcmrng_amba, sizeof(struct bcm2835rng_softc),
     bcmrng_match, bcmrng_attach, NULL, NULL);
 
@@ -103,11 +104,11 @@ bcmrng_attach(device_t parent, device_t 
 		return;
 	}
 
-	rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG,
-	    RND_FLAG_NO_ESTIMATE);
+	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
 
-	callout_init(&sc->sc_tick, CALLOUT_MPSAFE);
-	callout_setfunc(&sc->sc_tick, bcmrng_tick, sc);
+	rndsource_setcb(&sc->sc_rnd, bcmrng_get, sc);
+	rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG,
+	    RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
 
 	/* discard initial numbers, broadcom says they are "less random" */
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS, 0x40000);
@@ -116,26 +117,34 @@ bcmrng_attach(device_t parent, device_t 
 	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_CTRL);
 	ctrl |= RNG_CTRL_EN;
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, RNG_CTRL, ctrl);
-
-	/* start timer */
-	bcmrng_tick(sc);
 }
 
 static void
-bcmrng_tick(void *priv)
+bcmrng_get(size_t bytes, void *priv)
 {
-	struct bcm2835rng_softc *sc = priv;
+        struct bcm2835rng_softc *sc = priv;
 	uint32_t status;
-	int cnt;
+	int need = bytes, cnt;
 
-	status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS);
-	cnt = (status & RNG_STATUS_CNT_MASK) >> RNG_STATUS_CNT_SHIFT;
-	if (cnt > 0) {
-		bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh, RNG_DATA,
-		    sc->sc_data, cnt);
-		rnd_add_data(&sc->sc_rnd, sc->sc_data,
-		    cnt * 4, cnt * 4 * NBBY);
+        mutex_spin_enter(&sc->sc_mutex);
+
+        printf("bcmrng: asked for %d bytes", (int)bytes);
+
+	if (__predict_false(need < 1)) {
+		return;
 	}
 
-	callout_schedule(&sc->sc_tick, 1);
+	while (need > 0) {
+		status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS);
+		cnt = (status & RNG_STATUS_CNT_MASK) >> RNG_STATUS_CNT_SHIFT;
+		if (cnt > 0) {
+			bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh,
+					       RNG_DATA, sc->sc_data, cnt);
+			rnd_add_data(&sc->sc_rnd, sc->sc_data,
+		    		     cnt * 4, cnt * 4 * NBBY);
+		}
+
+		need -= cnt * 4;
+	}
+	mutex_spin_exit(&sc->sc_mutex);
 }

Index: src/sys/dev/rndpseudo.c
diff -u src/sys/dev/rndpseudo.c:1.11 src/sys/dev/rndpseudo.c:1.12
--- src/sys/dev/rndpseudo.c:1.11	Sun Nov 25 15:29:24 2012
+++ src/sys/dev/rndpseudo.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: rndpseudo.c,v 1.11 2012/11/25 15:29:24 christos Exp $	*/
+/*	$NetBSD: rndpseudo.c,v 1.12 2013/06/13 00:55:01 tls Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.11 2012/11/25 15:29:24 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.12 2013/06/13 00:55:01 tls Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -219,6 +219,7 @@ rndopen(dev_t dev, int flag, int ifmt,
 	}
 	ctx->cprng = NULL;
 	ctx->hard = hard;
+	ctx->bytesonkey = 0;
 	mutex_init(&ctx->interlock, MUTEX_DEFAULT, IPL_NONE);
 
 	return fd_clone(fp, fd, flag, &rnd_fileops, ctx);
@@ -298,12 +299,19 @@ rnd_read(struct file * fp, off_t *offp, 
 
 		/* XXX is this _really_ what's wanted? */
 		if (ctx->hard) {
+#ifdef RND_VERBOSE
+			printf("rnd: hard, want = %d, strength = %d, "
+			       "bytesonkey = %d\n", (int)want, (int)strength,
+			       (int)ctx->bytesonkey);
+#endif
 			n = MIN(want, strength - ctx->bytesonkey);
 			if (n < 1) {
-			    cprng_strong_deplete(cprng);
-			    n = MIN(want, strength);
-			    ctx->bytesonkey = 0;
-			    membar_producer();
+#ifdef RND_VERBOSE
+			    printf("rnd: BAD BAD BAD: n = %d, want = %d, "
+				   "strength = %d, bytesonkey = %d\n", n,
+				   (int)want, (int)strength,
+				   (int)ctx->bytesonkey);
+#endif
 			}
 		} else {
 			n = want;
@@ -313,7 +321,15 @@ rnd_read(struct file * fp, off_t *offp, 
 				     (fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0);
 
 		if (ctx->hard && nread > 0) {
-			atomic_add_int(&ctx->bytesonkey, nread);
+			if (atomic_add_int_nv(&ctx->bytesonkey, nread) >=
+			    strength) {
+				cprng_strong_deplete(cprng);
+				ctx->bytesonkey = 0;
+				membar_producer();
+			}
+#ifdef RND_VERBOSE
+			printf("rnd: new bytesonkey %d\n", ctx->bytesonkey);
+#endif
 		}
 		if (nread < 1) {
 			if (fp->f_flag & FNONBLOCK) {

Index: src/sys/dev/pci/amdpm.c
diff -u src/sys/dev/pci/amdpm.c:1.36 src/sys/dev/pci/amdpm.c:1.37
--- src/sys/dev/pci/amdpm.c:1.36	Sat Oct 27 17:18:28 2012
+++ src/sys/dev/pci/amdpm.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdpm.c,v 1.36 2012/10/27 17:18:28 chs Exp $	*/
+/*	$NetBSD: amdpm.c,v 1.37 2013/06/13 00:55:01 tls Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1.36 2012/10/27 17:18:28 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1.37 2013/06/13 00:55:01 tls Exp $");
 
 #include "opt_amdpm.h"
 
@@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1.
 #include <sys/device.h>
 #include <sys/callout.h>
 #include <sys/rnd.h>
+#include <sys/mutex.h>
 
 #include <sys/bus.h>
 #include <dev/ic/acpipmtimer.h>
@@ -55,6 +56,7 @@ __KERNEL_RCSID(0, "$NetBSD: amdpm.c,v 1.
 #include <dev/pci/amdpm_smbusreg.h>
 
 static void	amdpm_rnd_callout(void *);
+static void	amdpm_rnd_callout_locked(void *);
 
 #ifdef AMDPM_RND_COUNTERS
 #define	AMDPM_RNDCNT_INCR(ev)	(ev)->ev_count++
@@ -83,6 +85,17 @@ amdpm_match(device_t parent, cfdata_t ma
 }
 
 static void
+amdpm_rnd_get(size_t bytes, void *priv)
+{
+	struct amdpm_softc *sc = priv;
+
+	mutex_enter(&sc->sc_mutex);
+	sc->sc_rnd_need = bytes;
+	amdpm_rnd_callout_locked(sc);
+	mutex_exit(&sc->sc_mutex);
+}
+
+static void
 amdpm_attach(device_t parent, device_t self, void *aux)
 {
 	struct amdpm_softc *sc = device_private(self);
@@ -151,6 +164,9 @@ amdpm_attach(device_t parent, device_t s
 		  AMDPM_TMR, ((confreg & AMDPM_TMR32) ? ACPIPMT_32BIT : 0));
 	}
 
+	/* XXX this mutex is IPL_VM because it can be taken by rnd_getmore() */
+	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
+
 	/* try to attach devices on the smbus */
 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC8111_ACPI ||
 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
@@ -173,7 +189,9 @@ amdpm_attach(device_t parent, device_t s
 			aprint_normal_dev(self, ""
 			    "random number generator enabled (apprx. %dms)\n",
 			    i);
-			callout_init(&sc->sc_rnd_ch, 0);
+			callout_init(&sc->sc_rnd_ch, CALLOUT_MPSAFE);
+			rndsource_setcb(&sc->sc_rnd_source,
+					amdpm_rnd_get, sc);
 			rnd_attach_source(&sc->sc_rnd_source,
 			    device_xname(self), RND_TYPE_RNG,
 			    /*
@@ -187,7 +205,7 @@ amdpm_attach(device_t parent, device_t s
 			     * XXX as entropy, which is not a good idea since
 			     * XXX we add data periodically from a callout.
 			     */
-			    RND_FLAG_NO_ESTIMATE);
+			    RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
 #ifdef AMDPM_RND_COUNTERS
 			evcnt_attach_dynamic(&sc->sc_rnd_hits, EVCNT_TYPE_MISC,
 			    NULL, device_xname(self), "rnd hits");
@@ -199,6 +217,7 @@ amdpm_attach(device_t parent, device_t s
 				    "rnd data");
 			}
 #endif
+			sc->sc_rnd_need = RND_POOLBITS / NBBY;
 			amdpm_rnd_callout(sc);
 		}
 	}
@@ -208,7 +227,7 @@ CFATTACH_DECL_NEW(amdpm, sizeof(struct a
     amdpm_match, amdpm_attach, NULL, NULL);
 
 static void
-amdpm_rnd_callout(void *v)
+amdpm_rnd_callout_locked(void *v)
 {
 	struct amdpm_softc *sc = v;
 	u_int32_t rngreg;
@@ -216,12 +235,18 @@ amdpm_rnd_callout(void *v)
 	int i;
 #endif
 
+	if (sc->sc_rnd_need < 1) {
+		callout_stop(&sc->sc_rnd_ch);
+		return;
+	}
+
 	if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
 	    AMDPM_RNGDONE) != 0) {
 		rngreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
 		    AMDPM_RNGDATA);
 		rnd_add_data(&sc->sc_rnd_source, &rngreg,
 		    sizeof(rngreg), sizeof(rngreg) * NBBY);
+		sc->sc_rnd_need -= sizeof(rngreg);
 #ifdef AMDPM_RND_COUNTERS
 		AMDPM_RNDCNT_INCR(&sc->sc_rnd_hits);
 		for (i = 0; i < sizeof(rngreg); i++, rngreg >>= NBBY)
@@ -232,5 +257,17 @@ amdpm_rnd_callout(void *v)
 	else
 		AMDPM_RNDCNT_INCR(&sc->sc_rnd_miss);
 #endif
-	callout_reset(&sc->sc_rnd_ch, 1, amdpm_rnd_callout, sc);
+	if (sc->sc_rnd_need > 0) {
+		callout_reset(&sc->sc_rnd_ch, 1, amdpm_rnd_callout, sc);
+	}
+}
+
+static void
+amdpm_rnd_callout(void *v)
+{
+	struct amdpm_softc *sc = v;
+
+	mutex_enter(&sc->sc_mutex);
+	amdpm_rnd_callout_locked(v);
+	mutex_exit(&sc->sc_mutex);
 }

Index: src/sys/dev/pci/amdpm_smbus.c
diff -u src/sys/dev/pci/amdpm_smbus.c:1.19 src/sys/dev/pci/amdpm_smbus.c:1.20
--- src/sys/dev/pci/amdpm_smbus.c:1.19	Sat Oct 27 17:18:28 2012
+++ src/sys/dev/pci/amdpm_smbus.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdpm_smbus.c,v 1.19 2012/10/27 17:18:28 chs Exp $ */
+/*	$NetBSD: amdpm_smbus.c,v 1.20 2013/06/13 00:55:01 tls Exp $ */
 
 /*
  * Copyright (c) 2005 Anil Gopinath (anil_pub...@yahoo.com)
@@ -32,7 +32,7 @@
  * AMD-8111 HyperTransport I/O Hub
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.19 2012/10/27 17:18:28 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.20 2013/06/13 00:55:01 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -83,8 +83,6 @@ amdpm_smbus_attach(struct amdpm_softc *s
 	sc->sc_i2c.ic_write_byte = NULL;
 	sc->sc_i2c.ic_exec = amdpm_smbus_exec;
 
-	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
-
 	iba.iba_tag = &sc->sc_i2c;
 	(void)config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
 }

Index: src/sys/dev/pci/amdpmvar.h
diff -u src/sys/dev/pci/amdpmvar.h:1.9 src/sys/dev/pci/amdpmvar.h:1.10
--- src/sys/dev/pci/amdpmvar.h:1.9	Sat Oct 27 17:18:28 2012
+++ src/sys/dev/pci/amdpmvar.h	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdpmvar.h,v 1.9 2012/10/27 17:18:28 chs Exp $	*/
+/*	$NetBSD: amdpmvar.h,v 1.10 2013/06/13 00:55:01 tls Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -53,6 +53,7 @@ struct amdpm_softc {
 
 	struct callout sc_rnd_ch;
 	krndsource_t sc_rnd_source;
+	int sc_rnd_need;
 #ifdef AMDPM_RND_COUNTERS
 	struct evcnt sc_rnd_hits;
 	struct evcnt sc_rnd_miss;
Index: src/sys/dev/pci/hifn7751var.h
diff -u src/sys/dev/pci/hifn7751var.h:1.9 src/sys/dev/pci/hifn7751var.h:1.10
--- src/sys/dev/pci/hifn7751var.h:1.9	Sat Oct 27 17:18:32 2012
+++ src/sys/dev/pci/hifn7751var.h	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: hifn7751var.h,v 1.9 2012/10/27 17:18:32 chs Exp $	*/
+/*	$NetBSD: hifn7751var.h,v 1.10 2013/06/13 00:55:01 tls Exp $	*/
 /*	$OpenBSD: hifn7751var.h,v 1.18 2000/06/02 22:36:45 deraadt Exp $	*/
 
 /*
@@ -169,8 +169,8 @@ struct hifn_softc {
 	struct callout		sc_rngto;	/* rng timeout */
 	struct callout		sc_tickto;	/* led-clear timeout */
 	krndsource_t	sc_rnd_source;
-	int			sc_rngfirst;
 	int			sc_rnghz;
+	int			sc_rng_need;	/* how many bytes wanted */
 	int			sc_c_busy;	/* command ring busy */
 	int			sc_s_busy;	/* source data ring busy */
 	int			sc_d_busy;	/* destination data ring busy */
@@ -184,6 +184,7 @@ struct hifn_softc {
 	pcitag_t sc_pci_tag;
 	bus_size_t sc_waw_lastreg;
 	int sc_waw_lastgroup;
+	kmutex_t		sc_mtx;
 };
 
 #define WRITE_REG_0(sc,reg,val)		hifn_write_4((sc), 0, (reg), (val))

Index: src/sys/dev/pci/hifn7751.c
diff -u src/sys/dev/pci/hifn7751.c:1.51 src/sys/dev/pci/hifn7751.c:1.52
--- src/sys/dev/pci/hifn7751.c:1.51	Sat Oct 27 17:18:32 2012
+++ src/sys/dev/pci/hifn7751.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: hifn7751.c,v 1.51 2012/10/27 17:18:32 chs Exp $	*/
+/*	$NetBSD: hifn7751.c,v 1.52 2013/06/13 00:55:01 tls Exp $	*/
 /*	$FreeBSD: hifn7751.c,v 1.5.2.7 2003/10/08 23:52:00 sam Exp $ */
 /*	$OpenBSD: hifn7751.c,v 1.140 2003/08/01 17:55:54 deraadt Exp $	*/
 
@@ -48,10 +48,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hifn7751.c,v 1.51 2012/10/27 17:18:32 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hifn7751.c,v 1.52 2013/06/13 00:55:01 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/errno.h>
 #include <sys/malloc.h>
@@ -140,6 +141,7 @@ static int	hifn_dmamap_load_dst(struct h
 				     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_tick(void *);
 static void	hifn_abort(struct hifn_softc *);
 static void	hifn_alloc_slot(struct hifn_softc *, int *, int *, int *,
@@ -155,7 +157,6 @@ static void	hifn_callback_comp(struct hi
 				   u_int8_t *);
 #endif	/* HAVE_CRYPTO_LZS */
 
-
 struct hifn_stats hifnstats;
 
 static const struct hifn_product {
@@ -418,14 +419,18 @@ hifn_attach(device_t parent, device_t se
 	    sc->sc_dmamap->dm_mapsize,
 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
-	if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG))
+	if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) {
 		hifn_init_pubrng(sc);
+		sc->sc_rng_need = RND_POOLBITS / NBBY;
+	}
+
+	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
 
 #ifdef	__OpenBSD__
 	timeout_set(&sc->sc_tickto, hifn_tick, sc);
 	timeout_add(&sc->sc_tickto, hz);
 #else
-	callout_init(&sc->sc_tickto, 0);
+	callout_init(&sc->sc_tickto, CALLOUT_MPSAFE);
 	callout_reset(&sc->sc_tickto, hz, hifn_tick, sc);
 #endif
 	return;
@@ -448,6 +453,18 @@ fail_io0:
 	bus_space_unmap(sc->sc_st0, sc->sc_sh0, iosize0);
 }
 
+static void
+hifn_rng_get(size_t bytes, void *priv)
+{
+	struct hifn_softc *sc = priv;
+
+	mutex_enter(&sc->sc_mtx);
+	sc->sc_rng_need = bytes;
+
+	hifn_rng_locked(sc);
+	mutex_exit(&sc->sc_mtx);
+}
+
 static int
 hifn_init_pubrng(struct hifn_softc *sc)
 {
@@ -500,6 +517,7 @@ hifn_init_pubrng(struct hifn_softc *sc)
 		DELAY(4000);
 
 #ifdef __NetBSD__
+		rndsource_setcb(&sc->sc_rnd_source, hifn_rng_get, sc);
 		/*
 		 * XXX Careful!  The use of RND_FLAG_NO_ESTIMATE
 		 * XXX here is unobvious: we later feed raw bits
@@ -512,10 +530,10 @@ hifn_init_pubrng(struct hifn_softc *sc)
 		 * XXX we add data periodically from a callout.
 		 */
 		rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
-				  RND_TYPE_RNG, RND_FLAG_NO_ESTIMATE);
+				  RND_TYPE_RNG,
+				  RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
 #endif
 
-		sc->sc_rngfirst = 1;
 		if (hz >= 100)
 			sc->sc_rnghz = hz / 100;
 		else
@@ -523,7 +541,7 @@ hifn_init_pubrng(struct hifn_softc *sc)
 #ifdef	__OpenBSD__
 		timeout_set(&sc->sc_rngto, hifn_rng, sc);
 #else	/* !__OpenBSD__ */
-		callout_init(&sc->sc_rngto, 0);
+		callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
 #endif	/* !__OpenBSD__ */
 	}
 
@@ -541,7 +559,7 @@ hifn_init_pubrng(struct hifn_softc *sc)
 }
 
 static void
-hifn_rng(void *vsc)
+hifn_rng_locked(void *vsc)
 {
 	struct hifn_softc *sc = vsc;
 #ifdef __NetBSD__
@@ -551,6 +569,12 @@ hifn_rng(void *vsc)
 #endif
 	uint32_t sts;
 	int i;
+	size_t got, gotent;
+
+	if (sc->sc_rng_need < 1) {
+		callout_stop(&sc->sc_rngto);
+		return;
+	}
 
 	if (sc->sc_flags & HIFN_IS_7811) {
 		for (i = 0; i < 5; i++) {	/* XXX why 5? */
@@ -569,14 +593,12 @@ hifn_rng(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;
 
-			if (sc->sc_rngfirst)
-				sc->sc_rngfirst = 0;
 #ifdef __NetBSD__
-			rnd_add_data(&sc->sc_rnd_source, num,
-			    2 * sizeof(num[0]),
-			    (2 * sizeof(num[0]) * NBBY) /
-			    HIFN_RNG_BITSPER);
+			rnd_add_data(&sc->sc_rnd_source, num, got, gotent);
+			sc->sc_rng_need -= gotent;
 #else
 			/*
 			 * XXX This is a really bad idea.
@@ -597,13 +619,16 @@ hifn_rng(void *vsc)
 				
 		}
 	} else {
-#ifdef __NetBSD__
-		/* First time through, try to help fill the pool. */
-		int nwords = sc->sc_rngfirst ?
-		    sizeof(num) / sizeof(num[0]) : 4;
-#else
-		int nwords = 2;
-#endif
+		int nwords = 0;
+
+		if (sc->sc_rng_need) {
+			nwords = (sc->sc_rng_need * NBBY) / HIFN_RNG_BITSPER;
+		}
+
+		if (nwords < 2) {
+			nwords = 2;
+		}
+
 		/*
 		 * We must be *extremely* careful here.  The Hifn
 		 * 795x differ from the published 6500 RNG design
@@ -624,24 +649,18 @@ hifn_rng(void *vsc)
 		 * read must require at least one PCI cycle, and
 		 * RNG_Clk is at least PCI_Clk, this is safe.
 		 */
-
-
-		if (sc->sc_rngfirst) {
-			sc->sc_rngfirst = 0;
-		}
-		
-
 		for(i = 0 ; i < nwords * 8; i++)
 		{
 			volatile u_int32_t regtmp;
 			regtmp = READ_REG_1(sc, HIFN_1_RNG_DATA);
 			num[i / 8] = regtmp;
 		}
+
+		got = nwords * sizeof(num[0]);
+		gotent = (got * NBBY) / HIFN_RNG_BITSPER;
 #ifdef __NetBSD__
-		rnd_add_data(&sc->sc_rnd_source, num,
-		    nwords * sizeof(num[0]),
-		    (nwords * sizeof(num[0]) * NBBY) /
-		    HIFN_RNG_BITSPER);
+		rnd_add_data(&sc->sc_rnd_source, num, got, gotent);
+		sc->sc_rng_need -= gotent;
 #else
 		/* XXX a bad idea; see 7811 block above */
 		add_true_randomness(num[0]);
@@ -651,11 +670,23 @@ hifn_rng(void *vsc)
 #ifdef	__OpenBSD__
 	timeout_add(&sc->sc_rngto, sc->sc_rnghz);
 #else
-	callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc);
+	if (sc->sc_rng_need > 0) {
+		callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc);
+	}
 #endif
 }
 
 static void
+hifn_rng(void *vsc)
+{
+	struct hifn_softc *sc = vsc;
+
+	mutex_spin_enter(&sc->sc_mtx);
+	hifn_rng_locked(vsc);
+	mutex_spin_exit(&sc->sc_mtx);
+}
+
+static void
 hifn_puc_wait(struct hifn_softc *sc)
 {
 	int i;
@@ -1590,7 +1621,7 @@ hifn_crypto(struct hifn_softc *sc, struc
 {
 	struct	hifn_dma *dma = sc->sc_dma;
 	u_int32_t cmdlen;
-	int	cmdi, resi, s, err = 0;
+	int	cmdi, resi, err = 0;
 
 	if (bus_dmamap_create(sc->sc_dmat, HIFN_MAX_DMALEN, MAX_SCATTER,
 	    HIFN_MAX_SEGLEN, 0, BUS_DMA_NOWAIT, &cmd->src_map))
@@ -1720,21 +1751,17 @@ hifn_crypto(struct hifn_softc *sc, struc
 		    0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
 	}
 
-	s = splnet();
-
 	/*
 	 * need 1 cmd, and 1 res
 	 * need N src, and N dst
 	 */
 	if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE ||
 	    (dma->resu + 1) > HIFN_D_RES_RSIZE) {
-		splx(s);
 		err = ENOMEM;
 		goto err_dstmap;
 	}
 	if ((dma->srcu + cmd->src_map->dm_nsegs) > HIFN_D_SRC_RSIZE ||
 	    (dma->dstu + cmd->dst_map->dm_nsegs + 1) > HIFN_D_DST_RSIZE) {
-		splx(s);
 		err = ENOMEM;
 		goto err_dstmap;
 	}
@@ -1837,7 +1864,6 @@ hifn_crypto(struct hifn_softc *sc, struc
 #endif
 
 	sc->sc_active = 5;
-	splx(s);
 	return (err);		/* success */
 
 err_dstmap:
@@ -1860,9 +1886,8 @@ static void
 hifn_tick(void *vsc)
 {
 	struct hifn_softc *sc = vsc;
-	int s;
 
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 	if (sc->sc_active == 0) {
 		struct hifn_dma *dma = sc->sc_dma;
 		u_int32_t r = 0;
@@ -1891,12 +1916,12 @@ hifn_tick(void *vsc)
 	}
 	else
 		sc->sc_active--;
-	splx(s);
 #ifdef	__OpenBSD__
 	timeout_add(&sc->sc_tickto, hz);
 #else
 	callout_reset(&sc->sc_tickto, hz, hifn_tick, sc);
 #endif
+	mutex_spin_exit(&sc->sc_mtx);
 }
 
 static int
@@ -1917,9 +1942,13 @@ hifn_intr(void *arg)
 		       dma->cmdu, dma->srcu, dma->dstu, dma->resu);
 #endif
 
+	mutex_spin_enter(&sc->sc_mtx);
+
 	/* Nothing in the DMA unit interrupted */
-	if ((dmacsr & sc->sc_dmaier) == 0)
+	if ((dmacsr & sc->sc_dmaier) == 0) {
+		mutex_spin_exit(&sc->sc_mtx);
 		return (0);
+	}
 
 	WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier);
 
@@ -1948,7 +1977,7 @@ hifn_intr(void *arg)
 		printf("%s: abort, resetting.\n", device_xname(sc->sc_dv));
 		hifnstats.hst_abort++;
 		hifn_abort(sc);
-		return (1);
+		goto out;
 	}
 
 	if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->resu == 0)) {
@@ -2026,6 +2055,8 @@ hifn_intr(void *arg)
 	}
 	dma->cmdk = i; dma->cmdu = u;
 
+out:
+	mutex_spin_exit(&sc->sc_mtx);
 	return (1);
 }
 
@@ -2039,17 +2070,21 @@ hifn_newsession(void *arg, u_int32_t *si
 {
 	struct cryptoini *c;
 	struct hifn_softc *sc = arg;
-	int i, mac = 0, cry = 0, comp = 0;
+	int i, mac = 0, cry = 0, comp = 0, retval = EINVAL;
 
 	KASSERT(sc != NULL /*, ("hifn_newsession: null softc")*/);
 	if (sidp == NULL || cri == NULL || sc == NULL)
-		return (EINVAL);
+		return retval;
+
+	mutex_spin_enter(&sc->sc_mtx);
 
 	for (i = 0; i < sc->sc_maxses; i++)
 		if (sc->sc_sessions[i].hs_state == HS_STATE_FREE)
 			break;
-	if (i == sc->sc_maxses)
-		return (ENOMEM);
+	if (i == sc->sc_maxses) {
+		retval = ENOMEM;
+		goto out;
+	}
 
 	for (c = cri; c != NULL; c = c->cri_next) {
 		switch (c->cri_alg) {
@@ -2057,8 +2092,9 @@ hifn_newsession(void *arg, u_int32_t *si
 		case CRYPTO_SHA1:
 		case CRYPTO_MD5_HMAC_96:
 		case CRYPTO_SHA1_HMAC_96:
-			if (mac)
-				return (EINVAL);
+			if (mac) {
+				goto out;
+			}
 			mac = 1;
 			break;
 		case CRYPTO_DES_CBC:
@@ -2082,35 +2118,42 @@ hifn_newsession(void *arg, u_int32_t *si
 #endif
 			/*FALLTHROUGH*/
 		case CRYPTO_ARC4:
-			if (cry)
-				return (EINVAL);
+			if (cry) {
+				goto out;
+			}
 			cry = 1;
 			break;
 #ifdef HAVE_CRYPTO_LZS
 		case CRYPTO_LZS_COMP:
-			if (comp)
-				return (EINVAL);
+			if (comp) {
+				goto out;
+			}
 			comp = 1;
 			break;
 #endif
 		default:
-			return (EINVAL);
+			goto out;
 		}
 	}
-	if (mac == 0 && cry == 0 && comp == 0)
-		return (EINVAL);
+	if (mac == 0 && cry == 0 && comp == 0) {
+		goto out;
+	}
 
 	/*
 	 * XXX only want to support compression without chaining to
 	 * MAC/crypt engine right now
 	 */
-	if ((comp && mac) || (comp && cry))
-		return (EINVAL);
+	if ((comp && mac) || (comp && cry)) {
+		goto out;
+	}
 
 	*sidp = HIFN_SID(device_unit(sc->sc_dv), i);
 	sc->sc_sessions[i].hs_state = HS_STATE_USED;
 
-	return (0);
+	retval = 0;
+out:
+	mutex_spin_exit(&sc->sc_mtx);
+	return retval;
 }
 
 /*
@@ -2129,11 +2172,15 @@ hifn_freesession(void *arg, u_int64_t ti
 	if (sc == NULL)
 		return (EINVAL);
 
+	mutex_spin_enter(&sc->sc_mtx);
 	session = HIFN_SESSION(sid);
-	if (session >= sc->sc_maxses)
+	if (session >= sc->sc_maxses) {
+		mutex_spin_exit(&sc->sc_mtx);
 		return (EINVAL);
+	}
 
 	memset(&sc->sc_sessions[session], 0, sizeof(sc->sc_sessions[session]));
+	mutex_spin_exit(&sc->sc_mtx);
 	return (0);
 }
 
@@ -2149,6 +2196,8 @@ hifn_process(void *arg, struct cryptop *
 		hifnstats.hst_invalid++;
 		return (EINVAL);
 	}
+
+	mutex_spin_enter(&sc->sc_mtx);
 	session = HIFN_SESSION(crp->crp_sid);
 
 	if (sc == NULL || session >= sc->sc_maxses) {
@@ -2377,6 +2426,7 @@ hifn_process(void *arg, struct cryptop *
 				enccrd->crd_flags & CRD_F_ENCRYPT;
 		if (sc->sc_sessions[session].hs_state == HS_STATE_USED)
 			sc->sc_sessions[session].hs_state = HS_STATE_KEY;
+		mutex_spin_exit(&sc->sc_mtx);
 		return 0;
 	} else if (err == ERESTART) {
 		/*
@@ -2390,6 +2440,7 @@ hifn_process(void *arg, struct cryptop *
 #endif
 		free(cmd, M_DEVBUF);
 		sc->sc_needwakeup |= CRYPTO_SYMQ;
+		mutex_spin_exit(&sc->sc_mtx);
 		return (err);
 	}
 
@@ -2401,6 +2452,7 @@ errout:
 	else
 		hifnstats.hst_nomem++;
 	crp->crp_etype = err;
+	mutex_spin_exit(&sc->sc_mtx);
 	crypto_done(crp);
 	return (0);
 }
@@ -2716,9 +2768,7 @@ hifn_compression(struct hifn_softc *sc, 
 	cmd->session_num = 0;
 	cmd->softc = sc;
 
-	s = splnet();
 	err = hifn_compress_enter(sc, cmd);
-	splx(s);
 
 	if (err != 0)
 		goto fail;
@@ -2745,9 +2795,6 @@ fail:
 	return (0);
 }
 
-/*
- * must be called at splnet()
- */
 static int
 hifn_compress_enter(struct hifn_softc *sc, struct hifn_command *cmd)
 {
@@ -2921,7 +2968,6 @@ hifn_callback_comp(struct hifn_softc *sc
 		bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
 		    0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
 
-		/* already at splnet... */
 		err = hifn_compress_enter(sc, cmd);
 		if (err != 0)
 			goto out;

Index: src/sys/dev/pci/ubsec.c
diff -u src/sys/dev/pci/ubsec.c:1.28 src/sys/dev/pci/ubsec.c:1.29
--- src/sys/dev/pci/ubsec.c:1.28	Sat Oct 27 17:18:35 2012
+++ src/sys/dev/pci/ubsec.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: ubsec.c,v 1.28 2012/10/27 17:18:35 chs Exp $	*/
+/*	$NetBSD: ubsec.c,v 1.29 2013/06/13 00:55:01 tls Exp $	*/
 /* $FreeBSD: src/sys/dev/ubsec/ubsec.c,v 1.6.2.6 2003/01/23 21:06:43 sam Exp $ */
 /*	$OpenBSD: ubsec.c,v 1.127 2003/06/04 14:04:58 jason Exp $	*/
 
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ubsec.c,v 1.28 2012/10/27 17:18:35 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ubsec.c,v 1.29 2013/06/13 00:55:01 tls Exp $");
 
 #undef UBSEC_DEBUG
 
@@ -48,9 +48,9 @@ __KERNEL_RCSID(0, "$NetBSD: ubsec.c,v 1.
 #include <sys/proc.h>
 #include <sys/endian.h>
 #ifdef __NetBSD__
+  #define UBSEC_NO_RNG	/* hangs on attach */
   #define letoh16 htole16
   #define letoh32 htole32
-#define UBSEC_NO_RNG		/* until statistically tested */
 #endif
 #include <sys/errno.h>
 #include <sys/malloc.h>
@@ -119,7 +119,9 @@ static	void	ubsec_mcopy(struct mbuf *, s
 static	void	ubsec_callback2(struct ubsec_softc *, struct ubsec_q2 *);
 static	void	ubsec_feed2(struct ubsec_softc *);
 #ifndef UBSEC_NO_RNG
-static	void	ubsec_rng(void *);
+static  void	ubsec_rng(void *);
+static  void	ubsec_rng_locked(void *);
+static  void	ubsec_rng_get(size_t, void *);
 #endif /* UBSEC_NO_RNG */
 static	int 	ubsec_dma_malloc(struct ubsec_softc *, bus_size_t,
 				 struct ubsec_dma_alloc *, int);
@@ -359,6 +361,9 @@ ubsec_attach(device_t parent, device_t s
 		return;
 	}
 
+	sc->sc_rng_need = RND_POOLBITS / NBBY;
+	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
+
 	SIMPLEQ_INIT(&sc->sc_freequeue);
 	dmap = sc->sc_dmaa;
 	for (i = 0; i < UBS_MAX_NQUEUE; i++, dmap++) {
@@ -430,6 +435,10 @@ ubsec_attach(device_t parent, device_t s
 			goto skip_rng;
 		}
 
+		rndsource_setcb(&sc->sc_rnd_source, ubsec_rng_get, sc);
+		rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
+				  RND_TYPE_RNG,
+				  RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
 		if (hz >= 100)
 			sc->sc_rnghz = hz / 100;
 		else
@@ -474,9 +483,11 @@ ubsec_intr(void *arg)
 	struct ubsec_dma *dmap;
 	int npkts = 0, i;
 
+	mutex_spin_enter(&sc->sc_mtx);
 	stat = READ_REG(sc, BS_STAT);
 	stat &= sc->sc_statmask;
 	if (stat == 0) {
+		mutex_spin_exit(&sc->sc_mtx);
 		return (0);
 	}
 
@@ -583,6 +594,7 @@ ubsec_intr(void *arg)
 		sc->sc_needwakeup &= ~wkeup;
 		crypto_unblock(sc->sc_cid, wkeup);
 	}
+	mutex_spin_exit(&sc->sc_mtx);
 	return (1);
 }
 
@@ -926,7 +938,7 @@ ubsec_process(void *arg, struct cryptop 
 #ifdef	__OpenBSD__
 	int card;
 #endif
-	int err = 0, i, j, s, nicealign;
+	int err = 0, i, j, nicealign;
 	struct ubsec_softc *sc;
 	struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
 	int encoffset = 0, macoffset = 0, cpskip, cpoffset;
@@ -948,18 +960,18 @@ ubsec_process(void *arg, struct cryptop 
 		return (EINVAL);
 	}
 
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 
 	if (SIMPLEQ_EMPTY(&sc->sc_freequeue)) {
 		ubsecstats.hst_queuefull++;
 		sc->sc_needwakeup |= CRYPTO_SYMQ;
-		splx(s);
+		mutex_spin_exit(&sc->sc_mtx);
 		return(ERESTART);
 	}
 
 	q = SIMPLEQ_FIRST(&sc->sc_freequeue);
 	SIMPLEQ_REMOVE_HEAD(&sc->sc_freequeue, /*q,*/ q_next);
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 
 	dmap = q->q_dma; /* Save dma pointer */
 	memset(q, 0, sizeof(struct ubsec_q));
@@ -1436,14 +1448,14 @@ ubsec_process(void *arg, struct cryptop 
 		    offsetof(struct ubsec_dmachunk, d_ctx), &ctx,
 		    sizeof(struct ubsec_pktctx));
 
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 	SIMPLEQ_INSERT_TAIL(&sc->sc_queue, q, q_next);
 	sc->sc_nqueue++;
 	ubsecstats.hst_ipackets++;
 	ubsecstats.hst_ibytes += dmap->d_alloc.dma_map->dm_mapsize;
 	if ((hint & CRYPTO_HINT_MORE) == 0 || sc->sc_nqueue >= ubsec_maxbatch)
 		ubsec_feed(sc);
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 	return (0);
 
 errout:
@@ -1460,9 +1472,9 @@ errout:
 			bus_dmamap_destroy(sc->sc_dmat, q->q_src_map);
 		}
 
-		s = splnet();
+		mutex_spin_enter(&sc->sc_mtx);
 		SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q, q_next);
-		splx(s);
+		mutex_spin_exit(&sc->sc_mtx);
 	}
 #if 0 /* jonathan says: this openbsd code seems to be subsumed elsewhere */
 	if (err == EINVAL)
@@ -1638,13 +1650,18 @@ ubsec_callback2(struct ubsec_softc *sc, 
 			add_true_randomness(letoh32(*p));
 		rng->rng_used = 0;
 #else
-		/* XXX NetBSD rnd subsystem too weak */
-		i = 0; (void)i;	/* shut off gcc warnings */
+		i = UBSEC_RNG_BUFSIZ * sizeof(u_int32_t);
+		rnd_add_data(&sc->sc_rnd_source, (char *)p, i, i * NBBY);
+		sc->sc_rng_need -= i;
+		rng->rng_used = 0;
 #endif
 #ifdef __OpenBSD__
 		timeout_add(&sc->sc_rngto, sc->sc_rnghz);
 #else
-		callout_reset(&sc->sc_rngto, sc->sc_rnghz, ubsec_rng, sc);
+		if (sc->sc_rng_need > 0) {
+			callout_reset(&sc->sc_rngto, sc->sc_rnghz,
+				      ubsec_rng, sc);
+		}
 #endif
 		break;
 	}
@@ -1727,20 +1744,48 @@ ubsec_callback2(struct ubsec_softc *sc, 
 }
 
 #ifndef UBSEC_NO_RNG
+
+static void
+ubsec_rng_get(size_t bytes, void *vsc)
+{
+	struct ubsec_softc *sc = vsc;
+
+	mutex_spin_enter(&sc->sc_mtx);
+	sc->sc_rng_need = bytes;
+	ubsec_rng_locked(sc);
+	mutex_spin_exit(&sc->sc_mtx);
+
+}
+
 static void
 ubsec_rng(void *vsc)
 {
 	struct ubsec_softc *sc = vsc;
+	mutex_spin_enter(&sc->sc_mtx);
+	ubsec_rng_locked(sc);
+	mutex_spin_exit(&sc->sc_mtx);
+}
+
+static void
+ubsec_rng_locked(void *vsc)
+{
+	struct ubsec_softc *sc = vsc;
 	struct ubsec_q2_rng *rng = &sc->sc_rng;
 	struct ubsec_mcr *mcr;
 	struct ubsec_ctx_rngbypass *ctx;
-	int s;
 
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 	if (rng->rng_used) {
-		splx(s);
+		mutex_spin_exit(&sc->sc_mtx);
 		return;
 	}
+
+	if (sc->sc_rng_need < 1) {
+		callout_stop(&sc->sc_rngto);
+		mutex_spin_exit(&sc->sc_mtx);
+		return;
+	}
+
 	sc->sc_nqueue2++;
 	if (sc->sc_nqueue2 >= UBS_MAX_NQUEUE)
 		goto out;
@@ -1770,7 +1815,7 @@ ubsec_rng(void *vsc)
 	rng->rng_used = 1;
 	ubsec_feed2(sc);
 	ubsecstats.hst_rng++;
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 
 	return;
 
@@ -1779,7 +1824,7 @@ out:
 	 * Something weird happened, generate our own call back.
 	 */
 	sc->sc_nqueue2--;
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 #ifdef __OpenBSD__
 	timeout_add(&sc->sc_rngto, sc->sc_rnghz);
 #else
@@ -2097,7 +2142,7 @@ ubsec_kprocess_modexp_sw(struct ubsec_so
 	struct ubsec_mcr *mcr;
 	struct ubsec_ctx_modexp *ctx;
 	struct ubsec_pktbuf *epb;
-	int s, err = 0;
+	int err = 0;
 	u_int nbits, normbits, mbits, shiftbits, ebits;
 
 	me = (struct ubsec_q2_modexp *)malloc(sizeof *me, M_DEVBUF, M_NOWAIT);
@@ -2254,11 +2299,11 @@ ubsec_kprocess_modexp_sw(struct ubsec_so
 	    0, me->me_epb.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
 
 	/* Enqueue and we're done... */
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 	SIMPLEQ_INSERT_TAIL(&sc->sc_queue2, &me->me_q, q_next);
 	ubsec_feed2(sc);
 	ubsecstats.hst_modexp++;
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 
 	return (0);
 
@@ -2302,7 +2347,7 @@ ubsec_kprocess_modexp_hw(struct ubsec_so
 	struct ubsec_mcr *mcr;
 	struct ubsec_ctx_modexp *ctx;
 	struct ubsec_pktbuf *epb;
-	int s, err = 0;
+	int err = 0;
 	u_int nbits, normbits, mbits, shiftbits, ebits;
 
 	me = (struct ubsec_q2_modexp *)malloc(sizeof *me, M_DEVBUF, M_NOWAIT);
@@ -2459,10 +2504,10 @@ ubsec_kprocess_modexp_hw(struct ubsec_so
 	    0, me->me_epb.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
 
 	/* Enqueue and we're done... */
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 	SIMPLEQ_INSERT_TAIL(&sc->sc_queue2, &me->me_q, q_next);
 	ubsec_feed2(sc);
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 
 	return (0);
 
@@ -2502,7 +2547,7 @@ ubsec_kprocess_rsapriv(struct ubsec_soft
 	struct ubsec_q2_rsapriv *rp = NULL;
 	struct ubsec_mcr *mcr;
 	struct ubsec_ctx_rsapriv *ctx;
-	int s, err = 0;
+	int err = 0;
 	u_int padlen, msglen;
 
 	msglen = ubsec_ksigbits(&krp->krp_param[UBS_RSAPRIV_PAR_P]);
@@ -2655,11 +2700,11 @@ ubsec_kprocess_rsapriv(struct ubsec_soft
 	    0, rp->rpr_msgout.dma_map->dm_mapsize, BUS_DMASYNC_PREREAD);
 
 	/* Enqueue and we're done... */
-	s = splnet();
+	mutex_spin_enter(&sc->sc_mtx);
 	SIMPLEQ_INSERT_TAIL(&sc->sc_queue2, &rp->rpr_q, q_next);
 	ubsec_feed2(sc);
 	ubsecstats.hst_modexpcrt++;
-	splx(s);
+	mutex_spin_exit(&sc->sc_mtx);
 	return (0);
 
 errout:

Index: src/sys/dev/pci/ubsecvar.h
diff -u src/sys/dev/pci/ubsecvar.h:1.4 src/sys/dev/pci/ubsecvar.h:1.5
--- src/sys/dev/pci/ubsecvar.h:1.4	Sat Oct 27 17:18:35 2012
+++ src/sys/dev/pci/ubsecvar.h	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: ubsecvar.h,v 1.4 2012/10/27 17:18:35 chs Exp $	*/
+/*	$NetBSD: ubsecvar.h,v 1.5 2013/06/13 00:55:01 tls Exp $	*/
 /*	$OpenBSD: ubsecvar.h,v 1.36 2003/06/04 16:02:41 jason Exp $	*/
 
 /*
@@ -149,6 +149,7 @@ struct ubsec_q {
 struct ubsec_softc {
 	device_t		sc_dev;		/* generic device */
 	void			*sc_ih;		/* interrupt handler cookie */
+	kmutex_t		sc_mtx;
 	bus_space_handle_t	sc_sh;		/* memory handle */
 	bus_space_tag_t		sc_st;		/* memory tag */
 	bus_dma_tag_t		sc_dmat;	/* dma tag */
@@ -170,6 +171,8 @@ struct ubsec_softc {
 	struct callout		sc_rngto;	/* rng timeout */
 	int			sc_rnghz;	/* rng poll time */
 	struct ubsec_q2_rng	sc_rng;
+	krndsource_t		sc_rnd_source;
+	int			sc_rng_need;	/* how many bytes wanted */
 	struct ubsec_dma	sc_dmaa[UBS_MAX_NQUEUE];
 	struct ubsec_q		*sc_queuea[UBS_MAX_NQUEUE];
 	SIMPLEQ_HEAD(,ubsec_q2)	sc_q2free;	/* free list */

Index: src/sys/dev/scsipi/sd.c
diff -u src/sys/dev/scsipi/sd.c:1.300 src/sys/dev/scsipi/sd.c:1.301
--- src/sys/dev/scsipi/sd.c:1.300	Wed May 29 00:47:49 2013
+++ src/sys/dev/scsipi/sd.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: sd.c,v 1.300 2013/05/29 00:47:49 christos Exp $	*/
+/*	$NetBSD: sd.c,v 1.301 2013/06/13 00:55:01 tls Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@@ -47,7 +47,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.300 2013/05/29 00:47:49 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.301 2013/06/13 00:55:01 tls Exp $");
 
 #include "opt_scsi.h"
 
@@ -215,7 +215,7 @@ sdattach(device_t parent, device_t self,
 	struct sd_softc *sd = device_private(self);
 	struct scsipibus_attach_args *sa = aux;
 	struct scsipi_periph *periph = sa->sa_periph;
-	int error, result, rndval = cprng_strong32();
+	int error, result;
 	struct disk_parms *dp = &sd->params;
 	char pbuf[9];
 
@@ -328,16 +328,16 @@ sdattach(device_t parent, device_t self,
 	 * these bits, on insertion, because the deltas to the
 	 * nonexistent) previous event should never allow it.
 	 */
-	rnd_add_uint32(&sd->rnd_source, rndval);
+	rnd_add_uint32(&sd->rnd_source, 0);
 }
 
 static int
 sddetach(device_t self, int flags)
 {
 	struct sd_softc *sd = device_private(self);
-	int s, bmaj, cmaj, i, mn, rc, rndval = cprng_strong32();
+	int s, bmaj, cmaj, i, mn, rc;
 
-	rnd_add_uint32(&sd->rnd_source, rndval);
+	rnd_add_uint32(&sd->rnd_source, 0);
 
 	if ((rc = disk_begindetach(&sd->sc_dk, sdlastclose, self, flags)) != 0)
 		return rc;

Index: src/sys/kern/kern_rndpool.c
diff -u src/sys/kern/kern_rndpool.c:1.2 src/sys/kern/kern_rndpool.c:1.3
--- src/sys/kern/kern_rndpool.c:1.2	Tue Apr 17 02:50:38 2012
+++ src/sys/kern/kern_rndpool.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*      $NetBSD: kern_rndpool.c,v 1.2 2012/04/17 02:50:38 tls Exp $        */
+/*      $NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $        */
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.2 2012/04/17 02:50:38 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -51,9 +51,12 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndpool
 
 /*
  * Let others know: the pool is full.
+ *
+ * XXX these should be per-pool if we really mean to allow multiple pools.
  */
 int rnd_full = 0;			/* Flag: is the pool full? */
 int rnd_filled = 0;			/* Count: how many times filled? */
+int rnd_empty = 1;			/* Flag: is the pool empty? */
 
 static inline void rndpool_add_one_word(rndpool_t *, u_int32_t);
 

Index: src/sys/kern/kern_rndq.c
diff -u src/sys/kern/kern_rndq.c:1.10 src/sys/kern/kern_rndq.c:1.11
--- src/sys/kern/kern_rndq.c:1.10	Sat Jan 26 22:22:07 2013
+++ src/sys/kern/kern_rndq.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_rndq.c,v 1.10 2013/01/26 22:22:07 tls Exp $	*/
+/*	$NetBSD: kern_rndq.c,v 1.11 2013/06/13 00:55:01 tls Exp $	*/
 
 /*-
  * Copyright (c) 1997-2013 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.10 2013/01/26 22:22:07 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.11 2013/06/13 00:55:01 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,
 #include <sys/conf.h>
 #include <sys/systm.h>
 #include <sys/callout.h>
+#include <sys/intr.h>
 #include <sys/rnd.h>
 #include <sys/vnode.h>
 #include <sys/pool.h>
@@ -99,10 +100,13 @@ typedef struct _rnd_sample_t {
  * The event queue.  Fields are altered at an interrupt level.
  * All accesses must be protected with the mutex.
  */
-volatile int			rnd_timeout_pending;
 SIMPLEQ_HEAD(, _rnd_sample_t)	rnd_samples;
 kmutex_t			rnd_mtx;
 
+/*
+ * This lock protects dispatch of our soft interrupts.
+ */
+kmutex_t			rndsoft_mtx;
 
 /*
  * Entropy sinks: usually other generators waiting to be rekeyed.
@@ -149,14 +153,15 @@ static krndsource_t rnd_source_no_collec
 	.test_cnt = 0,
 	.test = NULL
 };
-
-struct callout rnd_callout, skew_callout;
+void *rnd_process, *rnd_wakeup;
+struct callout skew_callout;
 
 void	      rnd_wakeup_readers(void);
 static inline u_int32_t rnd_estimate_entropy(krndsource_t *, u_int32_t);
 static inline u_int32_t rnd_counter(void);
-static        void	rnd_timeout(void *);
-static	      void	rnd_process_events(void *);
+static        void	rnd_intr(void *);
+static	      void	rnd_wake(void *);
+static	      void	rnd_process_events(void);
 u_int32_t     rnd_extract_data_locked(void *, u_int32_t, u_int32_t); /* XXX */
 static	      void	rnd_add_data_ts(krndsource_t *, const void *const,
 					uint32_t, uint32_t, uint32_t);
@@ -196,22 +201,101 @@ rnd_counter(void)
 }
 
 /*
+ * We may be called from low IPL -- protect our softint.
+ */
+
+static inline void
+rnd_schedule_softint(void *softint)
+{
+	mutex_spin_enter(&rndsoft_mtx);
+	softint_schedule(softint);
+	mutex_spin_exit(&rndsoft_mtx);
+}
+
+/*
+ * XXX repulsive: we can't initialize our softints in rnd_init
+ * XXX (too early) so we wrap the points where we'd schedule them, thus.
+ */
+static inline void
+rnd_schedule_process(void)
+{
+	if (__predict_true(rnd_process)) {
+		rnd_schedule_softint(rnd_process);
+		return;
+	}
+	if (!cold) {
+		rnd_process = softint_establish(SOFTINT_SERIAL|SOFTINT_MPSAFE,
+						rnd_intr, NULL);
+	} 
+	rnd_process_events();
+}
+
+static inline void
+rnd_schedule_wakeup(void)
+{
+	if (__predict_true(rnd_wakeup)) {
+		rnd_schedule_softint(rnd_wakeup);
+		return;
+	}
+	if (!cold) {
+		rnd_wakeup = softint_establish(SOFTINT_CLOCK|SOFTINT_MPSAFE,
+					       rnd_wake, NULL);
+	}
+	rnd_wakeup_readers();
+}
+
+/*
+ * Tell any sources with "feed me" callbacks that we are hungry.
+ */
+static void 
+rnd_getmore(size_t byteswanted)
+{
+	krndsource_t *rs; 
+
+	KASSERT(mutex_owned(&rndpool_mtx));
+
+	LIST_FOREACH(rs, &rnd_sources, list) {
+		if (rs->flags & RND_FLAG_HASCB) {
+			KASSERT(rs->get != NULL);
+			KASSERT(rs->getarg != NULL);
+			rs->get((size_t)byteswanted, rs->getarg);
+#ifdef RND_VERBOSE
+			printf("rnd: asking source %s for %d bytes\n",
+			       rs->name, (int)byteswanted);
+#endif
+		}    
+	}    
+}
+
+/*
  * Check to see if there are readers waiting on us.  If so, kick them.
  */
 void
 rnd_wakeup_readers(void)
 {
 	rndsink_t *sink, *tsink;
+	size_t	entropy_count;
 	TAILQ_HEAD(, rndsink) sunk = TAILQ_HEAD_INITIALIZER(sunk);
 
 	mutex_spin_enter(&rndpool_mtx);
-	if (rndpool_get_entropy_count(&rnd_pool) < RND_ENTROPY_THRESHOLD * 8) {
+	entropy_count = rndpool_get_entropy_count(&rnd_pool);
+	if (entropy_count < RND_ENTROPY_THRESHOLD * 8) {
+		rnd_empty = 1;
 		mutex_spin_exit(&rndpool_mtx);
 		return;
+	} else {
+#ifdef RND_VERBOSE
+		if (__predict_false(!rnd_initial_entropy)) {
+			printf("rnd: have initial entropy (%u)\n",
+			       (unsigned int)entropy_count);
+		}
+#endif
+		rnd_empty = 0;
+		rnd_initial_entropy = 1;
 	}
 
 	/*
-	 * First, take care of in-kernel consumers needing rekeying.
+	 * First, take care of consumers needing rekeying.
 	 */
 	mutex_spin_enter(&rndsink_mtx);
 	TAILQ_FOREACH_SAFE(sink, &rnd_sinks, tailq, tsink) {
@@ -225,8 +309,7 @@ rnd_wakeup_readers(void)
 
 		KASSERT(RSTATE_PENDING == sink->state);
 		
-		if ((sink->len + RND_ENTROPY_THRESHOLD) * 8 <
-			rndpool_get_entropy_count(&rnd_pool)) {
+		if (sink->len * 8 < rndpool_get_entropy_count(&rnd_pool)) {
 			/* We have enough entropy to sink some here. */
 			if (rndpool_extract_data(&rnd_pool, sink->data,
 						 sink->len, RND_EXTRACT_GOOD)
@@ -239,28 +322,20 @@ rnd_wakeup_readers(void)
 			TAILQ_REMOVE(&rnd_sinks, sink, tailq);
 			TAILQ_INSERT_HEAD(&sunk, sink, tailq);
 		} else {
-			mutex_exit(&sink->mtx);
-		}
-	}
-	mutex_spin_exit(&rndsink_mtx);
-		
-	/*
-	 * If we still have enough new bits to do something, feed userspace.
-	 */
-	if (rndpool_get_entropy_count(&rnd_pool) > RND_ENTROPY_THRESHOLD * 8) {
 #ifdef RND_VERBOSE
-		if (!rnd_initial_entropy)
-			printf("rnd: have initial entropy (%u)\n",
-			       rndpool_get_entropy_count(&rnd_pool));
+			printf("sink wants %d, we have %d, asking for more\n",
+			       (int)sink->len * 8,
+			       (int)rndpool_get_entropy_count(&rnd_pool));
 #endif
-		rnd_initial_entropy = 1;
-		mutex_spin_exit(&rndpool_mtx);
-	} else {
-		mutex_spin_exit(&rndpool_mtx);
+			mutex_spin_exit(&sink->mtx);
+			rnd_getmore(sink->len * 8);
+		}
 	}
+	mutex_spin_exit(&rndsink_mtx);
+	mutex_spin_exit(&rndpool_mtx);
 
 	/*
-	 * Now that we have dropped the mutex, we can run sinks' callbacks.
+	 * Now that we have dropped the mutexes, we can run sinks' callbacks.
 	 * Since we have reused the "tailq" member of the sink structure for
 	 * this temporary on-stack queue, the callback must NEVER re-add
 	 * the sink to the main queue, or our on-stack queue will become
@@ -378,9 +453,7 @@ rnd_init(void)
 
 	mutex_init(&rnd_mtx, MUTEX_DEFAULT, IPL_VM);
 	mutex_init(&rndsink_mtx, MUTEX_DEFAULT, IPL_VM);
-
-	callout_init(&rnd_callout, CALLOUT_MPSAFE);
-	callout_setfunc(&rnd_callout, rnd_timeout, NULL);
+	mutex_init(&rndsoft_mtx, MUTEX_DEFAULT, IPL_VM);
 
 	/*
 	 * take a counter early, hoping that there's some variance in
@@ -757,26 +830,10 @@ rnd_add_data_ts(krndsource_t *rs, const 
 		SIMPLEQ_REMOVE_HEAD(&tmp_samples, next);
 		SIMPLEQ_INSERT_HEAD(&rnd_samples, state, next);
 	}
-
-	/*
-	 * If we are still starting up, cause immediate processing of
-	 * the queued samples.  Otherwise, if the timeout isn't
-	 * pending, have it run in the near future.
-	 */
-	if (__predict_false(cold)) {
-#ifdef RND_VERBOSE
-		printf("rnd: directly processing boot-time events.\n");
-#endif
-		rnd_process_events(NULL);	/* Drops lock! */
-		return;
-	}
-	if (rnd_timeout_pending == 0) {
-		rnd_timeout_pending = 1;
-		mutex_spin_exit(&rnd_mtx);
-		callout_schedule(&rnd_callout, 1);
-		return;
-	}
 	mutex_spin_exit(&rnd_mtx);
+
+	/* Cause processing of queued samples */
+	rnd_schedule_process();
 }
 
 static int
@@ -837,14 +894,16 @@ rnd_hwrng_test(rnd_sample_t *sample)
  * by the add routines directly if the callout has never fired (that
  * is, if we are "cold" -- just booted).
  *
- * Call with rnd_mtx held -- WILL RELEASE IT.
  */
 static void
-rnd_process_events(void *arg)
+rnd_process_events(void)
 {
-	rnd_sample_t *sample;
+	rnd_sample_t *sample = NULL;
 	krndsource_t *source, *badsource = NULL;
+	static krndsource_t *last_source;
 	u_int32_t entropy;
+	size_t pool_entropy;
+	int found = 0, wake = 0;
 	SIMPLEQ_HEAD(, _rnd_sample_t) dq_samples =
 			SIMPLEQ_HEAD_INITIALIZER(dq_samples);
 	SIMPLEQ_HEAD(, _rnd_sample_t) df_samples =
@@ -856,7 +915,9 @@ rnd_process_events(void *arg)
 	 * and drop lock.
 	 */
 
+	mutex_spin_enter(&rnd_mtx);
 	while ((sample = SIMPLEQ_FIRST(&rnd_samples))) {
+		found++;
 		SIMPLEQ_REMOVE_HEAD(&rnd_samples, next);
 		/*
 		 * We repeat this check here, since it is possible
@@ -874,12 +935,36 @@ rnd_process_events(void *arg)
 
 	/* Don't thrash the rndpool mtx either.  Hold, add all samples. */
 	mutex_spin_enter(&rndpool_mtx);
+
+	pool_entropy = rndpool_get_entropy_count(&rnd_pool);
+	if (pool_entropy > RND_ENTROPY_THRESHOLD * 8) {
+		wake++;
+	} else {
+		rnd_empty = 1;
+		rnd_getmore((RND_POOLBITS - pool_entropy) / 8);
+#ifdef RND_VERBOSE
+		printf("rnd: empty, asking for %d bits\n",
+		       (int)((RND_POOLBITS - pool_entropy) / 8));
+#endif
+	}
+
 	while ((sample = SIMPLEQ_FIRST(&dq_samples))) {
 		SIMPLEQ_REMOVE_HEAD(&dq_samples, next);
 		source = sample->source;
 		entropy = sample->entropy;
 
 		/*
+		 * Don't provide a side channel for timing attacks on
+		 * low-rate sources: require mixing with some other
+		 * source before we schedule a wakeup.
+		 */
+		if (!wake &&
+		    (source != last_source || source->flags & RND_FLAG_FAST)) {
+			wake++;
+		}
+		last_source = source;
+
+		/*
 		 * Hardware generators are great but sometimes they
 		 * have...hardware issues.  Don't use any data from
 		 * them unless it passes some tests.
@@ -925,27 +1010,32 @@ rnd_process_events(void *arg)
 		rnd_sample_free(sample);
 	}
 
+	
 	/*
 	 * Wake up any potential readers waiting.
 	 */
-	rnd_wakeup_readers();
+	if (wake) {
+		rnd_schedule_wakeup();
+	}
 }
 
-/*
- * Timeout, run to process the events in the ring buffer.
- */
 static void
-rnd_timeout(void *arg)
+rnd_intr(void *arg)
 {
-        mutex_spin_enter(&rnd_mtx);
-        rnd_timeout_pending = 0;
-        rnd_process_events(arg);
+	rnd_process_events();
+}
+
+static void
+rnd_wake(void *arg)
+{
+	rnd_wakeup_readers();
 }
 
 u_int32_t
 rnd_extract_data_locked(void *p, u_int32_t len, u_int32_t flags)
 {
 	static int timed_in;
+	int entropy_count;
 
 	KASSERT(mutex_owned(&rndpool_mtx));
 	if (__predict_false(!timed_in)) {
@@ -969,8 +1059,6 @@ rnd_extract_data_locked(void *p, u_int32
 
 #ifdef DIAGNOSTIC
 	while (!rnd_tested) {
-		int entropy_count;
-
 		entropy_count = rndpool_get_entropy_count(&rnd_pool);
 #ifdef RND_VERBOSE
 		printf("rnd: starting statistical RNG test, entropy = %d.\n",
@@ -1012,6 +1100,10 @@ rnd_extract_data_locked(void *p, u_int32
 		rnd_tested++;
 	}
 #endif
+	entropy_count = rndpool_get_entropy_count(&rnd_pool);
+	if (entropy_count < (RND_ENTROPY_THRESHOLD * 2 + len) * 8) {
+		rnd_getmore(RND_POOLBITS - entropy_count * 8);
+	}
 	return rndpool_extract_data(&rnd_pool, p, len, flags);
 }
 
@@ -1041,13 +1133,7 @@ rndsink_attach(rndsink_t *rs)
 	TAILQ_INSERT_TAIL(&rnd_sinks, rs, tailq);
 	mutex_spin_exit(&rndsink_mtx);
 
-	mutex_spin_enter(&rnd_mtx);
-	if (rnd_timeout_pending == 0) {
-		rnd_timeout_pending = 1;
-		callout_schedule(&rnd_callout, 1);
-	}
-	mutex_spin_exit(&rnd_mtx);
-
+	rnd_schedule_process();
 }
 
 void

Index: src/sys/kern/subr_cprng.c
diff -u src/sys/kern/subr_cprng.c:1.16 src/sys/kern/subr_cprng.c:1.17
--- src/sys/kern/subr_cprng.c:1.16	Thu Mar 28 18:06:48 2013
+++ src/sys/kern/subr_cprng.c	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_cprng.c,v 1.16 2013/03/28 18:06:48 tls Exp $ */
+/*	$NetBSD: subr_cprng.c,v 1.17 2013/06/13 00:55:01 tls Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -46,7 +46,7 @@
 
 #include <sys/cprng.h>
 
-__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.16 2013/03/28 18:06:48 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.17 2013/06/13 00:55:01 tls Exp $");
 
 void
 cprng_init(void)
@@ -200,8 +200,17 @@ cprng_strong_create(const char *const na
 	if (r != sizeof(key)) {
 		if (c->flags & CPRNG_INIT_ANY) {
 #ifdef DEBUG
-			printf("cprng %s: WARNING insufficient "
-			       "entropy at creation.\n", name);
+			/*
+			 * If we have ever crossed the pool's
+			 * minimum-entropy threshold, then we are
+			 * providing cryptographically strong
+			 * random output -- if not information-
+			 * theoretically strong.  Warn elsewise.
+			 */
+			if (!rnd_initial_entropy) {
+				printf("cprng %s: WARNING insufficient "
+			 		"entropy at creation.\n", name);
+			}
 #endif
 		} else {
 			hard++;

Index: src/sys/sys/rnd.h
diff -u src/sys/sys/rnd.h:1.35 src/sys/sys/rnd.h:1.36
--- src/sys/sys/rnd.h:1.35	Sat Jan 26 19:05:11 2013
+++ src/sys/sys/rnd.h	Thu Jun 13 00:55:01 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: rnd.h,v 1.35 2013/01/26 19:05:11 tls Exp $	*/
+/*	$NetBSD: rnd.h,v 1.36 2013/06/13 00:55:01 tls Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -92,6 +92,7 @@ typedef struct {
 #define	RND_FLAG_NO_ESTIMATE	0x00000100	/* don't estimate entropy */
 #define	RND_FLAG_NO_COLLECT	0x00000200	/* don't collect entropy */
 #define RND_FLAG_FAST		0x00000400	/* process samples in bulk */
+#define RND_FLAG_HASCB		0x00000800	/* has get callback */
 
 #define	RND_TYPE_UNKNOWN	0	/* unknown source */
 #define	RND_TYPE_DISK		1	/* source is physical disk */
@@ -127,8 +128,17 @@ typedef struct krndsource {
         void            *state;         /* state information */
         size_t          test_cnt;       /* how much test data accumulated? */
         rngtest_t	*test;          /* test data for RNG type sources */
+	void		(*get)(size_t, void *);	/* pool wants N bytes (badly) */
+	void		*getarg;	/* argument to get-function */
 } krndsource_t;
 
+static inline void
+rndsource_setcb(struct krndsource *const rs, void *const cb, void *const arg)
+{
+	rs->get = cb;
+	rs->getarg = arg;
+}
+
 enum rsink_st {
 	RSTATE_IDLE = 0,
 	RSTATE_PENDING,
@@ -186,6 +196,7 @@ rnd_add_uint32(krndsource_t *kr, uint32_
 	}
 }
 
+extern int	rnd_empty;
 extern int	rnd_full;
 extern int	rnd_filled;
 extern int	rnd_initial_entropy;

Reply via email to