Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 May 2009 02:12:10 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r192506 - head/sys/dev/nge
Message-ID:  <200905210212.n4L2CAQq051187@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Thu May 21 02:12:10 2009
New Revision: 192506
URL: http://svn.freebsd.org/changeset/base/192506

Log:
  bus_dma(9) conversion and make nge(4) work on all architectures.
  o Header file cleanup.
  o bus_dma(9) conversion.
    - Removed all consumers of vtophys(9) and converted to use
      bus_dma(9).
    - 64bit DMA support was disabled because DP83821 is not capable
      of handling the DMA request. 64bit DMA request on DP83820
      requires different descriptor structures and it's hard to
      dynamically change descriptor format at run time so I disabled
      it. Note, this is the same behavior as previous one but
      previously nge(4) didn't explicitly disable 64bit mode on
      DP83820.
    - Added Tx/Rx descriptor ring alignment requirements(8 bytes
      alignment).
    - Limit maximum number of Tx DMA segments to 16. In fact,
      controller does not seem to have limitations on number of Tx
      DMA segments but 16 should be enough for most cases and
      m_collapse(9) will handle highly fragmented frames without
      consuming a lot of CPU cycles.
    - Added Rx buffer alignment requirements(8 bytes alignment). This
      means driver should fixup received frames to align on 16bits
      boundary on strict-alignment architectures.
    - Nuked driver private data structure in descriptor ring.
    - Added endianness support code in Tx/Rx descriptor access.
  o Prefer faster memory mapped register access to I/O mapped access.
     Added fall-back mechanism to use alternative register access.
     The hardware supports both memory and I/O mapped access.
  o Added suspend/resume methods but it wasn't tested as controller I
    have does not support PCI PME.
  o Removed swap argument in nge_read_eeprom() since endianness
    should be handled after reading EEPROM.
  o Implemented experimental 802.3x full-duplex flow-control. ATM
    it was commented out but will be activated after we have generic
    flow-control framework in mii(4) layer.
  o Rearranged promiscuous mode settings and simplified logic.
  o Always disable Rx filter prior to changing Rx filter functions as
    indicated in DP83820/DP83821 datasheet.
  o Added an explicit DELAY in timeout loop of nge_reset().
  o Added a sysctl variable dev.nge.%d.int_holdoff to control
    interrupt moderation. Valid ranges are 1 to 255(default 1) in
    units of 100us. The actual delivery of interrupt would be delayed
    based on the sysctl value. The interface has to be brought down
    and up again before a change takes effect. With proper tuning
    value, users do not need to resort to polling(4) anymore.
  o Added ALTQ(4) support.
  o Added missing IFCAP_VLAN_HWCSUM as nge(4) can offload Tx/Rx
    checksum calculation on VLAN tagged frames as well as VLAN tag
    insertion/stripping. Also add IFCAP_VLAN_MTU capability as nge(4)
    can handle VLAN tagged oversized frames.
  o Fixed media header length for VLAN.
  o Rearranged nge_detach routine such that it's now used for general
    clean-up routine.
  o Enabled MWI.
  o Accessing EEPROM takes very long time so read 6 bytes ethernet
    address with one call instead of 3 separate accesses.
  o Don't set if_mtu in device attach, it's already set in
    ether_ifattach().
  o Don't do any special things for TBI interface. Remove TBI
    specific media handling in the driver and have gentbi(4) handle
    it. Add glue code to read/write TBI PHY registers in miibus
    method. This change removes a lot of PHY handling code in driver
    and now its functionality is handled by mii(4).
  o Alignment fixup code is now applied only for strict-alignment
    architectures. Previously the code was applied for all
    architectures except i386. With this change amd64 will get
    instant Rx performance boost.
  o When driver fails to allocate a new mbuf, update if_qdrops so
    users can see what was wrong in Rx path.
  o Added a workaround for a hardware bug which resulted in short
    VLAN tagged frames(e.g. ARP) was rejected as if runt frame was
    received. With this workaround nge(4) now accepts the short VLAN
    tagged frame and nge(4) can take full advantage of hardware VLAN
    tag stripping. I have no idea how this bug wasn't known so far,
    without the workaround nge(4) may never work on VLAN
    environments.
  o Fixed Rx checksum offload logic such that it now honors active
    interface capability configured with ifconfig(8).
  o In nge_start()/nge_txencap(), always leave at least one free
    descriptor as indicated in datasheet. Without this the hardware
    would be confused with ring descriptor structure(e.g. no clue
    for the end of descriptor ring).
  o Removed dead-code that checks interrupts on PHY hardware. The
    code was designed to detect link state changes but it was
    disabled as driving nge_tick clock would break auto-negotiation
    timer. This code is no longer needed as nge(4) now uses mii(4)
    and link state change handling is done with mii callback.
  o Rearranged ethernet address programming logic such that it works
     on strict-alignment architectures.
  o Added IFCAP_VLAN_HWTAGGING/IFCAP_VLAN_HWCSUM handler in
     nge_ioctl() such that the functionality is configurable with
     ifconfig(8). DP83820/DP83821 can do checksum offload for VLAN
     tagged frames so enable Tx/Rx checksum offload for VLAN
     interfaces.
  o Simplified IFCAP_POLLING selection logic in nge_ioctl().
  o Fixed module unload panic when bpf listeners are active.
  o Tx/Rx descriptor ring address uses 64bit DMA address for
     readability. High address part of DMA would be 0 as nge(4)
     disabled 64bit DMA transfers so it's ok for DP83821.
  o Removed volatile keyword in softc as bus_dmamap_sync(9) should
     take care of this.
  o Removed extra driver private structures in descriptor ring. These
     extra elements are not part of descriptor structure. Embedding
     private driver structure into descriptor ring is not good idea
     as its size may be different on 32bit/64bit architectures.
  o Added miibus_linkchg method handler to catch link state changes.
  o Removed unneeded nge_ifmedia in softc. All TBI access is handled
    in gentbi(4). There is no difference between TBI and non-TBI case
    now.
  o Removed "gigabit link up" message handling in nge_tick. Link
    state change notification is already performed by mii(4) and
    checking link state by accessing PHY registers in periodic timer
    handler of driver is wrong. All link state and speed/duplex
    monitoring should be handled in PHY driver.
  o Use our own timer for watchdog instead of if_watchdog/if_timer
    interface.
  o Added hardware MAC statistics counter, users canget current MAC
    statistics from dev.nge.%d.stats sysctl node(%d is unit number of
    a device).
  o Removed unused macros, NGE_LASTDESC, NGE_MODE, NGE_OWNDESC,
    NGE_RXBYTES.
  o Increased number of Tx/Rx descriptors from 128 to 256. From my
    experience on gigabit ethernet controllers, number of descriptors
    should be 256 or higher to get an optimal performance on gigabit
    link.
  o Increased jumbo frame length to 9022 bytes to cope with other
    gigabit ethernet drivers. Experimentation shows no problems with
    9022 bytes.
  o Removed unused member variables in softc.
  o Switched from bus_space_{read|write}_4 to bus_{read|write}_4.
  o Added support for WOL.

