Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Dec 2008 17:44:26 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-6@freebsd.org
Subject:   svn commit: r185644 - in stable/6: share/man/man4 sys/amd64/conf sys/conf sys/dev/nfe sys/i386/conf sys/modules sys/modules/nfe
Message-ID:  <200812051744.mB5HiQrT069049@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Dec  5 17:44:26 2008
New Revision: 185644
URL: http://svn.freebsd.org/changeset/base/185644

Log:
  MFC: Add the nfe(4) driver as an alternative to nve(4).  To avoid
  astonishment, nve(4) takes precedence over nfe(4) in this branch.
  I have also not added it to GENERIC.
  
  Reviewed by:	yongari (briefly)

Added:
  stable/6/share/man/man4/nfe.4
     - copied, changed from r159967, head/share/man/man4/nfe.4
  stable/6/sys/dev/nfe/
  stable/6/sys/dev/nfe/if_nfe.c   (contents, props changed)
  stable/6/sys/dev/nfe/if_nfereg.h   (contents, props changed)
  stable/6/sys/dev/nfe/if_nfevar.h   (contents, props changed)
  stable/6/sys/modules/nfe/
  stable/6/sys/modules/nfe/Makefile   (contents, props changed)
Modified:
  stable/6/share/man/man4/   (props changed)
  stable/6/share/man/man4/Makefile
  stable/6/share/man/man4/polling.4
  stable/6/share/man/man4/xl.4   (props changed)
  stable/6/sys/amd64/conf/NOTES
  stable/6/sys/conf/files.amd64
  stable/6/sys/conf/files.i386
  stable/6/sys/i386/conf/NOTES
  stable/6/sys/modules/Makefile

Modified: stable/6/share/man/man4/Makefile
==============================================================================
--- stable/6/share/man/man4/Makefile	Fri Dec  5 17:13:40 2008	(r185643)
+++ stable/6/share/man/man4/Makefile	Fri Dec  5 17:44:26 2008	(r185644)
@@ -180,6 +180,7 @@ MAN=	aac.4 \
 	ncv.4 \
 	netgraph.4 \
 	netintro.4 \
+	${_nfe.4} \
 	${_nfsmb.4} \
 	ng_async.4 \
 	ng_atm.4 \
@@ -469,6 +470,7 @@ MLINKS+=mxge.4 if_mxge.4
 MLINKS+=my.4 if_my.4
 MLINKS+=netintro.4 net.4 \
 	netintro.4 networking.4
+MLINKS+=${_nfe.4} ${_if_nfe.4}
 MLINKS+=nge.4 if_nge.4
 MLINKS+=${_nve.4} ${_if_nve.4}
 MLINKS+=oldcard.4 card.4
@@ -522,9 +524,11 @@ MLINKS+=watchdog.4 SW_WATCHDOG.4
 .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386"
 _amdsmb.4=	amdsmb.4
 _coretemp.4=	coretemp.4
+_if_nfe.4=	if_nfe.4
 _if_nve.4=	if_nve.4
 _ipmi.4=	ipmi.4
 _nfsmb.4=	nfsmb.4
+_nfe.4=		nfe.4
 _nve.4=		nve.4
 _rr232x.4=	rr232x.4
 _spkr.4=	spkr.4

Copied and modified: stable/6/share/man/man4/nfe.4 (from r159967, head/share/man/man4/nfe.4)
==============================================================================
--- head/share/man/man4/nfe.4	Mon Jun 26 23:41:07 2006	(r159967, copy source)
+++ stable/6/share/man/man4/nfe.4	Fri Dec  5 17:44:26 2008	(r185644)
@@ -16,7 +16,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 6, 2006
+.Dd October 2, 2008
 .Dt NFE 4
 .Os
 .Sh NAME
@@ -28,7 +28,7 @@ place the following lines in your
 kernel configuration file:
 .Bd -ragged -offset indent
 .Cd "device miibus"
-.Cd "device nve"
+.Cd "device nfe"
 .Ed
 .Pp
 Alternatively, to load the driver as a
@@ -42,31 +42,139 @@ The
 .Nm
 driver supports PCI Ethernet adapters based on the NVIDIA
 nForce Media and Communications Processors (MCP), such as
