Module Name:    src
Committed By:   jakllsch
Date:           Fri Jul 23 00:43:21 UTC 2010

Modified Files:
        src/sys/arch/amd64/conf: GENERIC
        src/sys/arch/i386/conf: GENERIC
        src/sys/arch/x86/pci: files.pci i82802reg.h ichlpcib.c pchb.c pchbvar.h
Added Files:
        src/sys/arch/x86/pci: fwhrng.c
Removed Files:
        src/sys/arch/x86/pci: pchb_rnd.c

Log Message:
Almost entirely rework Intel Firmware Hub random number generator support.

This introduces fwhrng(4) which attaches via ichlpcib(4), replacing
the rnd(4) support in pchb(4).


To generate a diff of this commit:
cvs rdiff -u -r1.282 -r1.283 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.987 -r1.988 src/sys/arch/i386/conf/GENERIC
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/x86/pci/files.pci
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/pci/fwhrng.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/x86/pci/i82802reg.h
cvs rdiff -u -r1.24 -r1.25 src/sys/arch/x86/pci/ichlpcib.c
cvs rdiff -u -r1.22 -r1.23 src/sys/arch/x86/pci/pchb.c
cvs rdiff -u -r1.9 -r0 src/sys/arch/x86/pci/pchb_rnd.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/x86/pci/pchbvar.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/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.282 src/sys/arch/amd64/conf/GENERIC:1.283
--- src/sys/arch/amd64/conf/GENERIC:1.282	Sun Jul 18 09:29:11 2010
+++ src/sys/arch/amd64/conf/GENERIC	Fri Jul 23 00:43:20 2010
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.282 2010/07/18 09:29:11 jruoho Exp $
+# $NetBSD: GENERIC,v 1.283 2010/07/23 00:43:20 jakllsch Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.282 $"
+#ident 		"GENERIC-$Revision: 1.283 $"
 
 maxusers	64		# estimated number of users
 
@@ -336,8 +336,9 @@
 #amdpcib* at pci? dev ? function ?	# AMD 8111 PCI-ISA w/ HPET
 #hpet* 	at amdpcib?
 
-ichlpcib* at pci? dev ? function ?	# Intel ICH PCI-ISA w/ timecounter,
-					# watchdog and Speedstep support.
+ichlpcib* at pci? dev ? function ?	# Intel ICH PCI-LPC w/ timecounter,
+					# watchdog and Speedstep and HPET
+fwhrng* at ichlpcib?		# Intel 82802 FWH Random Number Generator
 #hpet* 	at ichlpcib?
 
 aapic* 	at pci? dev ? function ?	# AMD 8131 IO apic

Index: src/sys/arch/i386/conf/GENERIC
diff -u src/sys/arch/i386/conf/GENERIC:1.987 src/sys/arch/i386/conf/GENERIC:1.988
--- src/sys/arch/i386/conf/GENERIC:1.987	Sun Jul 18 09:29:12 2010
+++ src/sys/arch/i386/conf/GENERIC	Fri Jul 23 00:43:20 2010
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.987 2010/07/18 09:29:12 jruoho Exp $
+# $NetBSD: GENERIC,v 1.988 2010/07/23 00:43:20 jakllsch Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.987 $"
+#ident 		"GENERIC-$Revision: 1.988 $"
 
 maxusers	64		# estimated number of users
 
@@ -457,8 +457,9 @@
 # PCI bridges
 #amdpcib* at pci? dev ? function ?	# AMD 8111 PCI-ISA w/ HPET
 #hpet* 	at amdpcib?
-ichlpcib* at pci? dev ? function ?	# Intel ICH PCI-ISA w/ timecounter,
+ichlpcib* at pci? dev ? function ?	# Intel ICH PCI-LPC w/ timecounter,
 					# watchdog, SpeedStep and HPET
+fwhrng* at ichlpcib?		# Intel 82802 FWH Random Number Generator
 #hpet* 	at ichlpcib?
 gcscpcib* at pci? dev ? function ?	# AMD CS5535/CS5536 PCI-ISA w/
 gpio* 	at gcscpcib?			# timecounter, watchdog and GPIO