Modified:
  head/sys/dev/nge/if_nge.c
  head/sys/dev/nge/if_ngereg.h

Modified: head/sys/dev/nge/if_nge.c
==============================================================================
--- head/sys/dev/nge/if_nge.c	Thu May 21 02:09:12 2009	(r192505)
+++ head/sys/dev/nge/if_nge.c	Thu May 21 02:12:10 2009	(r192506)
@@ -94,13 +94,20 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/mbuf.h>
 #include <sys/module.h>
-#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
 #include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
 
+#include <net/bpf.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/ethernet.h>
@@ -109,32 +116,23 @@ __FBSDID("$FreeBSD$");
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
 
-#include <net/bpf.h>
-
-#include <vm/vm.h>              /* for vtophys */
-#include <vm/pmap.h>            /* for vtophys */
-#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>
 
-#define NGE_USEIOSPACE
+#include <machine/bus.h>
 
 #include <dev/nge/if_ngereg.h>
 
+/* "device miibus" required.  See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
 MODULE_DEPEND(nge, pci, 1, 1, 1);
 MODULE_DEPEND(nge, ether, 1, 1, 1);
 MODULE_DEPEND(nge, miibus, 1, 1, 1);
 
-/* "device miibus" required.  See GENERIC if you get errors here. */
-#include "miibus_if.h"
-
 #define NGE_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
 
 /*
@@ -149,33 +147,38 @@ static struct nge_type nge_devs[] = {
 static int nge_probe(device_t);
 static int nge_attach(device_t);
 static int nge_detach(device_t);
+static int nge_shutdown(device_t);
+static int nge_suspend(device_t);
+static int nge_resume(device_t);
 
-static int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *);
-static int nge_encap(struct nge_softc *, struct mbuf *, uint32_t *);
-#ifdef NGE_FIXUP_RX
-static __inline void nge_fixup_rx (struct mbuf *);
+static __inline void nge_discard_rxbuf(struct nge_softc *, int);
+static int nge_newbuf(struct nge_softc *, int);
+static int nge_encap(struct nge_softc *, struct mbuf **);
+#ifndef __NO_STRICT_ALIGNMENT
+static __inline void nge_fixup_rx(struct mbuf *);
 #endif
 static void nge_rxeof(struct nge_softc *);
 static void nge_txeof(struct nge_softc *);
 static void nge_intr(void *);
 static void nge_tick(void *);
+static void nge_stats_update(struct nge_softc *);
 static void nge_start(struct ifnet *);
 static void nge_start_locked(struct ifnet *);
 static int nge_ioctl(struct ifnet *, u_long, caddr_t);
 static void nge_init(void *);
 static void nge_init_locked(struct nge_softc *);
+static int nge_stop_mac(struct nge_softc *);
 static void nge_stop(struct nge_softc *);
-static void nge_watchdog(struct ifnet *);
-static int nge_shutdown(device_t);
-static int nge_ifmedia_upd(struct ifnet *);
-static void nge_ifmedia_upd_locked(struct ifnet *);
-static void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static void nge_wol(struct nge_softc *);
+static void nge_watchdog(struct nge_softc *);
+static int nge_mediachange(struct ifnet *);
+static void nge_mediastatus(struct ifnet *, struct ifmediareq *);
 
 static void nge_delay(struct nge_softc *);
 static void nge_eeprom_idle(struct nge_softc *);
 static void nge_eeprom_putbyte(struct nge_softc *, int);
 static void nge_eeprom_getword(struct nge_softc *, int, uint16_t *);
-static void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int);
+static void nge_read_eeprom(struct nge_softc *, caddr_t, int, int);
 
 static void nge_mii_sync(struct nge_softc *);
 static void nge_mii_send(struct nge_softc *, uint32_t, int);
@@ -186,18 +189,16 @@ static int nge_miibus_readreg(device_t, 
 static int nge_miibus_writereg(device_t, int, int, int);
 static void nge_miibus_statchg(device_t);
 
-static void nge_setmulti(struct nge_softc *);
+static void nge_rxfilter(struct nge_softc *);
 static void nge_reset(struct nge_softc *);
+static void nge_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int nge_dma_alloc(struct nge_softc *);
+static void nge_dma_free(struct nge_softc *);
 static int nge_list_rx_init(struct nge_softc *);
 static int nge_list_tx_init(struct nge_softc *);
-
-#ifdef NGE_USEIOSPACE
-#define NGE_RES			SYS_RES_IOPORT
-#define NGE_RID			NGE_PCI_LOIO
-#else
-#define NGE_RES			SYS_RES_MEMORY
-#define NGE_RID			NGE_PCI_LOMEM
-#endif
+static void nge_sysctl_node(struct nge_softc *);
+static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
+static int sysctl_hw_nge_int_holdoff(SYSCTL_HANDLER_ARGS);
 
 static device_method_t nge_methods[] = {
 	/* Device interface */