-the nForce, nForce 2, nForce 3, CK804, MCP04, MCP51 and MCP55
-Ethernet controller chips.
+the nForce, nForce 2, nForce 3, CK804, MCP04, MCP51, MCP55,
+MCP61, MCP65, MCP67, MCP73, MCP77 and MCP79 Ethernet
+controller chips.
+.Pp
+Supported features include (hardware support provided):
+.Pp
+.Bl -bullet -compact
+.It
+Receive/Transmit IP/TCP/UDP checksum offload
+.It
+Hardware VLAN tag insertion/stripping
+.It
+TCP segmentation offload (TSO)
+.It
+MSI/MSI-X
+.It
+Jumbo Frames
+.El
+.Pp
+Support for Jumbo Frames is provided via the interface MTU setting.
+Selecting an MTU larger than 1500 bytes with the
+.Xr ifconfig 8
+utility configures the adapter to receive and transmit Jumbo Frames.
 .Pp
 The
 .Nm
-driver supports the following
-.Ar media
-types:
-.Pp
-.Bl -tag -width autoselect -compact
+driver supports the following media types:
+.Bl -tag -width "10baseT/UTP"
 .It Cm autoselect
 Enable autoselection of the media type and options.
-.It Cm 10baseT
+.It Cm 10baseT/UTP
 Set 10Mbps operation.
 .It Cm 100baseTX
 Set 100Mbps (Fast Ethernet) operation.
 .It Cm 1000baseT
 Set 1000Mbps (Gigabit Ethernet) operation (recent models only).
 .El
+.Pp
+The
+.Nm
+driver supports the following media options:
+.Bl -tag -width ".Cm 10baseT/UTP"
+.It Cm half-duplex
+Force half duplex operation.
+.It Cm full-duplex
+Force full duplex operation.
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh HARDWARE
+The
+.Nm
+driver supports the following NVIDIA MCP onboard adapters:
+.Pp
+.Bl -bullet -compact
+.It
+NVIDIA nForce MCP Networking Adapter
+.It
+NVIDIA nForce MCP04 Networking Adapter
+.It
+NVIDIA nForce 430 MCP12 Networking Adapter
+.It
+NVIDIA nForce 430 MCP13 Networking Adapter
+.It
+NVIDIA nForce MCP51 Networking Adapter
+.It
+NVIDIA nForce MCP55 Networking Adapter
+.It
+NVIDIA nForce MCP61 Networking Adapter
+.It
+NVIDIA nForce MCP65 Networking Adapter
+.It
+NVIDIA nForce MCP67 Networking Adapter
+.It
+NVIDIA nForce MCP73 Networking Adapter
+.It
+NVIDIA nForce MCP77 Networking Adapter
+.It
+NVIDIA nForce MCP79 Networking Adapter
+.It
+NVIDIA nForce2 MCP2 Networking Adapter
+.It
+NVIDIA nForce2 400 MCP4 Networking Adapter
+.It
+NVIDIA nForce2 400 MCP5 Networking Adapter
+.It
+NVIDIA nForce3 MCP3 Networking Adapter
+.It
+NVIDIA nForce3 250 MCP6 Networking Adapter
+.It
+NVIDIA nForce3 MCP7 Networking Adapter
+.It
+NVIDIA nForce4 CK804 MCP8 Networking Adapter
+.It
+NVIDIA nForce4 CK804 MCP9 Networking Adapter
+.El
+.Sh LOADER TUNABLES
+Tunables can be set at the
+.Xr loader 8
+prompt before booting the kernel or stored in
+.Xr loader.conf 5 .
+.Bl -tag -width indent
+.It Va hw.nfe.msi_disable
+Whether or not MSI support is enabled in the driver.
+The default value is 0.
+.It Va hw.nfe.msix_disable
+Whether or not MSI-X support is enabled in the driver.
+The default value is 0.
+.El
+.Sh SYSCTL VARIABLES
+The following
+.Xr sysctl 8
+variables can be used to modify or monitor
+.Nm
+behavior.
+.Bl -tag -width indent
+.It Va dev.nfe.%d.process_limit
+Maximum number of Rx events to be processed in the event loop
+before rescheduling a taskqueue.
+The accepted range is 50 to 255, the default value is 192.
+The interface does not need to be brought down and up again
+before a change takes effect.
+.El
 .Sh SEE ALSO
+.Xr altq 4 ,
 .Xr arp 4 ,
 .Xr intro 4 ,
 .Xr miibus 4 ,
 .Xr netintro 4 ,
 .Xr pci 4 ,