Index: src/sys/arch/x86/pci/files.pci
diff -u src/sys/arch/x86/pci/files.pci:1.9 src/sys/arch/x86/pci/files.pci:1.10
--- src/sys/arch/x86/pci/files.pci:1.9	Fri May 14 18:11:25 2010
+++ src/sys/arch/x86/pci/files.pci	Fri Jul 23 00:43:21 2010
@@ -1,4 +1,4 @@
-#	$NetBSD: files.pci,v 1.9 2010/05/14 18:11:25 phx Exp $
+#	$NetBSD: files.pci,v 1.10 2010/07/23 00:43:21 jakllsch Exp $
 
 device 	aapic
 attach 	aapic at pci
@@ -11,7 +11,6 @@
 		agp_intel, agp_sis, agp_via
 attach	pchb at pci
 file	arch/x86/pci/pchb.c		pchb		needs-flag
-file	arch/x86/pci/pchb_rnd.c		pchb & rnd
 
 # PCI-ISA bridges
 device	pcib: isabus
@@ -32,9 +31,14 @@
 file	arch/x86/pci/amdtemp.c		amdtemp
 
 # PCI-LPC bridges
+define	fwhichbus {}
 define	hpetichbus {}
-device	ichlpcib: acpipmtimer, isabus, sysmon_wdog, hpetichbus, gpiobus
+device	ichlpcib: acpipmtimer, isabus, sysmon_wdog, fwhichbus, hpetichbus, gpiobus
 attach	ichlpcib at pci
 attach	hpet at hpetichbus with ichlpcib_hpet
 
 file 	arch/x86/pci/ichlpcib.c 	ichlpcib
+
+device	fwhrng
+attach	fwhrng at fwhichbus
+file	arch/x86/pci/fwhrng.c		fwhrng needs-flag

Index: src/sys/arch/x86/pci/i82802reg.h
diff -u src/sys/arch/x86/pci/i82802reg.h:1.2 src/sys/arch/x86/pci/i82802reg.h:1.3
--- src/sys/arch/x86/pci/i82802reg.h:1.2	Tue Nov  3 01:19:35 2009
+++ src/sys/arch/x86/pci/i82802reg.h	Fri Jul 23 00:43:21 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: i82802reg.h,v 1.2 2009/11/03 01:19:35 snj Exp $	*/
+/*	$NetBSD: i82802reg.h,v 1.3 2010/07/23 00:43:21 jakllsch Exp $	*/
 
 /*
  * Copyright (c) 2000 Michael Shalayeff
@@ -34,33 +34,42 @@
  */
 
 /*
- * unfortunatelly FWH does not show up in the pci device scan, 10x intel.
- * so all we do is probe for it in the pchb driver at the following address.
+ * MMIO bases and sizes
  */