@@ -205,6 +206,8 @@ static device_method_t nge_methods[] = {
 	DEVMETHOD(device_attach,	nge_attach),
 	DEVMETHOD(device_detach,	nge_detach),
 	DEVMETHOD(device_shutdown,	nge_shutdown),
+	DEVMETHOD(device_suspend,	nge_suspend),
+	DEVMETHOD(device_resume,	nge_resume),
 
 	/* bus interface */
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
@@ -215,7 +218,7 @@ static device_method_t nge_methods[] = {
 	DEVMETHOD(miibus_writereg,	nge_miibus_writereg),
 	DEVMETHOD(miibus_statchg,	nge_miibus_statchg),
 
-	{ 0, 0 }
+	{ NULL, NULL }
 };
 
 static driver_t nge_driver = {
@@ -350,7 +353,7 @@ nge_eeprom_getword(struct nge_softc *sc,
  * Read a sequence of words from the EEPROM.
  */
 static void
-nge_read_eeprom(struct nge_softc *sc, caddr_t dest, int off, int cnt, int swap)
+nge_read_eeprom(struct nge_softc *sc, caddr_t dest, int off, int cnt)
 {
 	int i;
 	uint16_t word = 0, *ptr;
@@ -358,10 +361,7 @@ nge_read_eeprom(struct nge_softc *sc, ca
 	for (i = 0; i < cnt; i++) {
 		nge_eeprom_getword(sc, off + i, &word);
 		ptr = (uint16_t *)(dest + (i * 2));
-		if (swap)
-			*ptr = ntohs(word);
-		else
-			*ptr = word;
+		*ptr = word;
 	}
 }
 
@@ -540,8 +540,48 @@ nge_miibus_readreg(device_t dev, int phy
 {
 	struct nge_softc *sc;
 	struct nge_mii_frame frame;
+	int rv;
 
 	sc = device_get_softc(dev);
+	if ((sc->nge_flags & NGE_FLAG_TBI) != 0) {
+		/* Pretend PHY is at address 0. */
+		if (phy != 0)
+			return (0);
+		switch (reg) {
+		case MII_BMCR:
+			reg = NGE_TBI_BMCR;
+			break;
+		case MII_BMSR:
+			/* 83820/83821 has different bit layout for BMSR. */
+			rv = BMSR_ANEG | BMSR_EXTCAP | BMSR_EXTSTAT;
+			reg = CSR_READ_4(sc, NGE_TBI_BMSR);
+			if ((reg & NGE_TBIBMSR_ANEG_DONE) != 0)
+				rv |= BMSR_ACOMP;
+			if ((reg & NGE_TBIBMSR_LINKSTAT) != 0)
+				rv |= BMSR_LINK;
+			return (rv);
+		case MII_ANAR:
+			reg = NGE_TBI_ANAR;
+			break;
+		case MII_ANLPAR:
+			reg = NGE_TBI_ANLPAR;
+			break;
+		case MII_ANER:
+			reg = NGE_TBI_ANER;
+			break;
+		case MII_EXTSR:
+			reg = NGE_TBI_ESR;
+			break;
+		case MII_PHYIDR1:
+		case MII_PHYIDR2:
+			return (0);
+		default:
+			device_printf(sc->nge_dev,
+			    "bad phy register read : %d\n", reg);
+			return (0);
+		}
+		return (CSR_READ_4(sc, reg));
+	}
 
 	bzero((char *)&frame, sizeof(frame));
 
@@ -559,6 +599,39 @@ nge_miibus_writereg(device_t dev, int ph
 	struct nge_mii_frame frame;
 
 	sc = device_get_softc(dev);
+	if ((sc->nge_flags & NGE_FLAG_TBI) != 0) {
+		/* Pretend PHY is at address 0. */
+		if (phy != 0)
+			return (0);
+		switch (reg) {
+		case MII_BMCR:
+			reg = NGE_TBI_BMCR;
+			break;
+		case MII_BMSR:
+			return (0);
+		case MII_ANAR:
+			reg = NGE_TBI_ANAR;
+			break;
+		case MII_ANLPAR:
+			reg = NGE_TBI_ANLPAR;
+			break;
+		case MII_ANER:
+			reg = NGE_TBI_ANER;
+			break;
+		case MII_EXTSR:
+			reg = NGE_TBI_ESR;
+			break;
+		case MII_PHYIDR1:
+		case MII_PHYIDR2:
+			return (0);
+		default:
+			device_printf(sc->nge_dev,
+			    "bad phy register write : %d\n", reg);
+			return (0);
+		}
+		CSR_WRITE_4(sc, reg, data);
+		return (0);
+	}
 
 	bzero((char *)&frame, sizeof(frame));
 
@@ -570,90 +643,213 @@ nge_miibus_writereg(device_t dev, int ph
 	return (0);
 }
 
+/*
+ * media status/link state change handler.
+ */
 static void
 nge_miibus_statchg(device_t dev)
 {
-	int status;
 	struct nge_softc *sc;
 	struct mii_data *mii;
+	struct ifnet *ifp;
+	struct nge_txdesc *txd;
+	uint32_t done, reg, status;
+	int i;
 
 	sc = device_get_softc(dev);
-	if (sc->nge_tbi) {
-		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
-		    == IFM_AUTO) {
-			status = CSR_READ_4(sc, NGE_TBI_ANLPAR);
-			if (status == 0 || status & NGE_TBIANAR_FDX) {
-				NGE_SETBIT(sc, NGE_TX_CFG,
-				    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
-				NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
-			} else {
-				NGE_CLRBIT(sc, NGE_TX_CFG,
-				    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
-				NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
-			}
+	NGE_LOCK_ASSERT(sc);
 
-		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
-			!= IFM_FDX) {
-			NGE_CLRBIT(sc, NGE_TX_CFG,
-			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
-			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
-		} else {
-			NGE_SETBIT(sc, NGE_TX_CFG,
-			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
-			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+	mii = device_get_softc(sc->nge_miibus);
+	ifp = sc->nge_ifp;
+	if (mii == NULL || ifp == NULL ||
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
+
+	sc->nge_flags &= ~NGE_FLAG_LINK;
+	if ((mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE)) ==
+	    (IFM_AVALID | IFM_ACTIVE)) {
+		switch (IFM_SUBTYPE(mii->mii_media_active)) {
+		case IFM_10_T:
+		case IFM_100_TX:
+		case IFM_1000_T:
+		case IFM_1000_SX:
+		case IFM_1000_LX:
+		case IFM_1000_CX:
+			sc->nge_flags |= NGE_FLAG_LINK;
+			break;
+		default:
+			break;
 		}
-	} else {
-		mii = device_get_softc(sc->nge_miibus);
+	}
+
+	/* Stop Tx/Rx MACs. */
+	if (nge_stop_mac(sc) == ETIMEDOUT)
+		device_printf(sc->nge_dev,
+		    "%s: unable to stop Tx/Rx MAC\n", __func__);
+	nge_txeof(sc);
+	nge_rxeof(sc);
+	if (sc->nge_head != NULL) {
+		m_freem(sc->nge_head);
+		sc->nge_head = sc->nge_tail = NULL;
+	}
+
+	/* Release queued frames. */
+	for (i = 0; i < NGE_TX_RING_CNT; i++) {
+		txd = &sc->nge_cdata.nge_txdesc[i];
+		if (txd->tx_m != NULL) {
+			bus_dmamap_sync(sc->nge_cdata.nge_tx_tag,
+			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->nge_cdata.nge_tx_tag,
+			    txd->tx_dmamap);
+			m_freem(txd->tx_m);
+			txd->tx_m = NULL;
+		}
+	}
 
-		if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
-		        NGE_SETBIT(sc, NGE_TX_CFG,
-			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+	/* Program MAC with resolved speed/duplex. */
+	if ((sc->nge_flags & NGE_FLAG_LINK) != 0) {
+		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
+			NGE_SETBIT(sc, NGE_TX_CFG,
+			    (NGE_TXCFG_IGN_HBEAT | NGE_TXCFG_IGN_CARR));
 			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+#ifdef notyet
+			/* Enable flow-control. */
+			if ((IFM_OPTIONS(mii->mii_media_active) &
+			    (IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE)) != 0)
+				NGE_SETBIT(sc, NGE_PAUSECSR,
+				    NGE_PAUSECSR_PAUSE_ENB);
+#endif
 		} else {
 			NGE_CLRBIT(sc, NGE_TX_CFG,
-			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+			    (NGE_TXCFG_IGN_HBEAT | NGE_TXCFG_IGN_CARR));
 			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+			NGE_CLRBIT(sc, NGE_PAUSECSR, NGE_PAUSECSR_PAUSE_ENB);
 		}
-
 		/* If we have a 1000Mbps link, set the mode_1000 bit. */
-		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
-		    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) {
-			NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
-		} else {
-			NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
+		reg = CSR_READ_4(sc, NGE_CFG);
+		switch (IFM_SUBTYPE(mii->mii_media_active)) {
+		case IFM_1000_SX:
+		case IFM_1000_LX:
+		case IFM_1000_CX:
+		case IFM_1000_T:
+			reg |= NGE_CFG_MODE_1000;
+			break;
+		default:
+			reg &= ~NGE_CFG_MODE_1000;
+			break;
+		}
+		CSR_WRITE_4(sc, NGE_CFG, reg);
+
+		/* Reset Tx/Rx MAC. */
+		reg = CSR_READ_4(sc, NGE_CSR);
+		reg |= NGE_CSR_TX_RESET | NGE_CSR_RX_RESET;
+		CSR_WRITE_4(sc, NGE_CSR, reg);
+		/* Check the completion of reset. */
+		done = 0;
+		for (i = 0; i < NGE_TIMEOUT; i++) {
+			DELAY(1);
+			status = CSR_READ_4(sc, NGE_ISR);
+			if ((status & NGE_ISR_RX_RESET_DONE) != 0)
+				done |= NGE_ISR_RX_RESET_DONE;
+			if ((status & NGE_ISR_TX_RESET_DONE) != 0)
+				done |= NGE_ISR_TX_RESET_DONE;
+			if (done ==
+			    (NGE_ISR_TX_RESET_DONE | NGE_ISR_RX_RESET_DONE))
+				break;
+		}
+		if (i == NGE_TIMEOUT)
+			device_printf(sc->nge_dev,
+			    "%s: unable to reset Tx/Rx MAC\n", __func__);
+		/* Reuse Rx buffer and reset consumer pointer. */
+		sc->nge_cdata.nge_rx_cons = 0;
+		/*
+		 * It seems that resetting Rx/Tx MAC results in
+		 * resetting Tx/Rx descriptor pointer registers such
+		 * that reloading Tx/Rx lists address are needed.
+		 */
+		CSR_WRITE_4(sc, NGE_RX_LISTPTR_HI,
+		    NGE_ADDR_HI(sc->nge_rdata.nge_rx_ring_paddr));
+		CSR_WRITE_4(sc, NGE_RX_LISTPTR_LO,
+		    NGE_ADDR_LO(sc->nge_rdata.nge_rx_ring_paddr));
+		CSR_WRITE_4(sc, NGE_TX_LISTPTR_HI,
+		    NGE_ADDR_HI(sc->nge_rdata.nge_tx_ring_paddr));
+		CSR_WRITE_4(sc, NGE_TX_LISTPTR_LO,
+		    NGE_ADDR_LO(sc->nge_rdata.nge_tx_ring_paddr));
+		/* Reinitialize Tx buffers. */
+		nge_list_tx_init(sc);
+
+		/* Restart Rx MAC. */
+		reg = CSR_READ_4(sc, NGE_CSR);
+		reg |= NGE_CSR_RX_ENABLE;
+		CSR_WRITE_4(sc, NGE_CSR, reg);
+		for (i = 0; i < NGE_TIMEOUT; i++) {
+			if ((CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RX_ENABLE) != 0)
+				break;
+			DELAY(1);
 		}
+		if (i == NGE_TIMEOUT)
+			device_printf(sc->nge_dev,
+			    "%s: unable to restart Rx MAC\n", __func__);
 	}
+
+	/* Data LED off for TBI mode */
+	if ((sc->nge_flags & NGE_FLAG_TBI) != 0)
+		CSR_WRITE_4(sc, NGE_GPIO,
+		    CSR_READ_4(sc, NGE_GPIO) & ~NGE_GPIO_GP3_OUT);
 }
 
 static void
-nge_setmulti(struct nge_softc *sc)
+nge_rxfilter(struct nge_softc *sc)
 {
 	struct ifnet *ifp;
 	struct ifmultiaddr *ifma;
-	uint32_t h = 0, i, filtsave;
+	uint32_t h, i, rxfilt;
 	int bit, index;
 
 	NGE_LOCK_ASSERT(sc);
 	ifp = sc->nge_ifp;
 
-	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
-		NGE_CLRBIT(sc, NGE_RXFILT_CTL,
-		    NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH);
-		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI);
-		return;
+	/* Make sure to stop Rx filtering. */
+	rxfilt = CSR_READ_4(sc, NGE_RXFILT_CTL);
+	rxfilt &= ~NGE_RXFILTCTL_ENABLE;
+	CSR_WRITE_4(sc, NGE_RXFILT_CTL, rxfilt);
+	CSR_BARRIER_WRITE_4(sc, NGE_RXFILT_CTL);
+
+	rxfilt &= ~(NGE_RXFILTCTL_ALLMULTI | NGE_RXFILTCTL_ALLPHYS);
+	rxfilt &= ~NGE_RXFILTCTL_BROAD;
+	/*
+	 * We don't want to use the hash table for matching unicast
+	 * addresses.
+	 */
+	rxfilt &= ~(NGE_RXFILTCTL_MCHASH | NGE_RXFILTCTL_UCHASH);
+
+	/*
+	 * For the NatSemi chip, we have to explicitly enable the
+	 * reception of ARP frames, as well as turn on the 'perfect
+	 * match' filter where we store the station address, otherwise
+	 * we won't receive unicasts meant for this host.
+	 */
+	rxfilt |= NGE_RXFILTCTL_ARP | NGE_RXFILTCTL_PERFECT;
+
+	/*
+	 * Set the capture broadcast bit to capture broadcast frames.
+	 */
+	if ((ifp->if_flags & IFF_BROADCAST) != 0)
+		rxfilt |= NGE_RXFILTCTL_BROAD;
+
+	if ((ifp->if_flags & IFF_PROMISC) != 0 ||
+	    (ifp->if_flags & IFF_ALLMULTI) != 0) {
+		rxfilt |= NGE_RXFILTCTL_ALLMULTI;
+		if ((ifp->if_flags & IFF_PROMISC) != 0)
+			rxfilt |= NGE_RXFILTCTL_ALLPHYS;
+		goto done;
 	}
 
 	/*
 	 * We have to explicitly enable the multicast hash table
 	 * on the NatSemi chip if we want to use it, which we do.
-	 * We also have to tell it that we don't want to use the
-	 * hash table for matching unicast addresses.
 	 */
-	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH);
-	NGE_CLRBIT(sc, NGE_RXFILT_CTL,
-	    NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH);
-
-	filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL);
+	rxfilt |= NGE_RXFILTCTL_MCHASH;
 
 	/* first, zot all the existing hash bits */
 	for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) {
@@ -681,12 +877,18 @@ nge_setmulti(struct nge_softc *sc)
 	}
 	IF_ADDR_UNLOCK(ifp);
 
-	CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave);
+done:
+	CSR_WRITE_4(sc, NGE_RXFILT_CTL, rxfilt);
+	/* Turn the receive filter on. */
+	rxfilt |= NGE_RXFILTCTL_ENABLE;
+	CSR_WRITE_4(sc, NGE_RXFILT_CTL, rxfilt);
+	CSR_BARRIER_WRITE_4(sc, NGE_RXFILT_CTL);
 }
 
 static void
 nge_reset(struct nge_softc *sc)
 {
+	uint32_t v;
 	int i;
 
 	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET);
@@ -694,6 +896,7 @@ nge_reset(struct nge_softc *sc)
 	for (i = 0; i < NGE_TIMEOUT; i++) {
 		if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET))
 			break;
+		DELAY(1);
 	}
 
 	if (i == NGE_TIMEOUT)
@@ -708,6 +911,18 @@ nge_reset(struct nge_softc *sc)
 	 */
 	CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS);
 	CSR_WRITE_4(sc, NGE_CLKRUN, 0);
+
+	/* Clear WOL events which may interfere normal Rx filter opertaion. */
+	CSR_WRITE_4(sc, NGE_WOLCSR, 0);
+
+	/*
+	 * Only DP83820 supports 64bits addressing/data transfers and
+	 * 64bit addressing requires different descriptor structures.
+	 * To make it simple, disable 64bit addressing/data transfers.
+	 */
+	v = CSR_READ_4(sc, NGE_CFG);
+	v &= ~(NGE_CFG_64BIT_ADDR_ENB | NGE_CFG_64BIT_DATA_ENB);
+	CSR_WRITE_4(sc, NGE_CFG, v);
 }
 
 /*
@@ -740,11 +955,13 @@ nge_probe(device_t dev)
 static int
 nge_attach(device_t dev)
 {
-	u_char eaddr[ETHER_ADDR_LEN];
+	uint8_t eaddr[ETHER_ADDR_LEN];
+	uint16_t ea[ETHER_ADDR_LEN/2], ea_temp, reg;
 	struct nge_softc *sc;
-	struct ifnet *ifp = NULL;
-	int error = 0, rid;
+	struct ifnet *ifp;
+	int error, i, rid;
 
+	error = 0;
 	sc = device_get_softc(dev);
 	sc->nge_dev = dev;
 
@@ -756,18 +973,35 @@ nge_attach(device_t dev)
 	 */
 	pci_enable_busmaster(dev);
 
-	rid = NGE_RID;
-	sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE);
+#ifdef NGE_USEIOSPACE
+	sc->nge_res_type = SYS_RES_IOPORT;
+	sc->nge_res_id = PCIR_BAR(0);
+#else
+	sc->nge_res_type = SYS_RES_MEMORY;
+	sc->nge_res_id = PCIR_BAR(1);
+#endif
+	sc->nge_res = bus_alloc_resource_any(dev, sc->nge_res_type,
+	    &sc->nge_res_id, RF_ACTIVE);
 
 	if (sc->nge_res == NULL) {
-		device_printf(dev, "couldn't map ports/memory\n");
-		error = ENXIO;
-		goto fail;
+		if (sc->nge_res_type == SYS_RES_MEMORY) {
+			sc->nge_res_type = SYS_RES_IOPORT;
+			sc->nge_res_id = PCIR_BAR(0);
+		} else {
+			sc->nge_res_type = SYS_RES_MEMORY;
+			sc->nge_res_id = PCIR_BAR(1);
+		}
+		sc->nge_res = bus_alloc_resource_any(dev, sc->nge_res_type,
+		    &sc->nge_res_id, RF_ACTIVE);
+		if (sc->nge_res == NULL) {
+			device_printf(dev, "couldn't allocate %s resources\n",
+			    sc->nge_res_type == SYS_RES_MEMORY ? "memory" :
+			    "I/O");
+			NGE_LOCK_DESTROY(sc);
+			return (ENXIO);
+		}
 	}
 
-	sc->nge_btag = rman_get_bustag(sc->nge_res);
-	sc->nge_bhandle = rman_get_bushandle(sc->nge_res);
-
 	/* Allocate interrupt */
 	rid = 0;
 	sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@@ -779,83 +1013,77 @@ nge_attach(device_t dev)
 		goto fail;
 	}
 
+	/* Enable MWI. */
+	reg = pci_read_config(dev, PCIR_COMMAND, 2);
+	reg |= PCIM_CMD_MWRICEN;
+	pci_write_config(dev, PCIR_COMMAND, reg, 2);
+
 	/* Reset the adapter. */
 	nge_reset(sc);
 
 	/*
 	 * Get station address from the EEPROM.
 	 */
-	nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0);
-	nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0);
-	nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0);
+	nge_read_eeprom(sc, (caddr_t)ea, NGE_EE_NODEADDR, 3);
+	for (i = 0; i < ETHER_ADDR_LEN / 2; i++)
+		ea[i] = le16toh(ea[i]);
+	ea_temp = ea[0];
+	ea[0] = ea[2];
+	ea[2] = ea_temp;
+	bcopy(ea, eaddr, sizeof(eaddr));
 