+.Xr polling 4 ,
+.Xr sysctl 8 ,
 .Xr ifconfig 8
 .Sh HISTORY
 The
@@ -74,7 +182,7 @@ The
 device driver first appeared in
 .Ox 3.9 ,
 and then in
-.Fx 6.0 .
+.Fx 7.0 .
 .Sh AUTHORS
 .An -nosplit
 The
@@ -92,5 +200,3 @@ driver was ported to
 by
 .An Shigeaki Tagashira
 .Aq shigeaki@se.hiroshima-u.ac.jp .
-.Sh CAVEATS
-NVIDIA refuse to release any documentation on their products.

Modified: stable/6/share/man/man4/polling.4
==============================================================================
--- stable/6/share/man/man4/polling.4	Fri Dec  5 17:13:40 2008	(r185643)
+++ stable/6/share/man/man4/polling.4	Fri Dec  5 17:44:26 2008	(r185644)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 2, 2006
+.Dd April 6, 2007
 .Dt POLLING 4
 .Os
 .Sh NAME
@@ -184,6 +184,7 @@ As of this writing, the
 .Xr fwip 4 ,
 .Xr fxp 4 ,
 .Xr ixgb 4 ,
+.Xr nfe 4 ,
 .Xr nge 4 ,
 .Xr re 4 ,
 .Xr rl 4 ,

Modified: stable/6/sys/amd64/conf/NOTES
==============================================================================
--- stable/6/sys/amd64/conf/NOTES	Fri Dec  5 17:13:40 2008	(r185643)
+++ stable/6/sys/amd64/conf/NOTES	Fri Dec  5 17:44:26 2008	(r185644)
@@ -234,6 +234,7 @@ options 	DRM_DEBUG	# Include debug print
 # lnc:  Lance/PCnet cards (Isolan, Novell NE2100, NE32-VL, AMD Am7990 and
 #       Am79C960)
 # mxge: Myricom Myri-10G 10GbE NIC
+# nfe:	nVidia nForce MCP on-board Ethernet Networking (BSD open source)
 # nve:	nVidia nForce MCP on-board Ethernet Networking
 
 #XXX#	still calls MD i386 kvtop function instead of vtophys etc
@@ -243,6 +244,7 @@ options 	DRM_DEBUG	# Include debug print
 #XXX#options 		ED_SIC
 #XXX#device		lnc
 device		mxge		# Myricom Myri-10G 10GbE NIC
+device		nfe		# nVidia nForce MCP on-board Ethernet Networking
 device		nve		# nVidia nForce MCP on-board Ethernet Networking
 
 device		ath

Modified: stable/6/sys/conf/files.amd64
==============================================================================
--- stable/6/sys/conf/files.amd64	Fri Dec  5 17:13:40 2008	(r185643)
+++ stable/6/sys/conf/files.amd64	Fri Dec  5 17:44:26 2008	(r185644)
@@ -200,6 +200,7 @@ dev/mxge/mxge_ethp_z8e.c	optional	mxge p
 dev/mxge/mxge_rss_eth_z8e.c	optional	mxge pci
 dev/mxge/mxge_rss_ethp_z8e.c	optional	mxge pci
 net/zlib.c			optional	mxge
+dev/nfe/if_nfe.c		optional	nfe pci
 dev/nve/if_nve.c		optional	nve pci
 dev/nvram/nvram.c		optional	nvram isa
 dev/rr232x/os_bsd.c		optional	rr232x

Modified: stable/6/sys/conf/files.i386
==============================================================================
--- stable/6/sys/conf/files.i386	Fri Dec  5 17:13:40 2008	(r185643)
+++ stable/6/sys/conf/files.i386	Fri Dec  5 17:44:26 2008	(r185644)
@@ -234,6 +234,7 @@ dev/mxge/mxge_ethp_z8e.c	optional mxge p
 dev/mxge/mxge_rss_eth_z8e.c	optional mxge pci
 dev/mxge/mxge_rss_ethp_z8e.c	optional mxge pci
 net/zlib.c			optional mxge
+dev/nfe/if_nfe.c		optional nfe pci
 dev/nve/if_nve.c		optional nve pci
 dev/nvram/nvram.c		optional nvram isa
 dev/ppc/ppc.c			optional ppc