-#define	I82802_IOBASE	0xffb00000
-#define	I82802_IOSIZE	0x00100000
-
-/*
- * FWH registers
- * (table 4-4)
- */
-#define	I82802_BLOCK_LK		0xf0002
-#define	I82802_MINUS01_LK	0xe0002
-#define	I82802_MINUS02_LK	0xd0002
-#define	I82802_MINUS03_LK	0xc0002
-#define	I82802_MINUS04_LK	0xb0002
-#define	I82802_MINUS05_LK	0xa0002
-#define	I82802_MINUS06_LK	0x90002
-#define	I82802_MINUS07_LK	0x80002
-#define	I82802_MINUS08_LK	0x70002
-#define	I82802_MINUS09_LK	0x60002
-#define	I82802_MINUS10_LK	0x50002
-#define	I82802_MINUS11_LK	0x40002
-#define	I82802_MINUS12_LK	0x30002
-#define	I82802_MINUS13_LK	0x20002
-#define	I82802_MINUS14_LK	0x10002
-#define	I82802_MINUS15_LK	0x00002
-#define	I82802_FGPI_REG		0xc0100
+#define	I82802AC_REGBASE	0xffb00000
+#define	I82802AC_MEMBASE	0xfff00000
+#define	I82802AC_WINSIZE	0x00100000
+
+#define I82802_MFG	0x89
+#define I82802AB_ID	0xad
+#define I82802AC_ID	0xac
+
+/*
+ * Intel FWH registers
+ */
+#define	I82802_T_BLOCK_LK	0xf0002
+#define	I82802_T_MINUS01_LK	0xe0002
+#define	I82802_T_MINUS02_LK	0xd0002
+#define	I82802_T_MINUS03_LK	0xc0002
+#define	I82802_T_MINUS04_LK	0xb0002
+#define	I82802_T_MINUS05_LK	0xa0002
+#define	I82802_T_MINUS06_LK	0x90002
+#define	I82802_T_MINUS07_LK	0x80002
+
+#define	I82802_T_MINUS08_LK	0x70002
+#define	I82802_T_MINUS09_LK	0x60002
+#define	I82802_T_MINUS10_LK	0x50002
+#define	I82802_T_MINUS11_LK	0x40002
+#define	I82802_T_MINUS12_LK	0x30002
+#define	I82802_T_MINUS13_LK	0x20002
+#define	I82802_T_MINUS14_LK	0x10002
+#define	I82802_T_MINUS15_LK	0x00002
+
+#define	I82802_GPI_REG		0xc0100
+
+#define	I82802_RNG_HSR		0xc015f /* Hardware Status */
+#define	I82802_RNG_DSR		0xc0160 /* Data Status */
+#define	I82802_RNG_DR		0xc0161 /* Data */
 
 /*
  * T_BLOCK_LK and T_MINUS_* (block locking registers)
@@ -71,30 +80,18 @@
 #define	I82802_BLR_WL		0x01
 
 /*
- * Register Based Locking Value Definitions
- * (tabe 4-6)
- */
-#define	I82802_LV_FULL		0x00
-#define	I82802_LV_WRITE		0x01
-#define	I82802_LV_DOWN		0x02
-#define	I82802_LV_READ		0x04
-
-/*
  * General Purpose Inputs Register
  * (table 4-7)
- */
-#define	I82802_FGPI_PIN4	0x10	/* PLCC-30/T SOP-7  */
-#define	I82802_FGPI_PIN3	0x08	/* PLCC-30/T SOP-15 */
-#define	I82802_FGPI_PIN2	0x04	/* PLCC-30/T SOP-16 */
-#define	I82802_FGPI_PIN1	0x02	/* PLCC-30/T SOP-17 */
-#define	I82802_FGPI_PIN0	0x01	/* PLCC-30/T SOP-18 */
+ */					/* PLCC32/TSOP40 pin # */
+#define	I82802_GPI_REG_FGPI4	0x10	/*    30 /  7    */
+#define	I82802_GPI_REG_FGPI3	0x08	/*     3 / 15    */
+#define	I82802_GPI_REG_FGPI2	0x04	/*     4 / 16    */
+#define	I82802_GPI_REG_FGPI1	0x02	/*     5 / 17    */
+#define	I82802_GPI_REG_FGPI0	0x01	/*     6 / 18    */
 
 /*
  * RNG registers
  */
-#define	I82802_RNG_HWST		0xc015f
-#define	I82802_RNG_HWST_PRESENT	0x40
-#define	I82802_RNG_HWST_ENABLE	0x01
-#define	I82802_RNG_RNGST	0xc0160
-#define	I82802_RNG_RNGST_DATAV	0x01
-#define	I82802_RNG_DATA		0xc0161
+#define	I82802_RNG_HSR_PRESENT	0x40
+#define	I82802_RNG_HSR_ENABLE	0x01
+#define	I82802_RNG_DSR_VALID	0x01