-	sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF,
-	    M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
-
-	if (sc->nge_ldata == NULL) {
-		device_printf(dev, "no memory for list buffers!\n");
+	if (nge_dma_alloc(sc) != 0) {
 		error = ENXIO;
 		goto fail;
 	}
 
+	nge_sysctl_node(sc);
+
 	ifp = sc->nge_ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL) {
-		device_printf(dev, "can not if_alloc()\n");
+		device_printf(dev, "can not allocate ifnet structure\n");
 		error = ENOSPC;
 		goto fail;
 	}
 	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 = nge_ioctl;
 	ifp->if_start = nge_start;
-	ifp->if_watchdog = nge_watchdog;
 	ifp->if_init = nge_init;
-	ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1;
+	ifp->if_snd.ifq_drv_maxlen = NGE_TX_RING_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+	IFQ_SET_READY(&ifp->if_snd);
 	ifp->if_hwassist = NGE_CSUM_FEATURES;
-	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING;
+	ifp->if_capabilities = IFCAP_HWCSUM;
+	/*
+	 * It seems that some hardwares doesn't provide 3.3V auxiliary
+	 * supply(3VAUX) to drive PME such that checking PCI power
+	 * management capability is necessary.
+	 */
+	if (pci_find_extcap(sc->nge_dev, PCIY_PMG, &i) == 0)
+		ifp->if_capabilities |= IFCAP_WOL;
 	ifp->if_capenable = ifp->if_capabilities;