Added: stable/6/sys/dev/nfe/if_nfe.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/6/sys/dev/nfe/if_nfe.c	Fri Dec  5 17:44:26 2008	(r185644)
@@ -0,0 +1,2993 @@
+/*	$OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $	*/
+
+/*-
+ * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp>
+ * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_device_polling.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <net/bpf.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/nfe/if_nfereg.h>
+#include <dev/nfe/if_nfevar.h>
+
+MODULE_DEPEND(nfe, pci, 1, 1, 1);
+MODULE_DEPEND(nfe, ether, 1, 1, 1);
+MODULE_DEPEND(nfe, miibus, 1, 1, 1);
+
+/* "device miibus" required.  See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+static int  nfe_probe(device_t);
+static int  nfe_attach(device_t);
+static int  nfe_detach(device_t);
+static int  nfe_suspend(device_t);
+static int  nfe_resume(device_t);
+static int nfe_shutdown(device_t);
+static void nfe_power(struct nfe_softc *);
+static int  nfe_miibus_readreg(device_t, int, int);
+static int  nfe_miibus_writereg(device_t, int, int, int);
+static void nfe_miibus_statchg(device_t);
+static void nfe_link_task(void *, int);
+static void nfe_set_intr(struct nfe_softc *);
+static __inline void nfe_enable_intr(struct nfe_softc *);
+static __inline void nfe_disable_intr(struct nfe_softc *);
+static int  nfe_ioctl(struct ifnet *, u_long, caddr_t);
+static void nfe_alloc_msix(struct nfe_softc *, int);
+static void nfe_intr(void *);
+static void nfe_int_task(void *, int);
+static __inline void nfe_discard_rxbuf(struct nfe_softc *, int);
+static __inline void nfe_discard_jrxbuf(struct nfe_softc *, int);
+static int nfe_newbuf(struct nfe_softc *, int);
+static int nfe_jnewbuf(struct nfe_softc *, int);
+static int  nfe_rxeof(struct nfe_softc *, int);
+static int  nfe_jrxeof(struct nfe_softc *, int);
+static void nfe_txeof(struct nfe_softc *);
+static int  nfe_encap(struct nfe_softc *, struct mbuf **);
+static void nfe_setmulti(struct nfe_softc *);
+static void nfe_tx_task(void *, int);
+static void nfe_start(struct ifnet *);
+static void nfe_watchdog(struct ifnet *);
+static void nfe_init(void *);
+static void nfe_init_locked(void *);
+static void nfe_stop(struct ifnet *);
+static int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
+static void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
+static int  nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
+static int  nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
+static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
+static void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
+static int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
+static void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
+static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
+static int  nfe_ifmedia_upd(struct ifnet *);
+static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static void nfe_tick(void *);
+static void nfe_get_macaddr(struct nfe_softc *, uint8_t *);
+static void nfe_set_macaddr(struct nfe_softc *, uint8_t *);
+static void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int);
+
+static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
+static int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS);
+
+#ifdef NFE_DEBUG
+static int nfedebug = 0;
+#define	DPRINTF(sc, ...)	do {				\
+	if (nfedebug)						\
+		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
+} while (0)
+#define	DPRINTFN(sc, n, ...)	do {				\
+	if (nfedebug >= (n))					\
+		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
+} while (0)
+#else
+#define	DPRINTF(sc, ...)
+#define	DPRINTFN(sc, n, ...)
+#endif
+
+#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
+#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
+#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
+
+/* Tunables. */
+static int msi_disable = 0;
+static int msix_disable = 0;
+static int jumbo_disable = 0;
+TUNABLE_INT("hw.nfe.msi_disable", &msi_disable);
+TUNABLE_INT("hw.nfe.msix_disable", &msix_disable);
+TUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable);
+
+static device_method_t nfe_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		nfe_probe),
+	DEVMETHOD(device_attach,	nfe_attach),
+	DEVMETHOD(device_detach,	nfe_detach),
+	DEVMETHOD(device_suspend,	nfe_suspend),
+	DEVMETHOD(device_resume,	nfe_resume),
+	DEVMETHOD(device_shutdown,	nfe_shutdown),
+
+	/* bus interface */
+	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
+	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
+	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
+
+	{ NULL, NULL }
+};
+
+static driver_t nfe_driver = {
+	"nfe",
+	nfe_methods,
+	sizeof(struct nfe_softc)
+};
+
+static devclass_t nfe_devclass;
+
+DRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
+DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
+
+static struct nfe_type nfe_devs[] = {
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
+	    "NVIDIA nForce MCP Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
+	    "NVIDIA nForce2 MCP2 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
+	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
+	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
+	    "NVIDIA nForce3 MCP3 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
+	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
+	    "NVIDIA nForce3 MCP7 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
+	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
+	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
+	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP10 */
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
+	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP11 */
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
+	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
+	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
+	    "NVIDIA nForce MCP55 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
+	    "NVIDIA nForce MCP55 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
+	    "NVIDIA nForce MCP61 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
+	    "NVIDIA nForce MCP61 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
+	    "NVIDIA nForce MCP61 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4,
+	    "NVIDIA nForce MCP61 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
+	    "NVIDIA nForce MCP65 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
+	    "NVIDIA nForce MCP65 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
+	    "NVIDIA nForce MCP65 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4,
+	    "NVIDIA nForce MCP65 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1,
+	    "NVIDIA nForce MCP67 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2,
+	    "NVIDIA nForce MCP67 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3,
+	    "NVIDIA nForce MCP67 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4,
+	    "NVIDIA nForce MCP67 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1,
+	    "NVIDIA nForce MCP73 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2,
+	    "NVIDIA nForce MCP73 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3,
+	    "NVIDIA nForce MCP73 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4,
+	    "NVIDIA nForce MCP73 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1,
+	    "NVIDIA nForce MCP77 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2,
+	    "NVIDIA nForce MCP77 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3,
+	    "NVIDIA nForce MCP77 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4,
+	    "NVIDIA nForce MCP77 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1,
+	    "NVIDIA nForce MCP79 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2,
+	    "NVIDIA nForce MCP79 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3,
+	    "NVIDIA nForce MCP79 Networking Adapter"},
+	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4,
+	    "NVIDIA nForce MCP79 Networking Adapter"},
+	{0, 0, NULL}
+};
+
+
+/* Probe for supported hardware ID's */
+static int
+nfe_probe(device_t dev)
+{
+	struct nfe_type *t;
+
+	t = nfe_devs;
+	/* Check for matching PCI DEVICE ID's */
+	while (t->name != NULL) {
+		if ((pci_get_vendor(dev) == t->vid_id) &&
+		    (pci_get_device(dev) == t->dev_id)) {
+			device_set_desc(dev, t->name);
+			return (BUS_PROBE_LOW_PRIORITY);
+		}
+		t++;
+	}
+
+	return (ENXIO);
+}
+
+static void
+nfe_alloc_msix(struct nfe_softc *sc, int count)
+{
+	int rid;
+
+	rid = PCIR_BAR(2);
+	sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY,
+	    &rid, RF_ACTIVE);
+	if (sc->nfe_msix_res == NULL) {
+		device_printf(sc->nfe_dev,
+		    "couldn't allocate MSIX table resource\n");
+		return;
+	}
+	rid = PCIR_BAR(3);
+	sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev,
+	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (sc->nfe_msix_pba_res == NULL) {
+		device_printf(sc->nfe_dev,
+		    "couldn't allocate MSIX PBA resource\n");
+		bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2),
+		    sc->nfe_msix_res);
+		sc->nfe_msix_res = NULL;
+		return;
+	}
+
+	if (pci_alloc_msix(sc->nfe_dev, &count) == 0) {
+		if (count == NFE_MSI_MESSAGES) {
+			if (bootverbose)
+				device_printf(sc->nfe_dev,
+				    "Using %d MSIX messages\n", count);
+			sc->nfe_msix = 1;
+		} else {
+			if (bootverbose)
+				device_printf(sc->nfe_dev,
+				    "couldn't allocate MSIX\n");
+			pci_release_msi(sc->nfe_dev);
+			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
+			    PCIR_BAR(3), sc->nfe_msix_pba_res);
+			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
+			    PCIR_BAR(2), sc->nfe_msix_res);
+			sc->nfe_msix_pba_res = NULL;
+			sc->nfe_msix_res = NULL;
+		}
+	}
+}
+
+static int
+nfe_attach(device_t dev)
+{
+	struct nfe_softc *sc;
+	struct ifnet *ifp;
+	bus_addr_t dma_addr_max;
+	int error = 0, i, msic, reg, rid;
+
+	sc = device_get_softc(dev);
+	sc->nfe_dev = dev;
+
+	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+	    MTX_DEF);
+	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
+	TASK_INIT(&sc->nfe_link_task, 0, nfe_link_task, sc);
+
+	pci_enable_busmaster(dev);
+
+	rid = PCIR_BAR(0);
+	sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (sc->nfe_res[0] == NULL) {
+		device_printf(dev, "couldn't map memory resources\n");
+		mtx_destroy(&sc->nfe_mtx);
+		return (ENXIO);
+	}
+
+	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
+		uint16_t v, width;
+
+		v = pci_read_config(dev, reg + 0x08, 2);
+		/* Change max. read request size to 4096. */
+		v &= ~(7 << 12);
+		v |= (5 << 12);
+		pci_write_config(dev, reg + 0x08, v, 2);
+
+		v = pci_read_config(dev, reg + 0x0c, 2);
+		/* link capability */
+		v = (v >> 4) & 0x0f;
+		width = pci_read_config(dev, reg + 0x12, 2);
+		/* negotiated link width */
+		width = (width >> 4) & 0x3f;
+		if (v != width)
+			device_printf(sc->nfe_dev,
+			    "warning, negotiated width of link(x%d) != "
+			    "max. width of link(x%d)\n", width, v);
+	}
+
+	/* Allocate interrupt */
+	if (msix_disable == 0 || msi_disable == 0) {
+		if (msix_disable == 0 &&
+		    (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES)
+			nfe_alloc_msix(sc, msic);
+		if (msi_disable == 0 && sc->nfe_msix == 0 &&
+		    (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES &&
+		    pci_alloc_msi(dev, &msic) == 0) {
+			if (msic == NFE_MSI_MESSAGES) {
+				if (bootverbose)
+					device_printf(dev,
+					    "Using %d MSI messages\n", msic);
+				sc->nfe_msi = 1;
+			} else
+				pci_release_msi(dev);
+		}
+	}
+
+	if (sc->nfe_msix == 0 && sc->nfe_msi == 0) {
+		rid = 0;
+		sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+		    RF_SHAREABLE | RF_ACTIVE);
+		if (sc->nfe_irq[0] == NULL) {
+			device_printf(dev, "couldn't allocate IRQ resources\n");
+			error = ENXIO;
+			goto fail;
+		}
+	} else {
+		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
+			sc->nfe_irq[i] = bus_alloc_resource_any(dev,
+			    SYS_RES_IRQ, &rid, RF_ACTIVE);
+			if (sc->nfe_irq[i] == NULL) {
+				device_printf(dev,
+				    "couldn't allocate IRQ resources for "
+				    "message %d\n", rid);
+				error = ENXIO;
+				goto fail;
+			}
+		}
+		/* Map interrupts to vector 0. */
+		if (sc->nfe_msix != 0) {
+			NFE_WRITE(sc, NFE_MSIX_MAP0, 0);
+			NFE_WRITE(sc, NFE_MSIX_MAP1, 0);
+		} else if (sc->nfe_msi != 0) {
+			NFE_WRITE(sc, NFE_MSI_MAP0, 0);
+			NFE_WRITE(sc, NFE_MSI_MAP1, 0);
+		}
+	}
+
+	/* Set IRQ status/mask register. */
+	sc->nfe_irq_status = NFE_IRQ_STATUS;
+	sc->nfe_irq_mask = NFE_IRQ_MASK;
+	sc->nfe_intrs = NFE_IRQ_WANTED;
+	sc->nfe_nointrs = 0;
+	if (sc->nfe_msix != 0) {
+		sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS;
+		sc->nfe_nointrs = NFE_IRQ_WANTED;
+	} else if (sc->nfe_msi != 0) {
+		sc->nfe_irq_mask = NFE_MSI_IRQ_MASK;
+		sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED;
+	}
+
+	sc->nfe_devid = pci_get_device(dev);
+	sc->nfe_revid = pci_get_revid(dev);
+	sc->nfe_flags = 0;
+
+	switch (sc->nfe_devid) {
+	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
+	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
+	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
+	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
+		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
+		break;
+	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
+		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT;
+		break;
+	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
+	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
+		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM;
+		break;
+	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
+		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
+		    NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL;
+		break;
+
+	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
+	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
+	case PCI_PRODUCT_NVIDIA_MCP67_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP67_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP67_LAN3:
+	case PCI_PRODUCT_NVIDIA_MCP67_LAN4:
+	case PCI_PRODUCT_NVIDIA_MCP73_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP73_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP73_LAN3:
+	case PCI_PRODUCT_NVIDIA_MCP73_LAN4:
+		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT |
+		    NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL;
+		break;
+	case PCI_PRODUCT_NVIDIA_MCP77_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP77_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP77_LAN3:
+	case PCI_PRODUCT_NVIDIA_MCP77_LAN4:
+		/* XXX flow control */
+		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT |
+		    NFE_CORRECT_MACADDR;
+		break;
+	case PCI_PRODUCT_NVIDIA_MCP79_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP79_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP79_LAN3:
+	case PCI_PRODUCT_NVIDIA_MCP79_LAN4:
+		/* XXX flow control */
+		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
+		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR;
+		break;
+	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
+	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
+	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
+	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
+		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR |
+		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL;
+		break;
+	}
+
+	nfe_power(sc);
+	/* Check for reversed ethernet address */
+	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
+		sc->nfe_flags |= NFE_CORRECT_MACADDR;
+	nfe_get_macaddr(sc, sc->eaddr);
+	/*
+	 * Allocate the parent bus DMA tag appropriate for PCI.
+	 */
+	dma_addr_max = BUS_SPACE_MAXADDR_32BIT;
+	if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0)
+		dma_addr_max = NFE_DMA_MAXADDR;
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->nfe_dev),	/* parent */
+	    1, 0,				/* alignment, boundary */
+	    dma_addr_max,			/* lowaddr */
+	    BUS_SPACE_MAXADDR,			/* highaddr */
+	    NULL, NULL,				/* filter, filterarg */
+	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
+	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
+	    0,					/* flags */
+	    NULL, NULL,				/* lockfunc, lockarg */
+	    &sc->nfe_parent_tag);
+	if (error)
+		goto fail;
+
+	ifp = sc->nfe_ifp = if_alloc(IFT_ETHER);
+	if (ifp == NULL) {
+		device_printf(dev, "can not if_alloc()\n");
+		error = ENOSPC;
+		goto fail;
+	}
+	TASK_INIT(&sc->nfe_tx_task, 1, nfe_tx_task, ifp);
+
+	/*
+	 * Allocate Tx and Rx rings.
+	 */
+	if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0)
+		goto fail;
+
+	if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0)
+		goto fail;
+
+	nfe_alloc_jrx_ring(sc, &sc->jrxq);
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
+	    &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I",
+	    "max number of Rx events to process");
+
+	sc->nfe_process_limit = NFE_PROC_DEFAULT;
+	error = resource_int_value(device_get_name(dev), device_get_unit(dev),
+	    "process_limit", &sc->nfe_process_limit);
+	if (error == 0) {
+		if (sc->nfe_process_limit < NFE_PROC_MIN ||
+		    sc->nfe_process_limit > NFE_PROC_MAX) {
+			device_printf(dev, "process_limit value out of range; "
+			    "using default: %d\n", NFE_PROC_DEFAULT);
+			sc->nfe_process_limit = NFE_PROC_DEFAULT;
+		}
+	}
+
+	ifp->if_softc = sc;
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+	ifp->if_mtu = ETHERMTU;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_ioctl = nfe_ioctl;
+	ifp->if_start = nfe_start;
+	ifp->if_hwassist = 0;
+	ifp->if_capabilities = 0;
+	ifp->if_watchdog = NULL;
+	ifp->if_init = nfe_init;
+	IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1);
+	ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1;
+	IFQ_SET_READY(&ifp->if_snd);
+
+	if (sc->nfe_flags & NFE_HW_CSUM) {
+		ifp->if_capabilities |= IFCAP_HWCSUM;
+		ifp->if_hwassist |= NFE_CSUM_FEATURES;
+	}
+	ifp->if_capenable = ifp->if_capabilities;
+
+	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
+	/* VLAN capability setup. */
+	ifp->if_capabilities |= IFCAP_VLAN_MTU;
+	if ((sc->nfe_flags & NFE_HW_VLAN) != 0) {
+		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+	}
+	ifp->if_capenable = ifp->if_capabilities;
+
+	/*
+	 * Tell the upper layer(s) we support long frames.
+	 * Must appear after the call to ether_ifattach() because
+	 * ether_ifattach() sets ifi_hdrlen to the default value.
+	 */
+	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+
+#ifdef DEVICE_POLLING
+	ifp->if_capabilities |= IFCAP_POLLING;
+#endif
+
+	/* Do MII setup */
+	if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd,
+	    nfe_ifmedia_sts)) {
+		device_printf(dev, "MII without any phy!\n");
+		error = ENXIO;
+		goto fail;
+	}
+	ether_ifattach(ifp, sc->eaddr);
+
+	TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc);
+	sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK,
+	    taskqueue_thread_enqueue, &sc->nfe_tq);
+	taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq",
+	    device_get_nameunit(sc->nfe_dev));
+	error = 0;
+	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
+		error = bus_setup_intr(dev, sc->nfe_irq[0],
+		    INTR_TYPE_NET | INTR_FAST, nfe_intr, sc,
+		    &sc->nfe_intrhand[0]);
+	} else {
+		for (i = 0; i < NFE_MSI_MESSAGES; i++) {
+			error = bus_setup_intr(dev, sc->nfe_irq[i],
+			    INTR_TYPE_NET | INTR_FAST, nfe_intr, sc,
+			    &sc->nfe_intrhand[i]);
+			if (error != 0)
+				break;
+		}
+	}
+	if (error) {
+		device_printf(dev, "couldn't set up irq\n");
+		taskqueue_free(sc->nfe_tq);
+		sc->nfe_tq = NULL;
+		ether_ifdetach(ifp);
+		goto fail;
+	}
+
+fail:
+	if (error)
+		nfe_detach(dev);
+
+	return (error);
+}
+
+
+static int
+nfe_detach(device_t dev)
+{
+	struct nfe_softc *sc;
+	struct ifnet *ifp;
+	uint8_t eaddr[ETHER_ADDR_LEN];
+	int i, rid;
+
+	sc = device_get_softc(dev);
+	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
+	ifp = sc->nfe_ifp;
+
+#ifdef DEVICE_POLLING
+	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
+		ether_poll_deregister(ifp);
+#endif
+	if (device_is_attached(dev)) {
+		NFE_LOCK(sc);
+		nfe_stop(ifp);
+		ifp->if_flags &= ~IFF_UP;
+		NFE_UNLOCK(sc);
+		callout_drain(&sc->nfe_stat_ch);
+		taskqueue_drain(taskqueue_fast, &sc->nfe_tx_task);
+		taskqueue_drain(taskqueue_swi, &sc->nfe_link_task);
+		ether_ifdetach(ifp);
+	}
+
+	if (ifp) {
+		/* restore ethernet address */
+		if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
+			for (i = 0; i < ETHER_ADDR_LEN; i++) {
+				eaddr[i] = sc->eaddr[5 - i];
+			}
+		} else
+			bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN);
+		nfe_set_macaddr(sc, eaddr);
+		if_free(ifp);
+	}
+	if (sc->nfe_miibus)
+		device_delete_child(dev, sc->nfe_miibus);
+	bus_generic_detach(dev);
+	if (sc->nfe_tq != NULL) {
+		taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task);
+		taskqueue_free(sc->nfe_tq);
+		sc->nfe_tq = NULL;
+	}
+
+	for (i = 0; i < NFE_MSI_MESSAGES; i++) {
+		if (sc->nfe_intrhand[i] != NULL) {
+			bus_teardown_intr(dev, sc->nfe_irq[i],
+			    sc->nfe_intrhand[i]);
+			sc->nfe_intrhand[i] = NULL;
+		}
+	}
+
+	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
+		if (sc->nfe_irq[0] != NULL)
+			bus_release_resource(dev, SYS_RES_IRQ, 0,
+			    sc->nfe_irq[0]);
+	} else {
+		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
+			if (sc->nfe_irq[i] != NULL) {
+				bus_release_resource(dev, SYS_RES_IRQ, rid,
+				    sc->nfe_irq[i]);
+				sc->nfe_irq[i] = NULL;
+			}
+		}
+		pci_release_msi(dev);
+	}
+	if (sc->nfe_msix_pba_res != NULL) {
+		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3),
+		    sc->nfe_msix_pba_res);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812051744.mB5HiQrT069049>