Index: src/sys/arch/x86/pci/ichlpcib.c
diff -u src/sys/arch/x86/pci/ichlpcib.c:1.24 src/sys/arch/x86/pci/ichlpcib.c:1.25
--- src/sys/arch/x86/pci/ichlpcib.c:1.24	Wed Feb 24 22:37:55 2010
+++ src/sys/arch/x86/pci/ichlpcib.c	Fri Jul 23 00:43:21 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ichlpcib.c,v 1.24 2010/02/24 22:37:55 dyoung Exp $	*/
+/*	$NetBSD: ichlpcib.c,v 1.25 2010/07/23 00:43:21 jakllsch Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.24 2010/02/24 22:37:55 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.25 2010/07/23 00:43:21 jakllsch Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -65,6 +65,7 @@
 #include "hpet.h"
 #include "pcibvar.h"
 #include "gpio.h"
+#include "fwhrng.h"
 
 #define LPCIB_GPIO_NPINS 64
 
@@ -102,6 +103,10 @@
 	gpio_pin_t		sc_gpio_pins[LPCIB_GPIO_NPINS];
 #endif
 
+#if NFWHRNG > 0
+	device_t		sc_fwhbus;
+#endif
+
 	/* Speedstep */
 	pcireg_t		sc_pmcon_orig;
 
@@ -156,6 +161,11 @@
 static void lpcib_gpio_pin_ctl(void *, int, int);
 #endif
 
+#if NFWHRNG > 0
+static void lpcib_fwh_configure(device_t);
+static int lpcib_fwh_unconfigure(device_t, int);
+#endif
+
 struct lpcib_softc *speedstep_cookie;	/* XXX */
 
 CFATTACH_DECL2_NEW(ichlpcib, sizeof(struct lpcib_softc),
@@ -291,6 +301,10 @@
 	lpcib_gpio_configure(self);
 #endif
 
+#if NFWHRNG > 0
+	lpcib_fwh_configure(self);
+#endif
+
 	/* Install power handler */
 	if (!pmf_device_register1(self, lpcib_suspend, lpcib_resume,
 	    lpcib_shutdown))
@@ -303,6 +317,12 @@
 	struct lpcib_softc *sc = device_private(self);
 	uint32_t val;
 
+#if NFWHRNG > 0
+	if (sc->sc_fwhbus == child) {
+		sc->sc_fwhbus = NULL;
+		return;
+	}
+#endif
 #if NGPIO > 0
 	if (sc->sc_gpiobus == child) {
 		sc->sc_gpiobus = NULL;
@@ -354,6 +374,11 @@
 	struct lpcib_softc *sc = device_private(self);
 #endif
 
+#if NFWHRNG > 0
+	if (ifattr_match(ifattr, "fwhichbus") && sc->sc_fwhbus == NULL)
+		lpcib_fwh_configure(self);
+#endif
+
 #if NHPET > 0
 	if (ifattr_match(ifattr, "hpetichbus") && sc->sc_hpetbus == NULL)
 		lpcib_hpet_configure(self);
@@ -375,6 +400,11 @@
 
 	pmf_device_deregister(self);
 
+#if NFWHRNG > 0
+	if ((rc = lpcib_fwh_unconfigure(self, flags)) != 0)
+		return rc;
+#endif
+
 #if NHPET > 0
 	if ((rc = lpcib_hpet_unconfigure(self, flags)) != 0)
 		return rc;
@@ -1206,3 +1236,45 @@
 	mutex_exit(&sc->sc_gpio_mtx);
 }
 #endif
+
+#if NFWHRNG > 0
+static void
+lpcib_fwh_configure(device_t self)
+{
+	struct lpcib_softc *sc = device_private(self);
+
+	pcireg_t pr;
+
+	if (sc->sc_has_rcba) {
+		/*
+		 * Very unlikely to find a 82802 on a ICH6 or newer.
+		 * Also the write enable register moved at that point.
+		 */
+		return;
+	} else {
+		/* Enable FWH write to identify FWH. */
+		pr = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+		    0x4c);
+		pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+		    0x4c, pr|__BIT(16));
+	}
+
+	sc->sc_fwhbus = config_found_ia(self, "fwhichbus", NULL, NULL);
+
+	/* disable write */
+	pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag, 0x4c, pr);
+}
+
+static int
+lpcib_fwh_unconfigure(device_t self, int flags)
+{
+	struct lpcib_softc *sc = device_private(self);
+	int rc;
+
+	if (sc->sc_fwhbus != NULL &&
+	    (rc = config_detach(sc->sc_fwhbus, flags)) != 0)
+		return rc;
+
+	return 0;
+}
+#endif