-#ifdef DEVICE_POLLING
-	ifp->if_capabilities |= IFCAP_POLLING;
-#endif
+
+	if ((CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) != 0) {
+		sc->nge_flags |= NGE_FLAG_TBI;
+		device_printf(dev, "Using TBI\n");
+		/* Configure GPIO. */
+		CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
+		    | NGE_GPIO_GP4_OUT
+		    | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB
+		    | NGE_GPIO_GP3_OUTENB
+		    | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN);
+	}
 
 	/*
 	 * Do MII setup.
 	 */
-	/* XXX: leaked on error */
-	if (mii_phy_probe(dev, &sc->nge_miibus,
-			  nge_ifmedia_upd, nge_ifmedia_sts)) {
-		if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) {
-			sc->nge_tbi = 1;
-			device_printf(dev, "Using TBI\n");
-
-			sc->nge_miibus = dev;
-
-			ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd,
-				nge_ifmedia_sts);
-#define	ADD(m, c)	ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL)
-			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0);
-			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0);
-			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0);
-			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0);
-#undef ADD
-			device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n");
-
-			ifmedia_set(&sc->nge_ifmedia,
-				IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0));
-
-			CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
-				| NGE_GPIO_GP4_OUT
-				| NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB
-				| NGE_GPIO_GP3_OUTENB
-				| NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN);
-
-		} else {
-			device_printf(dev, "MII without any PHY!\n");
-			error = ENXIO;
-			goto fail;
-		}
+	error = mii_phy_probe(dev, &sc->nge_miibus, nge_mediachange,
+	    nge_mediastatus);
+	if (error != 0) {
+		device_printf(dev, "no PHY found!\n");
+		goto fail;
 	}
 
 	/*
@@ -863,6 +1091,20 @@ nge_attach(device_t dev)
 	 */
 	ether_ifattach(ifp, eaddr);
 
