From owner-svn-src-stable@FreeBSD.ORG Fri Dec 5 17:44:27 2008 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 372EE1065670; Fri, 5 Dec 2008 17:44:27 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 223768FC14; Fri, 5 Dec 2008 17:44:27 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id mB5HiRqU069057; Fri, 5 Dec 2008 17:44:27 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id mB5HiQrT069049; Fri, 5 Dec 2008 17:44:26 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <200812051744.mB5HiQrT069049@svn.freebsd.org> From: John Baldwin Date: Fri, 5 Dec 2008 17:44:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-6@freebsd.org X-SVN-Group: stable-6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: 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 X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 05 Dec 2008 17:44:27 -0000 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 + * Copyright (c) 2006 Damien Bergamini + * Copyright (c) 2005, 2006 Jonathan Gray + * + * 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 +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_KERNEL_OPTION_HEADERS +#include "opt_device_polling.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +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, ®) == 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 ***