Index: src/sys/arch/x86/pci/pchb.c
diff -u src/sys/arch/x86/pci/pchb.c:1.22 src/sys/arch/x86/pci/pchb.c:1.23
--- src/sys/arch/x86/pci/pchb.c:1.22	Wed Jun 16 03:35:01 2010
+++ src/sys/arch/x86/pci/pchb.c	Fri Jul 23 00:43:21 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pchb.c,v 1.22 2010/06/16 03:35:01 riz Exp $ */
+/*	$NetBSD: pchb.c,v 1.23 2010/07/23 00:43:21 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pchb.c,v 1.22 2010/06/16 03:35:01 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pchb.c,v 1.23 2010/07/23 00:43:21 jakllsch Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -409,13 +409,6 @@
 		break;
 	}
 
-#if NRND > 0
-	/*
-	 * Attach a random number generator, if there is one.
-	 */
-	pchb_attach_rnd(sc, pa);
-#endif
-
 	if (!pmf_device_register(self, pchb_suspend, pchb_resume))
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
@@ -450,21 +443,12 @@
 pchbdetach(device_t self, int flags)
 {
 	int rc;
-#if NRND > 0
-	struct pchb_softc *sc = device_private(self);
-#endif
 
 	if ((rc = config_detach_children(self, flags)) != 0)
 		return rc;
 
 	pmf_device_deregister(self);
 
-#if NRND > 0
-	/*
-	 * Attach a random number generator, if there is one.
-	 */
-	pchb_detach_rnd(sc);
-#endif
 	return 0;
 }
 

Index: src/sys/arch/x86/pci/pchbvar.h
diff -u src/sys/arch/x86/pci/pchbvar.h:1.5 src/sys/arch/x86/pci/pchbvar.h:1.6
--- src/sys/arch/x86/pci/pchbvar.h:1.5	Mon Apr 28 20:23:40 2008
+++ src/sys/arch/x86/pci/pchbvar.h	Fri Jul 23 00:43:21 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: pchbvar.h,v 1.5 2008/04/28 20:23:40 martin Exp $	*/
+/*	$NetBSD: pchbvar.h,v 1.6 2010/07/23 00:43:21 jakllsch Exp $	*/
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -41,16 +41,6 @@
 	pci_chipset_tag_t sc_pc;
 	pcitag_t sc_tag;
 
-	bus_space_tag_t sc_st;
-	bus_space_handle_t sc_sh;
-
-	struct callout sc_rnd_ch;
-	rndsource_element_t sc_rnd_source;
-
-	int sc_rnd_i;
-	uint32_t sc_rnd_ax;
-	bool sc_rnd_attached;
-
 	pcireg_t sc_pciconfext[48];
 };
 

Added files:

Index: src/sys/arch/x86/pci/fwhrng.c
diff -u /dev/null src/sys/arch/x86/pci/fwhrng.c:1.1
--- /dev/null	Fri Jul 23 00:43:22 2010
+++ src/sys/arch/x86/pci/fwhrng.c	Fri Jul 23 00:43:21 2010
@@ -0,0 +1,253 @@
+/*	$NetBSD: fwhrng.c,v 1.1 2010/07/23 00:43:21 jakllsch Exp $	*/
+
+/*
+ * Copyright (c) 2000 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from OpenBSD: pchb.c,v 1.23 2000/10/23 20:07:30 deraadt Exp
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: fwhrng.c,v 1.1 2010/07/23 00:43:21 jakllsch Exp $");
+
+#include "rnd.h"        
+                            
+#if NRND == 0
+#error fwhrng requires rnd pseudo-device
+#endif  
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/time.h>
+#include <sys/rnd.h>
+
+#include <machine/bus.h>
+
+#include <arch/x86/pci/i82802reg.h>
+
+struct fwhrng_softc {
+	device_t sc_dev;
+
+	bus_space_tag_t sc_st;
+	bus_space_handle_t sc_sh;
+
+	struct callout sc_rnd_ch;
+	rndsource_element_t sc_rnd_source;
+
+	int sc_rnd_i;
+	uint32_t sc_rnd_ax;
+};
+
+static int fwhrng_match(device_t, cfdata_t, void *);
+static void fwhrng_attach(device_t, device_t, void *);
+static int fwhrng_detach(device_t, int);
+
+static void fwhrng_callout(void *v);
+
+#define	FWHRNG_RETRIES		1000
+#define	FWHRNG_MIN_SAMPLES	10
+
+CFATTACH_DECL_NEW(fwhrng, sizeof(struct fwhrng_softc),
+    fwhrng_match, fwhrng_attach, fwhrng_detach, NULL);
+
+static int
+fwhrng_match(device_t parent, cfdata_t match, void *aux)
+{
+	bus_space_tag_t bst;
+	bus_space_handle_t bsh;
+	int ret;
+	uint8_t id0, id1, data0, data1;
+
+	ret = 0;
+
+	bst = x86_bus_space_mem;
+
+	/* read chip ID */
+	if (bus_space_map(bst, I82802AC_MEMBASE, I82802AC_WINSIZE, 0, &bsh))
+		return 0;
+
+	bus_space_write_1(bst, bsh, 0, 0xff); /* reset */
+	data0 = bus_space_read_1(bst, bsh, 0);
+	data1 = bus_space_read_1(bst, bsh, 1);
+	bus_space_write_1(bst, bsh, 0, 0x90); /* enter read id */
+	id0 = bus_space_read_1(bst, bsh, 0);
+	id1 = bus_space_read_1(bst, bsh, 1);
+	bus_space_write_1(bst, bsh, 0, 0xff); /* reset */
+
+	bus_space_unmap(bst, bsh, I82802AC_WINSIZE);
+
+	aprint_debug_dev(parent, "fwh: data %02x,%02x, id %02x,%02x\n",
+	    data0, data1, id0, id1);
+
+	/* unlikely to have these match if we actually read the ID */
+	if ((id0 == data0) && (id1 == data1))
+		return 0;
+
+	/* check for chips with RNG */
+	if (!(id0 == I82802_MFG))
+		return 0;
+	if (!((id1 == I82802AB_ID) || (id1 == I82802AC_ID)))
+		return 0;
+
+	/* check for RNG presence */
+	if (bus_space_map(bst, I82802AC_REGBASE, I82802AC_WINSIZE, 0, &bsh))
+		return 0;
+	data0 = bus_space_read_1(bst, bsh, I82802_RNG_HSR);
+	bus_space_unmap(bst, bsh, I82802AC_WINSIZE);
+	if ((data0 & I82802_RNG_HSR_PRESENT) == I82802_RNG_HSR_PRESENT)
+		return 1;
+
+	return 0;
+}
+
+static void
+fwhrng_attach(device_t parent, device_t self, void *aux)
+{
+	struct fwhrng_softc *sc;
+	int i, j, count_ff;
+	uint8_t reg8;
+
+	sc = device_private(self);
+	sc->sc_dev = self;
+
+	aprint_naive("\n");
+	aprint_normal(": Intel Firmware Hub Random Number Generator\n");
+
+	sc->sc_st = x86_bus_space_mem;
+
+	if (bus_space_map(sc->sc_st, I82802AC_REGBASE, I82802AC_WINSIZE, 0,
+	    &sc->sc_sh) != 0) {
+		aprint_error_dev(self, "unable to map registers\n");
+		return;
+	}
+
+	/* Enable the RNG. */
+	reg8 = bus_space_read_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR);
+	bus_space_write_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR,
+	    reg8 | I82802_RNG_HSR_ENABLE);
+	reg8 = bus_space_read_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR);
+	if ((reg8 & I82802_RNG_HSR_ENABLE) == 0) {
+		aprint_error_dev(self, "unable to enable\n");
+		bus_space_unmap(sc->sc_st, sc->sc_sh, I82802AC_WINSIZE);
+		return;
+	}
+
+	/* Check to see if we can read data from the RNG. */
+	count_ff = 0;
+	for (j = 0; j < FWHRNG_MIN_SAMPLES; ++j) {
+		for (i = 0; i < FWHRNG_RETRIES; i++) {
+			reg8 = bus_space_read_1(sc->sc_st, sc->sc_sh,
+			    I82802_RNG_DSR);
+			if (!(reg8 & I82802_RNG_DSR_VALID)) {
+				delay(10);
+				continue;
+			}
+			reg8 = bus_space_read_1(sc->sc_st, sc->sc_sh,
+			    I82802_RNG_DR);
+			break;
+		}
+		if (i == FWHRNG_RETRIES) {
+			bus_space_unmap(sc->sc_st, sc->sc_sh, I82802AC_WINSIZE);
+			aprint_verbose_dev(sc->sc_dev,
+			    "timeout reading test samples, RNG disabled.\n");
+			return;
+		}
+		if (reg8 == 0xff)
+			++count_ff;
+	}
+
+	if (count_ff == FWHRNG_MIN_SAMPLES) {
+		/* Disable the RNG. */
+		reg8 = bus_space_read_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR);
+		bus_space_write_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR,
+		    reg8 & ~I82802_RNG_HSR_ENABLE);
+		bus_space_unmap(sc->sc_st, sc->sc_sh, I82802AC_WINSIZE);
+		aprint_error_dev(sc->sc_dev,
+		    "returns constant 0xff stream, RNG disabled.\n");
+		return;
+	}
+
+	/*
+	 * Should test entropy source to ensure
+	 * that it passes the Statistical Random
+	 * Number Generator Tests in section 4.11.1,
+	 * FIPS PUB 140-1.
+	 *
+	 *	http://csrc.nist.gov/fips/fips1401.htm
+	 */
+
+	aprint_debug_dev(sc->sc_dev, "random number generator enabled\n");
+
+	callout_init(&sc->sc_rnd_ch, 0);
+	/* FWH is polled for entropy, so no estimate is available. */
+	rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
+	    RND_TYPE_RNG, RND_FLAG_NO_ESTIMATE);
+	sc->sc_rnd_i = sizeof(sc->sc_rnd_ax);
+	fwhrng_callout(sc);
+
+	return;
+}
+
+static int
+fwhrng_detach(device_t self, int flags)
+{
+	struct fwhrng_softc *sc;
+	uint8_t reg8;
+
+	sc = device_private(self);
+
+	rnd_detach_source(&sc->sc_rnd_source);
+
+	callout_stop(&sc->sc_rnd_ch);
+	callout_destroy(&sc->sc_rnd_ch);
+
+	/* Disable the RNG. */
+	reg8 = bus_space_read_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR);
+	bus_space_write_1(sc->sc_st, sc->sc_sh, I82802_RNG_HSR,
+	    reg8 & ~I82802_RNG_HSR_ENABLE);
+
+	bus_space_unmap(sc->sc_st, sc->sc_sh, I82802AC_WINSIZE);
+
+	return 0;
+}
+
+static void
+fwhrng_callout(void *v)
+{
+	struct fwhrng_softc *sc = v;
+
+	if ((bus_space_read_1(sc->sc_st, sc->sc_sh, I82802_RNG_DSR) &
+	     I82802_RNG_DSR_VALID) != 0) {
+		sc->sc_rnd_ax = (sc->sc_rnd_ax << NBBY) |
+		    bus_space_read_1(sc->sc_st, sc->sc_sh, I82802_RNG_DR);
+		if (--sc->sc_rnd_i == 0) {
+			sc->sc_rnd_i = sizeof(sc->sc_rnd_ax);
+			rnd_add_data(&sc->sc_rnd_source, &sc->sc_rnd_ax,
+			    sizeof(sc->sc_rnd_ax),
+			    sizeof(sc->sc_rnd_ax) * NBBY);
+		}
+	}
+	callout_reset(&sc->sc_rnd_ch, 1, fwhrng_callout, sc);
+}

Reply via email to