+	/* VLAN capability setup. */
+	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
+	ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
+	ifp->if_capenable = ifp->if_capabilities;
+#ifdef DEVICE_POLLING
+	ifp->if_capabilities |= IFCAP_POLLING;
+#endif
+	/*
+	 * 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);
+
 	/*
 	 * Hookup IRQ last.
 	 */
@@ -873,19 +1115,9 @@ nge_attach(device_t dev)
 		goto fail;
 	}
 
-	return (0);
-
 fail:
-	if (sc->nge_ldata)
-		contigfree(sc->nge_ldata,
-		  sizeof(struct nge_list_data), M_DEVBUF);
-	if (ifp)
-		if_free(ifp);
-	if (sc->nge_irq)
-		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
-	if (sc->nge_res)
-		bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
-	NGE_LOCK_DESTROY(sc);
+	if (error != 0)
+		nge_detach(dev);
 	return (error);
 }
 
@@ -899,68 +1131,339 @@ nge_detach(device_t dev)
 	ifp = sc->nge_ifp;
 
 #ifdef DEVICE_POLLING
-	if (ifp->if_capenable & IFCAP_POLLING)
+	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
 		ether_poll_deregister(ifp);
 #endif
-	NGE_LOCK(sc);
-	nge_reset(sc);
-	nge_stop(sc);
-	NGE_UNLOCK(sc);
-	callout_drain(&sc->nge_stat_ch);
-	ether_ifdetach(ifp);
 
-	bus_generic_detach(dev);
-	if (!sc->nge_tbi) {
+	if (device_is_attached(dev)) {
+		NGE_LOCK(sc);
+		sc->nge_flags |= NGE_FLAG_DETACH;
+		nge_stop(sc);
+		NGE_UNLOCK(sc);
+		callout_drain(&sc->nge_stat_ch);
+		if (ifp != NULL)
+			ether_ifdetach(ifp);
+	}
+
+	if (sc->nge_miibus != NULL) {
 		device_delete_child(dev, sc->nge_miibus);
+		sc->nge_miibus = NULL;
 	}
-	bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
-	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
-	bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
+	bus_generic_detach(dev);
+	if (sc->nge_intrhand != NULL)
+		bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
+	if (sc->nge_irq != NULL)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
+	if (sc->nge_res != NULL)
+		bus_release_resource(dev, sc->nge_res_type, sc->nge_res_id,
+		    sc->nge_res);
 
-	contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF);
-	if_free(ifp);
+	nge_dma_free(sc);
+	if (ifp != NULL)
+		if_free(ifp);
 
 	NGE_LOCK_DESTROY(sc);
 
 	return (0);
 }
 
+struct nge_dmamap_arg {
+	bus_addr_t	nge_busaddr;
+};
+
+static void
+nge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	struct nge_dmamap_arg *ctx;
+
+	if (error != 0)
+		return;
+	ctx = arg;
+	ctx->nge_busaddr = segs[0].ds_addr;
+}
+
+static int
+nge_dma_alloc(struct nge_softc *sc)
+{
+	struct nge_dmamap_arg ctx;
+	struct nge_txdesc *txd;
+	struct nge_rxdesc *rxd;
+	int error, i;
+
+	/* Create parent DMA tag. */
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->nge_dev),	/* parent */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
+	    0,				/* nsegments */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->nge_cdata.nge_parent_tag);
+	if (error != 0) {
+		device_printf(sc->nge_dev, "failed to create parent DMA tag\n");
+		goto fail;
+	}
+	/* Create tag for Tx ring. */
+	error = bus_dma_tag_create(sc->nge_cdata.nge_parent_tag,/* parent */
+	    NGE_RING_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    NGE_TX_RING_SIZE,		/* maxsize */
+	    1,				/* nsegments */
+	    NGE_TX_RING_SIZE,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->nge_cdata.nge_tx_ring_tag);
+	if (error != 0) {
+		device_printf(sc->nge_dev, "failed to create Tx ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Rx ring. */
+	error = bus_dma_tag_create(sc->nge_cdata.nge_parent_tag,/* parent */
+	    NGE_RING_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    NGE_RX_RING_SIZE,		/* maxsize */
+	    1,				/* nsegments */
+	    NGE_RX_RING_SIZE,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->nge_cdata.nge_rx_ring_tag);
+	if (error != 0) {
+		device_printf(sc->nge_dev,
+		    "failed to create Rx ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Tx buffers. */
+	error = bus_dma_tag_create(sc->nge_cdata.nge_parent_tag,/* parent */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES * NGE_MAXTXSEGS,	/* maxsize */
+	    NGE_MAXTXSEGS,		/* nsegments */
+	    MCLBYTES,			/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->nge_cdata.nge_tx_tag);
+	if (error != 0) {
+		device_printf(sc->nge_dev, "failed to create Tx DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Rx buffers. */
+	error = bus_dma_tag_create(sc->nge_cdata.nge_parent_tag,/* parent */
+	    NGE_RX_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES,			/* maxsize */
+	    1,				/* nsegments */
+	    MCLBYTES,			/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->nge_cdata.nge_rx_tag);
+	if (error != 0) {
+		device_printf(sc->nge_dev, "failed to create Rx DMA tag\n");
+		goto fail;
+	}
+
+	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
+	error = bus_dmamem_alloc(sc->nge_cdata.nge_tx_ring_tag,
+	    (void **)&sc->nge_rdata.nge_tx_ring, BUS_DMA_WAITOK |
+	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->nge_cdata.nge_tx_ring_map);
+	if (error != 0) {
+		device_printf(sc->nge_dev,
+		    "failed to allocate DMA'able memory for Tx ring\n");
+		goto fail;
+	}
+
+	ctx.nge_busaddr = 0;
+	error = bus_dmamap_load(sc->nge_cdata.nge_tx_ring_tag,
+	    sc->nge_cdata.nge_tx_ring_map, sc->nge_rdata.nge_tx_ring,
+	    NGE_TX_RING_SIZE, nge_dmamap_cb, &ctx, 0);
+	if (error != 0 || ctx.nge_busaddr == 0) {
+		device_printf(sc->nge_dev,
+		    "failed to load DMA'able memory for Tx ring\n");
+		goto fail;
+	}
+	sc->nge_rdata.nge_tx_ring_paddr = ctx.nge_busaddr;
+
+	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
+	error = bus_dmamem_alloc(sc->nge_cdata.nge_rx_ring_tag,
+	    (void **)&sc->nge_rdata.nge_rx_ring, BUS_DMA_WAITOK |
+	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->nge_cdata.nge_rx_ring_map);
+	if (error != 0) {
+		device_printf(sc->nge_dev,
+		    "failed to allocate DMA'able memory for Rx ring\n");
+		goto fail;
+	}

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



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