i386/134517: Realtek 8111C Driver Backport for FreeBSD 6.1

Craig Cocca craigc at fw.master6.uia.net
Wed May 13 18:30:02 UTC 2009


>Number:         134517
>Category:       i386
>Synopsis:       Realtek 8111C Driver Backport for FreeBSD 6.1
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-i386
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Wed May 13 18:30:01 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Craig Cocca
>Release:        FreeBSD 6.1-RELEASE-p24 i386
>Organization:
ULTIMATE INTERNET ACCESS
>Environment:
System: FreeBSD fw.master6.uia.net 6.1-RELEASE-p24 FreeBSD 6.1-RELEASE-p24 #20: Wed Aug 6 14:35:49 PDT 2008 craigc at fw.master6.uia.net:/usr/src/sys/i386/compile/UIAFW_61_01 i386

>Description:
	Submitting Realtek 8111 Driver Backport for FreeBSD 6.1.  Updates
the re driver to work with newer Realtek network devices in FreeBSD 6.1

>How-To-Repeat:
>Fix:
	See unified diffs below.

--- if_rl.c.orig	Wed Apr 15 13:15:36 2009
+++ if_rl.c	Tue May 12 08:42:54 2009
@@ -136,6 +136,75 @@
 
 #include <pci/if_rlreg.h>
 
+struct rl_softc;
+
+struct rl_dmaload_arg {
+	struct rl_softc		*sc;
+	int			rl_idx;
+	int			rl_maxsegs;
+	uint32_t		rl_flags;
+	struct rl_desc		*rl_ring;
+};
+
+struct rl_list_data {
+	struct mbuf		*rl_tx_mbuf[RL_TX_DESC_CNT];
+	struct mbuf		*rl_rx_mbuf[RL_TX_DESC_CNT];
+	int			rl_tx_prodidx;
+	int			rl_rx_prodidx;
+	int			rl_tx_considx;
+	int			rl_tx_free;
+	bus_dmamap_t		rl_tx_dmamap[RL_TX_DESC_CNT];
+	bus_dmamap_t		rl_rx_dmamap[RL_RX_DESC_CNT];
+	bus_dma_tag_t		rl_mtag;	/* mbuf mapping tag */
+	bus_dma_tag_t		rl_stag;	/* stats mapping tag */
+	bus_dmamap_t		rl_smap;	/* stats map */
+	struct rl_stats		*rl_stats;
+	bus_addr_t		rl_stats_addr;
+	bus_dma_tag_t		rl_rx_list_tag;
+	bus_dmamap_t		rl_rx_list_map;
+	struct rl_desc		*rl_rx_list;
+	bus_addr_t		rl_rx_list_addr;
+	bus_dma_tag_t		rl_tx_list_tag;
+	bus_dmamap_t		rl_tx_list_map;
+	struct rl_desc		*rl_tx_list;
+	bus_addr_t		rl_tx_list_addr;
+};
+
+struct rl_softc {
+	struct ifnet		*rl_ifp;	/* interface info */
+	bus_space_handle_t	rl_bhandle;	/* bus space handle */
+	bus_space_tag_t		rl_btag;	/* bus space tag */
+	struct resource		*rl_res;
+	struct resource		*rl_irq;
+	void			*rl_intrhand;
+	device_t		rl_miibus;
+	bus_dma_tag_t		rl_parent_tag;
+	bus_dma_tag_t		rl_tag;
+	uint8_t			rl_type;
+	int			rl_eecmd_read;
+	uint8_t			rl_stats_no_timeout;
+	int			rl_txthresh;
+	struct rl_chain_data	rl_cdata;
+	struct rl_list_data	rl_ldata;
+	struct callout		rl_stat_callout;
+	struct mtx		rl_mtx;
+	struct mbuf		*rl_head;
+	struct mbuf		*rl_tail;
+	uint32_t		rl_hwrev;
+	uint32_t		rl_rxlenmask;
+	int			rl_testmode;
+	int			suspended;	/* 0 = normal  1 = suspended */
+#ifdef DEVICE_POLLING
+	int			rxcycles;
+#endif
+};
+
+#define	RL_LOCK(_sc)		mtx_lock(&(_sc)->rl_mtx)
+#define	RL_UNLOCK(_sc)		mtx_unlock(&(_sc)->rl_mtx)
+#define	RL_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->rl_mtx, MA_OWNED)
+
+#define RL_TIMEOUT		1000
+
 /*
  * Various supported device vendors/types and their names.
  */



--- if_rlreg.h.orig	Thu Apr 16 11:08:10 2009
+++ if_rlreg.h	Tue May 12 08:42:54 2009
@@ -29,7 +29,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/pci/if_rlreg.h,v 1.51.2.3 2005/11/06 16:00:54 jhb Exp $
+ * $FreeBSD: src/sys/pci/if_rlreg.h,v 1.67.2.23 2009/03/18 02:10:01 yongari Exp $
  */
 
 /*
@@ -76,7 +76,11 @@
 #define RL_EECMD	0x0050		/* EEPROM command register */
 #define RL_CFG0		0x0051		/* config register #0 */
 #define RL_CFG1		0x0052		/* config register #1 */
-                                        /* 0053-0057 reserved */   
+#define	RL_CFG2		0x0053		/* config register #2 */
+#define	RL_CFG3		0x0054		/* config register #3 */
+#define	RL_CFG4		0x0055		/* config register #4 */
+#define	RL_CFG5		0x0056		/* config register #5 */
+					/* 0057 reserved */
 #define RL_MEDIASTAT	0x0058		/* media status register (8139) */
 					/* 0059-005A reserved */
 #define RL_MII		0x005A		/* 8129 chip only */
@@ -127,8 +131,10 @@
 #define RL_TBI_ANAR		0x0068
 #define RL_TBI_LPAR		0x006A
 #define RL_GMEDIASTAT		0x006C	/* 8 bits */
+#define RL_MACDBG		0x006D	/* 8 bits, 8168C SPIN2 only */
+#define RL_GPIO			0x006E	/* 8 bits, 8168C SPIN2 only */
 #define RL_MAXRXPKTLEN		0x00DA	/* 16 bits, chip multiplies by 8 */
-#define RL_GTXSTART		0x0038	/* 16 bits */
+#define RL_GTXSTART		0x0038	/* 8 bits */
 
 /*
  * TX config register bits
@@ -145,10 +151,24 @@
 #define RL_LOOPTEST_ON		0x00020000
 #define RL_LOOPTEST_ON_CPLUS	0x00060000
 
+/* Known revision codes. */
+
 #define RL_HWREV_8169		0x00000000
-#define RL_HWREV_8169S		0x04000000
-#define RL_HWREV_8169SB		0x10000000
-#define RL_HWREV_8110S		0x00800000
+#define RL_HWREV_8169S		0x00800000
+#define RL_HWREV_8110S		0x04000000
+#define RL_HWREV_8169_8110SB	0x10000000
+#define RL_HWREV_8169_8110SC	0x18000000
+#define RL_HWREV_8102EL		0x24800000
+#define RL_HWREV_8168D		0x28000000
+#define RL_HWREV_8168_SPIN1	0x30000000
+#define RL_HWREV_8100E		0x30800000
+#define RL_HWREV_8101E		0x34000000
+#define RL_HWREV_8102E		0x34800000
+#define RL_HWREV_8168_SPIN2	0x38000000
+#define RL_HWREV_8168_SPIN3	0x38400000
+#define RL_HWREV_8168C		0x3C000000
+#define RL_HWREV_8168C_SPIN2	0x3C400000
+#define RL_HWREV_8168CP		0x3C800000
 #define RL_HWREV_8139		0x60000000
 #define RL_HWREV_8139A		0x70000000
 #define RL_HWREV_8139AG		0x70800000
@@ -159,6 +179,8 @@
 #define RL_HWREV_8139CPLUS	0x74800000
 #define RL_HWREV_8101		0x74c00000
 #define RL_HWREV_8100		0x78800000
+#define RL_HWREV_8169_8110SBL	0x7CC00000
+#define RL_HWREV_8169_8110SCE	0x98000000
 
 #define RL_TXDMA_16BYTES	0x00000000
 #define RL_TXDMA_32BYTES	0x00000100
@@ -206,10 +228,17 @@
 	RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW|	\
 	RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR)
 
+#ifdef RE_TX_MODERATION
 #define RL_INTRS_CPLUS	\
 	(RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_TX_ERR|			\
 	RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW|	\
 	RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR|RL_ISR_TIMEOUT_EXPIRED)
+#else
+#define RL_INTRS_CPLUS	\
+	(RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_TX_ERR|RL_ISR_TX_OK|		\
+	RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW|	\
+	RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR|RL_ISR_TIMEOUT_EXPIRED)
+#endif
 
 /*
  * Media status register. (8139 only)
@@ -282,6 +311,7 @@
 #define RL_CMD_TX_ENB		0x0004
 #define RL_CMD_RX_ENB		0x0008
 #define RL_CMD_RESET		0x0010
+#define RL_CMD_STOPREQ		0x0080
 
 /*
  * EEPROM control register
@@ -298,6 +328,17 @@
 #define RL_EEMODE_WRITECFG	(0x80|0x40)
 
 /* 9346 EEPROM commands */
+#define RL_9346_ADDR_LEN	6	/* 93C46 1K: 128x16 */
+#define RL_9356_ADDR_LEN	8	/* 93C56 2K: 256x16 */
+
+#define RL_9346_WRITE          0x5
+#define RL_9346_READ           0x6
+#define RL_9346_ERASE          0x7
+#define RL_9346_EWEN           0x4
+#define RL_9346_EWEN_ADDR      0x30
+#define RL_9456_EWDS           0x4
+#define RL_9346_EWDS_ADDR      0x00
+
 #define RL_EECMD_WRITE		0x140
 #define RL_EECMD_READ_6BIT	0x180
 #define RL_EECMD_READ_8BIT	0x600
@@ -333,16 +374,51 @@
  * Config 1 register
  */
 #define RL_CFG1_PWRDWN		0x01
+#define RL_CFG1_PME		0x01	
 #define RL_CFG1_SLEEP		0x02
+#define RL_CFG1_VPDEN		0x02
 #define RL_CFG1_IOMAP		0x04
 #define RL_CFG1_MEMMAP		0x08
 #define RL_CFG1_RSVD		0x10
+#define	RL_CFG1_LWACT		0x10
 #define RL_CFG1_DRVLOAD		0x20
 #define RL_CFG1_LED0		0x40
 #define RL_CFG1_FULLDUPLEX	0x40	/* 8129 only */
 #define RL_CFG1_LED1		0x80
 
 /*
+ * Config 2 register
+ */
+#define	RL_CFG2_PCI33MHZ	0x00
+#define	RL_CFG2_PCI66MHZ	0x01
+#define	RL_CFG2_PCI64BIT	0x08
+#define	RL_CFG2_AUXPWR		0x10
+#define	RL_CFG2_MSI		0x20
+
+/*
+ * Config 3 register
+ */
+#define	RL_CFG3_GRANTSEL	0x80
+#define	RL_CFG3_WOL_MAGIC	0x20
+#define	RL_CFG3_WOL_LINK	0x10
+#define	RL_CFG3_FAST_B2B	0x01
+
+/*
+ * Config 4 register
+ */
+#define	RL_CFG4_LWPTN		0x04
+#define	RL_CFG4_LWPME		0x10
+
+/*
+ * Config 5 register
+ */
+#define	RL_CFG5_WOL_BCAST	0x40
+#define	RL_CFG5_WOL_MCAST	0x20
+#define	RL_CFG5_WOL_UCAST	0x10
+#define	RL_CFG5_WOL_LANWAKE	0x02
+#define	RL_CFG5_PME_STS		0x01
+
+/*
  * 8139C+ register definitions
  */
 
@@ -377,6 +453,15 @@
 #define RL_CPLUSCMD_PCI_DAC	0x0010	/* PCI dual-address cycle only */
 #define RL_CPLUSCMD_RXCSUM_ENB	0x0020	/* enable RX checksum offload */
 #define RL_CPLUSCMD_VLANSTRIP	0x0040	/* enable VLAN tag stripping */
+#define	RL_CPLUSCMD_MACSTAT_DIS	0x0080	/* 8168B/C/CP */
+#define	RL_CPLUSCMD_ASF		0x0100	/* 8168C/CP */
+#define	RL_CPLUSCMD_DBG_SEL	0x0200	/* 8168C/CP */
+#define	RL_CPLUSCMD_FORCE_TXFC	0x0400	/* 8168C/CP */
+#define	RL_CPLUSCMD_FORCE_RXFC	0x0800	/* 8168C/CP */
+#define	RL_CPLUSCMD_FORCE_HDPX	0x1000	/* 8168C/CP */
+#define	RL_CPLUSCMD_NORMAL_MODE	0x2000	/* 8168C/CP */
+#define	RL_CPLUSCMD_DBG_ENB	0x4000	/* 8168C/CP */
+#define	RL_CPLUSCMD_BIST_ENB	0x8000	/* 8168C/CP */
 
 /* C+ early transmit threshold */
 
@@ -421,6 +506,11 @@
 #define RL_RXBUFLEN		(1 << ((RL_RX_BUF_SZ >> 11) + 13))
 #define RL_TX_LIST_CNT		4
 #define RL_MIN_FRAMELEN		60
+#define	RL_TX_8139_BUF_ALIGN	4
+#define	RL_RX_8139_BUF_ALIGN	8
+#define	RL_RX_8139_BUF_RESERVE	sizeof(int64_t)
+#define	RL_RX_8139_BUF_GUARD_SZ	\
+	(ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN + RL_RX_8139_BUF_RESERVE)	
 #define RL_TXTHRESH(x)		((x) << 11)
 #define RL_TX_THRESH_INIT	96
 #define RL_RX_FIFOTHRESH	RL_RXFIFO_NOTHRESH
@@ -432,14 +522,23 @@
 
 #define RL_ETHER_ALIGN	2
 
+/*
+ * re(4) hardware ip4csum-tx could be mangled with 28 bytes or less IP packets.
+ */
+#define	RL_IP4CSUMTX_MINLEN	28
+#define	RL_IP4CSUMTX_PADLEN	(ETHER_HDR_LEN + RL_IP4CSUMTX_MINLEN)
+
 struct rl_chain_data {
 	uint16_t		cur_rx;
 	uint8_t			*rl_rx_buf;
 	uint8_t			*rl_rx_buf_ptr;
-	bus_dmamap_t		rl_rx_dmamap;
 
 	struct mbuf		*rl_tx_chain[RL_TX_LIST_CNT];
 	bus_dmamap_t		rl_tx_dmamap[RL_TX_LIST_CNT];
+	bus_dma_tag_t		rl_tx_tag;
+	bus_dma_tag_t		rl_rx_tag;
+	bus_dmamap_t		rl_rx_dmamap;
+	bus_addr_t		rl_rx_buf_paddr;
 	uint8_t			last_tx;
 	uint8_t			cur_tx;
 };
@@ -518,6 +617,7 @@
 #define RL_TDESC_CMD_UDPCSUM	0x00020000	/* UDP checksum enable */
 #define RL_TDESC_CMD_IPCSUM	0x00040000	/* IP header checksum enable */
 #define RL_TDESC_CMD_MSSVAL	0x07FF0000	/* Large send MSS value */
+#define RL_TDESC_CMD_MSSVAL_SHIFT	16	/* Large send MSS value shift */
 #define RL_TDESC_CMD_LGSEND	0x08000000	/* TCP large send enb */
 #define RL_TDESC_CMD_EOF	0x10000000	/* end of frame marker */
 #define RL_TDESC_CMD_SOF	0x20000000	/* start of frame marker */
@@ -526,6 +626,10 @@
 
 #define RL_TDESC_VLANCTL_TAG	0x00020000	/* Insert VLAN tag */
 #define RL_TDESC_VLANCTL_DATA	0x0000FFFF	/* TAG data */
+/* RTL8168C/RTL8168CP/RTL8111C/RTL8111CP */
+#define	RL_TDESC_CMD_UDPCSUMV2	0x80000000
+#define	RL_TDESC_CMD_TCPCSUMV2	0x40000000	
+#define	RL_TDESC_CMD_IPCSUMV2	0x20000000	
 
 /*
  * Error bits are valid only on the last descriptor of a frame
@@ -563,6 +667,8 @@
 #define RL_RDESC_STAT_RUNT	0x00080000	/* runt packet received */
 #define RL_RDESC_STAT_CRCERR	0x00040000	/* CRC error */
 #define RL_RDESC_STAT_PROTOID	0x00030000	/* Protocol type */
+#define	RL_RDESC_STAT_UDP	0x00020000	/* UDP, 8168C/CP, 8111C/CP */
+#define	RL_RDESC_STAT_TCP	0x00010000	/* TCP, 8168C/CP, 8111C/CP */
 #define RL_RDESC_STAT_IPSUMBAD	0x00008000	/* IP header checksum bad */
 #define RL_RDESC_STAT_UDPSUMBAD	0x00004000	/* UDP checksum bad */
 #define RL_RDESC_STAT_TCPSUMBAD	0x00002000	/* TCP checksum bad */
@@ -574,6 +680,9 @@
 #define RL_RDESC_VLANCTL_TAG	0x00010000	/* VLAN tag available
 						   (rl_vlandata valid)*/
 #define RL_RDESC_VLANCTL_DATA	0x0000FFFF	/* TAG data */
+/* RTL8168C/RTL8168CP/RTL8111C/RTL8111CP */
+#define	RL_RDESC_IPV6		0x80000000
+#define	RL_RDESC_IPV4		0x40000000
 
 #define RL_PROTOID_NONIP	0x00000000
 #define RL_PROTOID_TCPIP	0x00010000
@@ -609,22 +718,35 @@
 /*
  * Rx/Tx descriptor parameters (8139C+ and 8169 only)
  *
- * Tx/Rx count must be equal.  Shared code like re_dma_map_desc assumes this.
- * Buffers must be a multiple of 8 bytes.  Currently limit to 64 descriptors
- * due to the 8139C+.  We need to put the number of descriptors in the ring
- * structure and use that value instead.
+ * 8139C+
+ *  Number of descriptors supported : up to 64
+ *  Descriptor alignment : 256 bytes
+ *  Tx buffer : At least 4 bytes in length.
+ *  Rx buffer : At least 8 bytes in length and 8 bytes alignment required.
+ *  
+ * 8169
+ *  Number of descriptors supported : up to 1024
+ *  Descriptor alignment : 256 bytes
+ *  Tx buffer : At least 4 bytes in length.
+ *  Rx buffer : At least 8 bytes in length and 8 bytes alignment required.
  */
-#if !defined(__i386__) && !defined(__amd64__)
+#ifndef	__NO_STRICT_ALIGNMENT
 #define RE_FIXUP_RX	1
 #endif
 
-#define RL_TX_DESC_CNT		64
-#define RL_RX_DESC_CNT		RL_TX_DESC_CNT
-#define RL_RX_LIST_SZ		(RL_RX_DESC_CNT * sizeof(struct rl_desc))
-#define RL_TX_LIST_SZ		(RL_TX_DESC_CNT * sizeof(struct rl_desc))
+#define RL_8169_TX_DESC_CNT	256
+#define RL_8169_RX_DESC_CNT	256
+#define RL_8139_TX_DESC_CNT	64
+#define RL_8139_RX_DESC_CNT	64
+#define RL_TX_DESC_CNT		RL_8169_TX_DESC_CNT
+#define RL_RX_DESC_CNT		RL_8169_RX_DESC_CNT
+#define	RL_NTXSEGS		32
+
 #define RL_RING_ALIGN		256
 #define RL_IFQ_MAXLEN		512
-#define RL_DESC_INC(x)		(x = (x + 1) % RL_TX_DESC_CNT)
+#define RL_TX_DESC_NXT(sc,x)	((x + 1) & ((sc)->rl_ldata.rl_tx_desc_cnt - 1))
+#define RL_TX_DESC_PRV(sc,x)	((x - 1) & ((sc)->rl_ldata.rl_tx_desc_cnt - 1))
+#define RL_RX_DESC_NXT(sc,x)	((x + 1) & ((sc)->rl_ldata.rl_rx_desc_cnt - 1))
 #define RL_OWN(x)		(le32toh((x)->rl_cmdstat) & RL_RDESC_STAT_OWN)
 #define RL_RXBYTES(x)		(le32toh((x)->rl_cmdstat) & sc->rl_rxlenmask)
 #define RL_PKTSZ(x)		((x)/* >> 3*/)
@@ -636,79 +758,25 @@
 #define RE_RX_DESC_BUFLEN	MCLBYTES
 #endif
 
+#define	RL_MSI_MESSAGES	1
+
 #define RL_ADDR_LO(y)		((uint64_t) (y) & 0xFFFFFFFF)
 #define RL_ADDR_HI(y)		((uint64_t) (y) >> 32)
 
+/*
+ * The number of bits reserved for MSS in RealTek controllers is
+ * 11bits. This limits the maximum interface MTU size in TSO case
+ * as upper stack should not generate TCP segments with MSS greater
+ * than the limit.
+ */
+#define	RL_TSO_MTU		(2047 - ETHER_HDR_LEN - ETHER_CRC_LEN)
+
 /* see comment in dev/re/if_re.c */
 #define RL_JUMBO_FRAMELEN	7440
 #define RL_JUMBO_MTU		(RL_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define	RL_MAX_FRAMELEN		\
+	(ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
 
-struct rl_softc;
-
-struct rl_dmaload_arg {
-	struct rl_softc		*sc;
-	int			rl_idx;
-	int			rl_maxsegs;
-	uint32_t		rl_flags;
-	struct rl_desc		*rl_ring;
-};
-
-struct rl_list_data {
-	struct mbuf		*rl_tx_mbuf[RL_TX_DESC_CNT];
-	struct mbuf		*rl_rx_mbuf[RL_TX_DESC_CNT];
-	int			rl_tx_prodidx;
-	int			rl_rx_prodidx;
-	int			rl_tx_considx;
-	int			rl_tx_free;
-	bus_dmamap_t		rl_tx_dmamap[RL_TX_DESC_CNT];
-	bus_dmamap_t		rl_rx_dmamap[RL_RX_DESC_CNT];
-	bus_dma_tag_t		rl_mtag;	/* mbuf mapping tag */
-	bus_dma_tag_t		rl_stag;	/* stats mapping tag */
-	bus_dmamap_t		rl_smap;	/* stats map */
-	struct rl_stats		*rl_stats;
-	bus_addr_t		rl_stats_addr;
-	bus_dma_tag_t		rl_rx_list_tag;
-	bus_dmamap_t		rl_rx_list_map;
-	struct rl_desc		*rl_rx_list;
-	bus_addr_t		rl_rx_list_addr;
-	bus_dma_tag_t		rl_tx_list_tag;
-	bus_dmamap_t		rl_tx_list_map;
-	struct rl_desc		*rl_tx_list;
-	bus_addr_t		rl_tx_list_addr;
-};
-
-struct rl_softc {
-	struct ifnet		*rl_ifp;	/* interface info */
-	bus_space_handle_t	rl_bhandle;	/* bus space handle */
-	bus_space_tag_t		rl_btag;	/* bus space tag */
-	struct resource		*rl_res;
-	struct resource		*rl_irq;
-	void			*rl_intrhand;
-	device_t		rl_miibus;
-	bus_dma_tag_t		rl_parent_tag;
-	bus_dma_tag_t		rl_tag;
-	uint8_t			rl_type;
-	int			rl_eecmd_read;
-	uint8_t			rl_stats_no_timeout;
-	int			rl_txthresh;
-	struct rl_chain_data	rl_cdata;
-	struct rl_list_data	rl_ldata;
-	struct callout		rl_stat_callout;
-	struct mtx		rl_mtx;
-	struct mbuf		*rl_head;
-	struct mbuf		*rl_tail;
-	uint32_t		rl_hwrev;
-	uint32_t		rl_rxlenmask;
-	int			rl_testmode;
-	int			suspended;	/* 0 = normal  1 = suspended */
-#ifdef DEVICE_POLLING
-	int			rxcycles;
-#endif
-};
-
-#define	RL_LOCK(_sc)		mtx_lock(&(_sc)->rl_mtx)
-#define	RL_UNLOCK(_sc)		mtx_unlock(&(_sc)->rl_mtx)
-#define	RL_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->rl_mtx, MA_OWNED)
 
 /*
  * register space access macros
@@ -729,7 +797,26 @@
 #define CSR_READ_1(sc, reg)		\
 	bus_space_read_1(sc->rl_btag, sc->rl_bhandle, reg)
 
+#define CSR_SETBIT_1(sc, offset, val)		\
+	CSR_WRITE_1(sc, offset, CSR_READ_1(sc, offset) | (val))
+
+#define CSR_CLRBIT_1(sc, offset, val)		\
+	CSR_WRITE_1(sc, offset, CSR_READ_1(sc, offset) & ~(val))
+
+#define CSR_SETBIT_2(sc, offset, val)		\
+	CSR_WRITE_2(sc, offset, CSR_READ_2(sc, offset) | (val))
+
+#define CSR_CLRBIT_2(sc, offset, val)		\
+	CSR_WRITE_2(sc, offset, CSR_READ_2(sc, offset) & ~(val))
+
+#define CSR_SETBIT_4(sc, offset, val)		\
+	CSR_WRITE_4(sc, offset, CSR_READ_4(sc, offset) | (val))
+
+#define CSR_CLRBIT_4(sc, offset, val)		\
+	CSR_WRITE_4(sc, offset, CSR_READ_4(sc, offset) & ~(val))
+
 #define RL_TIMEOUT		1000
+#define RL_PHY_TIMEOUT		2000
 
 /*
  * General constants that are fun to know.
@@ -741,9 +828,13 @@
 /*
  * RealTek chip device IDs.
  */
+#define RT_DEVICEID_8139D			0x8039
 #define	RT_DEVICEID_8129			0x8129
+#define RT_DEVICEID_8101E			0x8136
 #define	RT_DEVICEID_8138			0x8138
 #define	RT_DEVICEID_8139			0x8139
+#define RT_DEVICEID_8169SC			0x8167
+#define RT_DEVICEID_8168			0x8168
 #define RT_DEVICEID_8169			0x8169
 #define RT_DEVICEID_8100			0x8100
 
@@ -855,6 +946,11 @@
 #define PLANEX_VENDORID				0x14ea
 
 /*
+ * Planex FNW-3603-TX device ID
+ */
+#define PLANEX_DEVICEID_FNW3603TX		0xab06
+
+/*
  * Planex FNW-3800-TX device ID
  */
 #define PLANEX_DEVICEID_FNW3800TX		0xab07
@@ -883,6 +979,14 @@
  * Edimax EP-4103DL cardbus device ID
  */
 #define EDIMAX_DEVICEID_EP4103DL		0xAB06
+
+/* US Robotics vendor ID */
+
+#define USR_VENDORID		0x16EC
+
+/* US Robotics 997902 device ID */
+
+#define USR_DEVICEID_997902	0x0116
 
 /*
  * PCI low memory base and low I/O base register, and



--- if_re.c.old	Fri Mar 17 13:30:55 2006
+++ if_re.c	Tue May 12 08:42:54 2009
@@ -31,10 +31,10 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/re/if_re.c,v 1.46.2.14 2006/03/17 21:30:55 glebius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/re/if_re.c,v 1.95.2.48 2009/04/03 00:12:14 yongari Exp $");
 
 /*
- * RealTek 8139C+/8169/8169S/8110S PCI NIC driver
+ * RealTek 8139C+/8169/8169S/8110S/8168/8111/8101E PCI NIC driver
  *
  * Written by Bill Paul <wpaul at windriver.com>
  * Senior Networking Software Engineer
@@ -44,8 +44,8 @@
 /*
  * This driver is designed to support RealTek's next generation of
  * 10/100 and 10/100/1000 PCI ethernet controllers. There are currently
- * four devices in this family: the RTL8139C+, the RTL8169, the RTL8169S
- * and the RTL8110S.
+ * seven devices in this family: the RTL8139C+, the RTL8169, the RTL8169S,
+ * RTL8110S, the RTL8168, the RTL8111 and the RTL8101E.
  *
  * The 8139C+ is a 10/100 ethernet chip. It is backwards compatible
  * with the older 8139 family, however it also supports a special
@@ -121,6 +121,9 @@
 #include <sys/module.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -143,19 +146,111 @@
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
+#include <pci/if_rlreg.h>
+
 MODULE_DEPEND(re, pci, 1, 1, 1);
 MODULE_DEPEND(re, ether, 1, 1, 1);
 MODULE_DEPEND(re, miibus, 1, 1, 1);
 
-/* "controller miibus0" required.  See GENERIC if you get errors here. */
-#include "miibus_if.h"
+struct rl_txdesc {
+	struct mbuf		*tx_m;
+	bus_dmamap_t		tx_dmamap;
+};
 
-/*
- * Default to using PIO access for this driver.
- */
-#define RE_USEIOSPACE
+struct rl_rxdesc {
+	struct mbuf		*rx_m;
+	bus_dmamap_t		rx_dmamap;
+	bus_size_t		rx_size;
+};
 
-#include <pci/if_rlreg.h>
+struct rl_list_data {
+	struct rl_txdesc	rl_tx_desc[RL_TX_DESC_CNT];
+	struct rl_rxdesc	rl_rx_desc[RL_RX_DESC_CNT];
+	int			rl_tx_desc_cnt;
+	int			rl_rx_desc_cnt;
+	int			rl_tx_prodidx;
+	int			rl_rx_prodidx;
+	int			rl_tx_considx;
+	int			rl_tx_free;
+	bus_dma_tag_t		rl_tx_mtag;	/* mbuf TX mapping tag */
+	bus_dma_tag_t		rl_rx_mtag;	/* mbuf RX mapping tag */
+	bus_dmamap_t		rl_rx_sparemap;
+	bus_dma_tag_t		rl_stag;	/* stats mapping tag */
+	bus_dmamap_t		rl_smap;	/* stats map */
+	struct rl_stats		*rl_stats;
+	bus_addr_t		rl_stats_addr;
+	bus_dma_tag_t		rl_rx_list_tag;
+	bus_dmamap_t		rl_rx_list_map;
+	struct rl_desc		*rl_rx_list;
+	bus_addr_t		rl_rx_list_addr;
+	bus_dma_tag_t		rl_tx_list_tag;
+	bus_dmamap_t		rl_tx_list_map;
+	struct rl_desc		*rl_tx_list;
+	bus_addr_t		rl_tx_list_addr;
+};
+
+struct rl_softc {
+	struct ifnet		*rl_ifp;	/* interface info */
+	bus_space_handle_t	rl_bhandle;	/* bus space handle */
+	bus_space_tag_t		rl_btag;	/* bus space tag */
+	device_t		rl_dev;
+	struct resource		*rl_res;
+	int			rl_res_id;
+	int			rl_res_type;
+	struct resource		*rl_irq[RL_MSI_MESSAGES];
+	void			*rl_intrhand[RL_MSI_MESSAGES];
+	device_t		rl_miibus;
+	bus_dma_tag_t		rl_parent_tag;
+	uint8_t			rl_type;
+	int			rl_eecmd_read;
+	int			rl_eewidth;
+	uint8_t			rl_stats_no_timeout;
+	int			rl_txthresh;
+	struct rl_chain_data	rl_cdata;
+	struct rl_list_data	rl_ldata;
+	struct callout		rl_stat_callout;
+	int			rl_watchdog_timer;
+	struct mtx		rl_mtx;
+	struct mbuf		*rl_head;
+	struct mbuf		*rl_tail;
+	uint32_t		rl_hwrev;
+	uint32_t		rl_rxlenmask;
+	int			rl_testmode;
+	int			rl_if_flags;
+	int			suspended;	/* 0 = normal  1 = suspended */
+#ifdef DEVICE_POLLING
+	int			rxcycles;
+#endif
+
+	struct task		rl_txtask;
+	struct task		rl_inttask;
+
+	int			rl_txstart;
+	uint32_t		rl_flags;
+#define	RL_FLAG_MSI		0x0001
+#define	RL_FLAG_PHYWAKE		0x0008
+#define	RL_FLAG_NOJUMBO		0x0010
+#define	RL_FLAG_PAR		0x0020
+#define	RL_FLAG_DESCV2		0x0040
+#define	RL_FLAG_MACSTAT		0x0080
+#define	RL_FLAG_FASTETHER	0x0100
+#define	RL_FLAG_CMDSTOP		0x0200
+#define	RL_FLAG_MACRESET	0x0400
+#define	RL_FLAG_WOLRXENB	0x1000
+#define	RL_FLAG_MACSLEEP	0x2000
+#define	RL_FLAG_PCIE		0x4000
+#define	RL_FLAG_LINK		0x8000
+};
+
+#define	RL_LOCK(_sc)		mtx_lock(&(_sc)->rl_mtx)
+#define	RL_UNLOCK(_sc)		mtx_unlock(&(_sc)->rl_mtx)
+#define	RL_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->rl_mtx, MA_OWNED)
+
+/* "device miibus" required.  See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+static int prefer_iomap = 0;
+TUNABLE_INT("hw.re.prefer_iomap", &prefer_iomap);
 
 #define RE_CSUM_FEATURES    (CSUM_IP | CSUM_TCP | CSUM_UDP)
 
@@ -163,23 +258,25 @@
  * Various supported device vendors/types and their names.
  */
 static struct rl_type re_devs[] = {
-	{ DLINK_VENDORID, DLINK_DEVICEID_528T, RL_HWREV_8169S,
-		"D-Link DGE-528(T) Gigabit Ethernet Adapter" },
-	{ RT_VENDORID, RT_DEVICEID_8139, RL_HWREV_8139CPLUS,
-		"RealTek 8139C+ 10/100BaseTX" },
-	{ RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169,
-		"RealTek 8169 Gigabit Ethernet" },
-	{ RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169S,
-		"RealTek 8169S Single-chip Gigabit Ethernet" },
-	{ RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169SB,
-		"RealTek 8169SB Single-chip Gigabit Ethernet" },
-	{ RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8110S,
-		"RealTek 8110S Single-chip Gigabit Ethernet" },
-	{ COREGA_VENDORID, COREGA_DEVICEID_CGLAPCIGT, RL_HWREV_8169S,
-		"Corega CG-LAPCIGT (RTL8169S) Gigabit Ethernet" },
-	{ LINKSYS_VENDORID, LINKSYS_DEVICEID_EG1032, RL_HWREV_8169S,
-		"Linksys EG1032 (RTL8169S) Gigabit Ethernet" },
-	{ 0, 0, 0, NULL }
+	{ DLINK_VENDORID, DLINK_DEVICEID_528T, 0,
+	    "D-Link DGE-528(T) Gigabit Ethernet Adapter" },
+	{ RT_VENDORID, RT_DEVICEID_8139, 0,
+	    "RealTek 8139C+ 10/100BaseTX" },
+	{ RT_VENDORID, RT_DEVICEID_8101E, 0,
+	    "RealTek 8101E/8102E/8102EL PCIe 10/100baseTX" },
+	{ RT_VENDORID, RT_DEVICEID_8168, 0,
+	    "RealTek 8168/8168B/8168C/8168CP/8168D/8111B/8111C/8111CP PCIe "
+	    "Gigabit Ethernet" },
+	{ RT_VENDORID, RT_DEVICEID_8169, 0,
+	    "RealTek 8169/8169S/8169SB(L)/8110S/8110SB(L) Gigabit Ethernet" },
+	{ RT_VENDORID, RT_DEVICEID_8169SC, 0,
+	    "RealTek 8169SC/8110SC Single-chip Gigabit Ethernet" },
+	{ COREGA_VENDORID, COREGA_DEVICEID_CGLAPCIGT, 0,
+	    "Corega CG-LAPCIGT (RTL8169S) Gigabit Ethernet" },
+	{ LINKSYS_VENDORID, LINKSYS_DEVICEID_EG1032, 0,
+	    "Linksys EG1032 (RTL8169S) Gigabit Ethernet" },
+	{ USR_VENDORID, USR_DEVICEID_997902, 0,
+	    "US Robotics 997902 (RTL8169S) Gigabit Ethernet" }
 };
 
 static struct rl_hwrev re_hwrevs[] = {
@@ -191,12 +288,26 @@
 	{ RL_HWREV_8139C, RL_8139, "C" },
 	{ RL_HWREV_8139D, RL_8139, "8139D/8100B/8100C" },
 	{ RL_HWREV_8139CPLUS, RL_8139CPLUS, "C+"},
+	{ RL_HWREV_8168_SPIN1, RL_8169, "8168"},
 	{ RL_HWREV_8169, RL_8169, "8169"},
 	{ RL_HWREV_8169S, RL_8169, "8169S"},
-	{ RL_HWREV_8169SB, RL_8169, "8169SB"},
 	{ RL_HWREV_8110S, RL_8169, "8110S"},
+	{ RL_HWREV_8169_8110SB, RL_8169, "8169SB/8110SB"},
+	{ RL_HWREV_8169_8110SC, RL_8169, "8169SC/8110SC"},
+	{ RL_HWREV_8169_8110SBL, RL_8169, "8169SBL/8110SBL"},
+	{ RL_HWREV_8169_8110SCE, RL_8169, "8169SC/8110SC"},
 	{ RL_HWREV_8100, RL_8139, "8100"},
 	{ RL_HWREV_8101, RL_8139, "8101"},
+	{ RL_HWREV_8100E, RL_8169, "8100E"},
+	{ RL_HWREV_8101E, RL_8169, "8101E"},
+	{ RL_HWREV_8102E, RL_8169, "8102E"},
+	{ RL_HWREV_8102EL, RL_8169, "8102EL"},
+	{ RL_HWREV_8168_SPIN2, RL_8169, "8168"},
+	{ RL_HWREV_8168_SPIN3, RL_8169, "8168"},
+	{ RL_HWREV_8168C, RL_8169, "8168C/8111C"},
+	{ RL_HWREV_8168C_SPIN2, RL_8169, "8168C/8111C"},
+	{ RL_HWREV_8168CP, RL_8169, "8168CP/8111CP"},
+	{ RL_HWREV_8168D, RL_8169, "8168D"},
 	{ 0, 0, NULL }
 };
 
@@ -204,20 +315,20 @@
 static int re_attach		(device_t);
 static int re_detach		(device_t);
 
-static int re_encap		(struct rl_softc *, struct mbuf **, int *);
+static int re_encap		(struct rl_softc *, struct mbuf **);
 
 static void re_dma_map_addr	(void *, bus_dma_segment_t *, int, int);
-static void re_dma_map_desc	(void *, bus_dma_segment_t *, int,
-				    bus_size_t, int);
 static int re_allocmem		(device_t, struct rl_softc *);
-static int re_newbuf		(struct rl_softc *, int, struct mbuf *);
+static __inline void re_discard_rxbuf
+				(struct rl_softc *, int);
+static int re_newbuf		(struct rl_softc *, int);
 static int re_rx_list_init	(struct rl_softc *);
 static int re_tx_list_init	(struct rl_softc *);
 #ifdef RE_FIXUP_RX
 static __inline void re_fixup_rx
 				(struct mbuf *);
 #endif
-static void re_rxeof		(struct rl_softc *);
+static int re_rxeof		(struct rl_softc *);
 static void re_txeof		(struct rl_softc *);
 #ifdef DEVICE_POLLING
 static void re_poll		(struct ifnet *, enum poll_cmd, int);
@@ -225,22 +336,23 @@
 #endif
 static void re_intr		(void *);
 static void re_tick		(void *);
+static void re_tx_task		(void *, int);
+static void re_int_task		(void *, int);
 static void re_start		(struct ifnet *);
-static void re_start_locked	(struct ifnet *);
 static int re_ioctl		(struct ifnet *, u_long, caddr_t);
 static void re_init		(void *);
 static void re_init_locked	(struct rl_softc *);
 static void re_stop		(struct rl_softc *);
-static void re_watchdog		(struct ifnet *);
+static void re_watchdog		(struct rl_softc *);
 static int re_suspend		(device_t);
 static int re_resume		(device_t);
-static void re_shutdown		(device_t);
+static int re_shutdown		(device_t);
 static int re_ifmedia_upd	(struct ifnet *);
 static void re_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
 
 static void re_eeprom_putbyte	(struct rl_softc *, int);
 static void re_eeprom_getword	(struct rl_softc *, int, u_int16_t *);
-static void re_read_eeprom	(struct rl_softc *, caddr_t, int, int, int);
+static void re_read_eeprom	(struct rl_softc *, caddr_t, int, int);
 static int re_gmii_readreg	(device_t, int, int);
 static int re_gmii_writereg	(device_t, int, int, int);
 
@@ -248,17 +360,11 @@
 static int re_miibus_writereg	(device_t, int, int, int);
 static void re_miibus_statchg	(device_t);
 
-static void re_setmulti		(struct rl_softc *);
+static void re_set_rxmode		(struct rl_softc *);
 static void re_reset		(struct rl_softc *);
 
+#ifdef RE_DIAG
 static int re_diag		(struct rl_softc *);
-
-#ifdef RE_USEIOSPACE
-#define RL_RES			SYS_RES_IOPORT
-#define RL_RID			RL_PCI_LOIO
-#else
-#define RL_RES			SYS_RES_MEMORY
-#define RL_RID			RL_PCI_LOMEM
 #endif
 
 static device_method_t re_methods[] = {
@@ -306,18 +412,17 @@
  * Send a read command and address to the EEPROM, check for ACK.
  */
 static void
-re_eeprom_putbyte(sc, addr)
-	struct rl_softc		*sc;
-	int			addr;
+re_eeprom_putbyte(struct rl_softc *sc, int addr)
 {
-	register int		d, i;
+	int			d, i;
 
-	d = addr | sc->rl_eecmd_read;
+	d = addr | (RL_9346_READ << sc->rl_eewidth);
 
 	/*
 	 * Feed in each bit and strobe the clock.
 	 */
-	for (i = 0x400; i; i >>= 1) {
+
+	for (i = 1 << (sc->rl_eewidth + 3); i; i >>= 1) {
 		if (d & i) {
 			EE_SET(RL_EE_DATAIN);
 		} else {
@@ -335,24 +440,16 @@
  * Read a word of data stored in the EEPROM at address 'addr.'
  */
 static void
-re_eeprom_getword(sc, addr, dest)
-	struct rl_softc		*sc;
-	int			addr;
-	u_int16_t		*dest;
+re_eeprom_getword(struct rl_softc *sc, int addr, u_int16_t *dest)
 {
-	register int		i;
+	int			i;
 	u_int16_t		word = 0;
 
-	/* Enter EEPROM access mode. */
-	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL);
-
 	/*
 	 * Send address of word we want to read.
 	 */
 	re_eeprom_putbyte(sc, addr);
 
-	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL);
-
 	/*
 	 * Start reading bits from EEPROM.
 	 */
@@ -365,9 +462,6 @@
 		DELAY(100);
 	}
 
-	/* Turn off EEPROM access mode. */
-	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
-
 	*dest = word;
 }
 
@@ -375,30 +469,28 @@
  * Read a sequence of words from the EEPROM.
  */
 static void
-re_read_eeprom(sc, dest, off, cnt, swap)
-	struct rl_softc		*sc;
-	caddr_t			dest;
-	int			off;
-	int			cnt;
-	int			swap;
+re_read_eeprom(struct rl_softc *sc, caddr_t dest, int off, int cnt)
 {
 	int			i;
 	u_int16_t		word = 0, *ptr;
 
+	CSR_SETBIT_1(sc, RL_EECMD, RL_EEMODE_PROGRAM);
+
+        DELAY(100);
+
 	for (i = 0; i < cnt; i++) {
+		CSR_SETBIT_1(sc, RL_EECMD, RL_EE_SEL);
 		re_eeprom_getword(sc, off + i, &word);
+		CSR_CLRBIT_1(sc, RL_EECMD, RL_EE_SEL);
 		ptr = (u_int16_t *)(dest + (i * 2));
-		if (swap)
-			*ptr = ntohs(word);
-		else
-			*ptr = word;
+                *ptr = word;
 	}
+
+	CSR_CLRBIT_1(sc, RL_EECMD, RL_EEMODE_PROGRAM);
 }
 
 static int
-re_gmii_readreg(dev, phy, reg)
-	device_t		dev;
-	int			phy, reg;
+re_gmii_readreg(device_t dev, int phy, int reg)
 {
 	struct rl_softc		*sc;
 	u_int32_t		rval;
@@ -419,15 +511,15 @@
 	CSR_WRITE_4(sc, RL_PHYAR, reg << 16);
 	DELAY(1000);
 
-	for (i = 0; i < RL_TIMEOUT; i++) {
+	for (i = 0; i < RL_PHY_TIMEOUT; i++) {
 		rval = CSR_READ_4(sc, RL_PHYAR);
 		if (rval & RL_PHYAR_BUSY)
 			break;
 		DELAY(100);
 	}
 
-	if (i == RL_TIMEOUT) {
-		if_printf(sc->rl_ifp, "PHY read failed\n");
+	if (i == RL_PHY_TIMEOUT) {
+		device_printf(sc->rl_dev, "PHY read failed\n");
 		return (0);
 	}
 
@@ -435,9 +527,7 @@
 }
 
 static int
-re_gmii_writereg(dev, phy, reg, data)
-	device_t		dev;
-	int			phy, reg, data;
+re_gmii_writereg(device_t dev, int phy, int reg, int data)
 {
 	struct rl_softc		*sc;
 	u_int32_t		rval;
@@ -449,15 +539,15 @@
 	    (data & RL_PHYAR_PHYDATA) | RL_PHYAR_BUSY);
 	DELAY(1000);
 
-	for (i = 0; i < RL_TIMEOUT; i++) {
+	for (i = 0; i < RL_PHY_TIMEOUT; i++) {
 		rval = CSR_READ_4(sc, RL_PHYAR);
 		if (!(rval & RL_PHYAR_BUSY))
 			break;
 		DELAY(100);
 	}
 
-	if (i == RL_TIMEOUT) {
-		if_printf(sc->rl_ifp, "PHY write failed\n");
+	if (i == RL_PHY_TIMEOUT) {
+		device_printf(sc->rl_dev, "PHY write failed\n");
 		return (0);
 	}
 
@@ -465,9 +555,7 @@
 }
 
 static int
-re_miibus_readreg(dev, phy, reg)
-	device_t		dev;
-	int			phy, reg;
+re_miibus_readreg(device_t dev, int phy, int reg)
 {
 	struct rl_softc		*sc;
 	u_int16_t		rval = 0;
@@ -513,17 +601,19 @@
 		rval = CSR_READ_1(sc, RL_MEDIASTAT);
 		return (rval);
 	default:
-		if_printf(sc->rl_ifp, "bad phy register\n");
+		device_printf(sc->rl_dev, "bad phy register\n");
 		return (0);
 	}
 	rval = CSR_READ_2(sc, re8139_reg);
+	if (sc->rl_type == RL_8139CPLUS && re8139_reg == RL_BMCR) {
+		/* 8139C+ has different bit layout. */
+		rval &= ~(BMCR_LOOP | BMCR_ISO);
+	}
 	return (rval);
 }
 
 static int
-re_miibus_writereg(dev, phy, reg, data)
-	device_t		dev;
-	int			phy, reg, data;
+re_miibus_writereg(device_t dev, int phy, int reg, int data)
 {
 	struct rl_softc		*sc;
 	u_int16_t		re8139_reg = 0;
@@ -543,6 +633,10 @@
 	switch (reg) {
 	case MII_BMCR:
 		re8139_reg = RL_BMCR;
+		if (sc->rl_type == RL_8139CPLUS) {
+			/* 8139C+ has different bit layout. */
+			data &= ~(BMCR_LOOP | BMCR_ISO);
+		}
 		break;
 	case MII_BMSR:
 		re8139_reg = RL_BMSR;
@@ -561,7 +655,7 @@
 		return (0);
 		break;
 	default:
-		if_printf(sc->rl_ifp, "bad phy register\n");
+		device_printf(sc->rl_dev, "bad phy register\n");
 		return (0);
 	}
 	CSR_WRITE_2(sc, re8139_reg, data);
@@ -569,45 +663,73 @@
 }
 
 static void
-re_miibus_statchg(dev)
-	device_t		dev;
+re_miibus_statchg(device_t dev)
 {
+	struct rl_softc		*sc;
+	struct ifnet		*ifp;
+	struct mii_data		*mii;
+
+	sc = device_get_softc(dev);
+	mii = device_get_softc(sc->rl_miibus);
+	ifp = sc->rl_ifp;
+	if (mii == NULL || ifp == NULL ||
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
 
+	sc->rl_flags &= ~RL_FLAG_LINK;
+	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+	    (IFM_ACTIVE | IFM_AVALID)) {
+		switch (IFM_SUBTYPE(mii->mii_media_active)) {
+		case IFM_10_T:
+		case IFM_100_TX:
+			sc->rl_flags |= RL_FLAG_LINK;
+			break;
+		case IFM_1000_T:
+			if ((sc->rl_flags & RL_FLAG_FASTETHER) != 0)
+				break;
+			sc->rl_flags |= RL_FLAG_LINK;
+			break;
+		default:
+			break;
+		}
+	}
+	/*
+	 * RealTek controllers does not provide any interface to
+	 * Tx/Rx MACs for resolved speed, duplex and flow-control
+	 * parameters.
+	 */
 }
 
 /*
- * Program the 64-bit multicast hash filter.
+ * Set the RX configuration and 64-bit multicast hash filter.
  */
 static void
-re_setmulti(sc)
-	struct rl_softc		*sc;
+re_set_rxmode(struct rl_softc *sc)
 {
 	struct ifnet		*ifp;
-	int			h = 0;
-	u_int32_t		hashes[2] = { 0, 0 };
 	struct ifmultiaddr	*ifma;
-	u_int32_t		rxfilt;
-	int			mcnt = 0;
+	uint32_t		hashes[2] = { 0, 0 };
+	uint32_t		h, rxfilt;
 
 	RL_LOCK_ASSERT(sc);
 
 	ifp = sc->rl_ifp;
 
-	rxfilt = CSR_READ_4(sc, RL_RXCFG);
+	rxfilt = RL_RXCFG_CONFIG | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_BROAD;
 
-	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+	if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
+		if (ifp->if_flags & IFF_PROMISC)
+			rxfilt |= RL_RXCFG_RX_ALLPHYS;
+		/*
+		 * Unlike other hardwares, we have to explicitly set
+		 * RL_RXCFG_RX_MULTI to receive multicast frames in
+		 * promiscuous mode.
+		 */
 		rxfilt |= RL_RXCFG_RX_MULTI;
-		CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
-		CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF);
-		CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF);
-		return;
+		hashes[0] = hashes[1] = 0xffffffff;
+		goto done;
 	}
 
-	/* first, zot all the existing hash bits */
-	CSR_WRITE_4(sc, RL_MAR0, 0);
-	CSR_WRITE_4(sc, RL_MAR4, 0);
-
-	/* now program new ones */
 	IF_ADDR_LOCK(ifp);
 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 		if (ifma->ifma_addr->sa_family != AF_LINK)
@@ -618,25 +740,35 @@
 			hashes[0] |= (1 << h);
 		else
 			hashes[1] |= (1 << (h - 32));
-		mcnt++;
 	}
 	IF_ADDR_UNLOCK(ifp);
 
-	if (mcnt)
+	if (hashes[0] != 0 || hashes[1] != 0) {
+		/*
+		 * For some unfathomable reason, RealTek decided to
+		 * reverse the order of the multicast hash registers
+		 * in the PCI Express parts.  This means we have to
+		 * write the hash pattern in reverse order for those
+		 * devices.
+		 */
+		if ((sc->rl_flags & RL_FLAG_PCIE) != 0) {
+			h = bswap32(hashes[0]);
+			hashes[0] = bswap32(hashes[1]);
+			hashes[1] = h;
+		}
 		rxfilt |= RL_RXCFG_RX_MULTI;
-	else
-		rxfilt &= ~RL_RXCFG_RX_MULTI;
+	}
 
-	CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
+done:
 	CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
 	CSR_WRITE_4(sc, RL_MAR4, hashes[1]);
+	CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
 }
 
 static void
-re_reset(sc)
-	struct rl_softc		*sc;
+re_reset(struct rl_softc *sc)
 {
-	register int		i;
+	int			i;
 
 	RL_LOCK_ASSERT(sc);
 
@@ -648,11 +780,16 @@
 			break;
 	}
 	if (i == RL_TIMEOUT)
-		if_printf(sc->rl_ifp, "reset never completed!\n");
+		device_printf(sc->rl_dev, "reset never completed!\n");
 
-	CSR_WRITE_1(sc, 0x82, 1);
+	if ((sc->rl_flags & RL_FLAG_MACRESET) != 0)
+		CSR_WRITE_1(sc, 0x82, 1);
+	if (sc->rl_hwrev == RL_HWREV_8169S)
+		re_gmii_writereg(sc->rl_dev, 1, 0x0b, 0);
 }
 
+#ifdef RE_DIAG
+
 /*
  * The following routine is designed to test for a defect on some
  * 32-bit 8169 cards. Some of these NICs have the REQ64# and ACK64#
@@ -674,8 +811,7 @@
  */
 
 static int
-re_diag(sc)
-	struct rl_softc		*sc;
+re_diag(struct rl_softc *sc)
 {
 	struct ifnet		*ifp = sc->rl_ifp;
 	struct mbuf		*m0;
@@ -683,7 +819,7 @@
 	struct rl_desc		*cur_rx;
 	u_int16_t		status;
 	u_int32_t		rxstat;
-	int			total_len, i, error = 0;
+	int			total_len, i, error = 0, phyaddr;
 	u_int8_t		dst[] = { 0x00, 'h', 'e', 'l', 'l', 'o' };
 	u_int8_t		src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' };
 
@@ -706,9 +842,23 @@
 	ifp->if_flags |= IFF_PROMISC;
 	sc->rl_testmode = 1;
 	re_init_locked(sc);
-	re_stop(sc);
+	sc->rl_flags |= RL_FLAG_LINK;
+	if (sc->rl_type == RL_8169)
+		phyaddr = 1;
+	else
+		phyaddr = 0;
+
+	re_miibus_writereg(sc->rl_dev, phyaddr, MII_BMCR, BMCR_RESET);
+	for (i = 0; i < RL_TIMEOUT; i++) {
+		status = re_miibus_readreg(sc->rl_dev, phyaddr, MII_BMCR);
+		if (!(status & BMCR_RESET))
+			break;
+	}
+
+	re_miibus_writereg(sc->rl_dev, phyaddr, MII_BMCR, BMCR_LOOP);
+	CSR_WRITE_2(sc, RL_ISR, RL_INTRS);
+
 	DELAY(100000);
-	re_init_locked(sc);
 
 	/* Put some data in the mbuf */
 
@@ -735,6 +885,7 @@
 	DELAY(100000);
 	for (i = 0; i < RL_TIMEOUT; i++) {
 		status = CSR_READ_2(sc, RL_ISR);
+		CSR_WRITE_2(sc, RL_ISR, status);
 		if ((status & (RL_ISR_TIMEOUT_EXPIRED|RL_ISR_RX_OK)) ==
 		    (RL_ISR_TIMEOUT_EXPIRED|RL_ISR_RX_OK))
 			break;
@@ -742,8 +893,9 @@
 	}
 
 	if (i == RL_TIMEOUT) {
-		if_printf(ifp, "diagnostic failed, failed to receive packet "
-		    "in loopback mode\n");
+		device_printf(sc->rl_dev,
+		    "diagnostic failed, failed to receive packet in"
+		    " loopback mode\n");
 		error = EIO;
 		goto done;
 	}
@@ -756,14 +908,14 @@
 	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
 	    sc->rl_ldata.rl_rx_list_map,
 	    BUS_DMASYNC_POSTREAD);
-	bus_dmamap_sync(sc->rl_ldata.rl_mtag,
-	    sc->rl_ldata.rl_rx_dmamap[0],
-	    BUS_DMASYNC_POSTWRITE);
-	bus_dmamap_unload(sc->rl_ldata.rl_mtag,
-	    sc->rl_ldata.rl_rx_dmamap[0]);
+	bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
+	    sc->rl_ldata.rl_rx_desc[0].rx_dmamap,
+	    BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(sc->rl_ldata.rl_rx_mtag,
+	    sc->rl_ldata.rl_rx_desc[0].rx_dmamap);
 
-	m0 = sc->rl_ldata.rl_rx_mbuf[0];
-	sc->rl_ldata.rl_rx_mbuf[0] = NULL;
+	m0 = sc->rl_ldata.rl_rx_desc[0].rx_m;
+	sc->rl_ldata.rl_rx_desc[0].rx_m = NULL;
 	eh = mtod(m0, struct ether_header *);
 
 	cur_rx = &sc->rl_ldata.rl_rx_list[0];
@@ -771,7 +923,8 @@
 	rxstat = le32toh(cur_rx->rl_cmdstat);
 
 	if (total_len != ETHER_MIN_LEN) {
-		if_printf(ifp, "diagnostic failed, received short packet\n");
+		device_printf(sc->rl_dev,
+		    "diagnostic failed, received short packet\n");
 		error = EIO;
 		goto done;
 	}
@@ -781,17 +934,18 @@
 	if (bcmp((char *)&eh->ether_dhost, (char *)&dst, ETHER_ADDR_LEN) ||
 	    bcmp((char *)&eh->ether_shost, (char *)&src, ETHER_ADDR_LEN) ||
 	    ntohs(eh->ether_type) != ETHERTYPE_IP) {
-		if_printf(ifp, "WARNING, DMA FAILURE!\n");
-		if_printf(ifp, "expected TX data: %6D/%6D/0x%x\n",
+		device_printf(sc->rl_dev, "WARNING, DMA FAILURE!\n");
+		device_printf(sc->rl_dev, "expected TX data: %6D/%6D/0x%x\n",
 		    dst, ":", src, ":", ETHERTYPE_IP);
-		if_printf(ifp, "received RX data: %6D/%6D/0x%x\n",
+		device_printf(sc->rl_dev, "received RX data: %6D/%6D/0x%x\n",
 		    eh->ether_dhost, ":",  eh->ether_shost, ":",
 		    ntohs(eh->ether_type));
-		if_printf(ifp, "You may have a defective 32-bit NIC plugged "
-		    "into a 64-bit PCI slot.\n");
-		if_printf(ifp, "Please re-install the NIC in a 32-bit slot "
-		    "for proper operation.\n");
-		if_printf(ifp, "Read the re(4) man page for more details.\n");
+		device_printf(sc->rl_dev, "You may have a defective 32-bit "
+		    "NIC plugged into a 64-bit PCI slot.\n");
+		device_printf(sc->rl_dev, "Please re-install the NIC in a "
+		    "32-bit slot for proper operation.\n");
+		device_printf(sc->rl_dev, "Read the re(4) man page for more "
+		    "details.\n");
 		error = EIO;
 	}
 
@@ -799,6 +953,7 @@
 	/* Turn interface off, release resources */
 
 	sc->rl_testmode = 0;
+	sc->rl_flags &= ~RL_FLAG_LINK;
 	ifp->if_flags &= ~IFF_PROMISC;
 	re_stop(sc);
 	if (m0 != NULL)
@@ -809,139 +964,51 @@
 	return (error);
 }
 
+#endif
+
 /*
  * Probe for a RealTek 8139C+/8169/8110 chip. Check the PCI vendor and device
  * IDs against our list and return a device name if we find a match.
  */
 static int
-re_probe(dev)
-	device_t		dev;
+re_probe(device_t dev)
 {
 	struct rl_type		*t;
-	struct rl_softc		*sc;
-	int			rid;
-	u_int32_t		hwrev;
-
-	t = re_devs;
-	sc = device_get_softc(dev);
+	uint16_t		devid, vendor;
+	uint16_t		revid, sdevid;
+	int			i;
+	
+	vendor = pci_get_vendor(dev);
+	devid = pci_get_device(dev);
+	revid = pci_get_revid(dev);
+	sdevid = pci_get_subdevice(dev);
 
-	while (t->rl_name != NULL) {
-		if ((pci_get_vendor(dev) == t->rl_vid) &&
-		    (pci_get_device(dev) == t->rl_did)) {
+	if (vendor == LINKSYS_VENDORID && devid == LINKSYS_DEVICEID_EG1032) {
+		if (sdevid != LINKSYS_SUBDEVICE_EG1032_REV3) {
 			/*
 			 * Only attach to rev. 3 of the Linksys EG1032 adapter.
-			 * Rev. 2 i supported by sk(4).
-			 */
-			if ((t->rl_vid == LINKSYS_VENDORID) &&
-				(t->rl_did == LINKSYS_DEVICEID_EG1032) &&
-				(pci_get_subdevice(dev) !=
-				LINKSYS_SUBDEVICE_EG1032_REV3)) {
-				t++;
-				continue;
-			}
-
-			/*
-			 * Temporarily map the I/O space
-			 * so we can read the chip ID register.
+			 * Rev. 2 is supported by sk(4).
 			 */
-			rid = RL_RID;
-			sc->rl_res = bus_alloc_resource_any(dev, RL_RES, &rid,
-			    RF_ACTIVE);
-			if (sc->rl_res == NULL) {
-				device_printf(dev,
-				    "couldn't map ports/memory\n");
-				return (ENXIO);
-			}
-			sc->rl_btag = rman_get_bustag(sc->rl_res);
-			sc->rl_bhandle = rman_get_bushandle(sc->rl_res);
-			hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
-			bus_release_resource(dev, RL_RES,
-			    RL_RID, sc->rl_res);
-			if (t->rl_basetype == hwrev) {
-				device_set_desc(dev, t->rl_name);
-				return (BUS_PROBE_DEFAULT);
-			}
+			return (ENXIO);
 		}
-		t++;
 	}
 
-	return (ENXIO);
-}
-
-/*
- * This routine takes the segment list provided as the result of
- * a bus_dma_map_load() operation and assigns the addresses/lengths
- * to RealTek DMA descriptors. This can be called either by the RX
- * code or the TX code. In the RX case, we'll probably wind up mapping
- * at most one segment. For the TX case, there could be any number of
- * segments since TX packets may span multiple mbufs. In either case,
- * if the number of segments is larger than the rl_maxsegs limit
- * specified by the caller, we abort the mapping operation. Sadly,
- * whoever designed the buffer mapping API did not provide a way to
- * return an error from here, so we have to fake it a bit.
- */
-
-static void
-re_dma_map_desc(arg, segs, nseg, mapsize, error)
-	void			*arg;
-	bus_dma_segment_t	*segs;
-	int			nseg;
-	bus_size_t		mapsize;
-	int			error;
-{
-	struct rl_dmaload_arg	*ctx;
-	struct rl_desc		*d = NULL;
-	int			i = 0, idx;
-
-	if (error)
-		return;
-
-	ctx = arg;
-
-	/* Signal error to caller if there's too many segments */
-	if (nseg > ctx->rl_maxsegs) {
-		ctx->rl_maxsegs = 0;
-		return;
+	if (vendor == RT_VENDORID && devid == RT_DEVICEID_8139) {
+		if (revid != 0x20) {
+			/* 8139, let rl(4) take care of this device. */
+			return (ENXIO);
+		}
 	}
 
-	/*
-	 * Map the segment array into descriptors. Note that we set the
-	 * start-of-frame and end-of-frame markers for either TX or RX, but
-	 * they really only have meaning in the TX case. (In the RX case,
-	 * it's the chip that tells us where packets begin and end.)
-	 * We also keep track of the end of the ring and set the
-	 * end-of-ring bits as needed, and we set the ownership bits
-	 * in all except the very first descriptor. (The caller will
-	 * set this descriptor later when it start transmission or
-	 * reception.)
-	 */
-	idx = ctx->rl_idx;
-	for (;;) {
-		u_int32_t		cmdstat;
-		d = &ctx->rl_ring[idx];
-		if (le32toh(d->rl_cmdstat) & RL_RDESC_STAT_OWN) {
-			ctx->rl_maxsegs = 0;
-			return;
+	t = re_devs;
+	for (i = 0; i < sizeof(re_devs) / sizeof(re_devs[0]); i++, t++) {
+		if (vendor == t->rl_vid && devid == t->rl_did) {
+			device_set_desc(dev, t->rl_name);
+			return (BUS_PROBE_DEFAULT);
 		}
-		cmdstat = segs[i].ds_len;
-		d->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[i].ds_addr));
-		d->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[i].ds_addr));
-		if (i == 0)
-			cmdstat |= RL_TDESC_CMD_SOF;
-		else
-			cmdstat |= RL_TDESC_CMD_OWN;
-		if (idx == (RL_RX_DESC_CNT - 1))
-			cmdstat |= RL_TDESC_CMD_EOR;
-		d->rl_cmdstat = htole32(cmdstat | ctx->rl_flags);
-		i++;
-		if (i == nseg)
-			break;
-		RL_DESC_INC(idx);
 	}
 
-	d->rl_cmdstat |= htole32(RL_TDESC_CMD_EOF);
-	ctx->rl_maxsegs = nseg;
-	ctx->rl_idx = idx;
+	return (ENXIO);
 }
 
 /*
@@ -949,11 +1016,7 @@
  */
 
 static void
-re_dma_map_addr(arg, segs, nseg, error)
-	void			*arg;
-	bus_dma_segment_t	*segs;
-	int			nseg;
-	int			error;
+re_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
 	bus_addr_t		*addr;
 
@@ -966,25 +1029,54 @@
 }
 
 static int
-re_allocmem(dev, sc)
-	device_t		dev;
-	struct rl_softc		*sc;
+re_allocmem(device_t dev, struct rl_softc *sc)
 {
+	bus_size_t		rx_list_size, tx_list_size;
 	int			error;
-	int			nseg;
 	int			i;
 
+	rx_list_size = sc->rl_ldata.rl_rx_desc_cnt * sizeof(struct rl_desc);
+	tx_list_size = sc->rl_ldata.rl_tx_desc_cnt * sizeof(struct rl_desc);
+
+	/*
+	 * Allocate the parent bus DMA tag appropriate for PCI.
+	 * In order to use DAC, RL_CPLUSCMD_PCI_DAC bit of RL_CPLUS_CMD
+	 * register should be set. However some RealTek chips are known
+	 * to be buggy on DAC handling, therefore disable DAC by limiting
+	 * DMA address space to 32bit. PCIe variants of RealTek chips
+	 * may not have the limitation but I took safer path.
+	 */
+	error = bus_dma_tag_create(NULL, 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0,
+	    NULL, NULL, &sc->rl_parent_tag);
+	if (error) {
+		device_printf(dev, "could not allocate parent DMA tag\n");
+		return (error);
+	}
+
+	/*
+	 * Allocate map for TX mbufs.
+	 */
+	error = bus_dma_tag_create(sc->rl_parent_tag, 1, 0,
+	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL,
+	    NULL, MCLBYTES * RL_NTXSEGS, RL_NTXSEGS, 4096, 0,
+	    NULL, NULL, &sc->rl_ldata.rl_tx_mtag);
+	if (error) {
+		device_printf(dev, "could not allocate TX DMA tag\n");
+		return (error);
+	}
+
 	/*
 	 * Allocate map for RX mbufs.
 	 */
-	nseg = 32;
-	error = bus_dma_tag_create(sc->rl_parent_tag, ETHER_ALIGN, 0,
-	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
-	    NULL, MCLBYTES * nseg, nseg, MCLBYTES, BUS_DMA_ALLOCNOW,
-	    NULL, NULL, &sc->rl_ldata.rl_mtag);
+
+	error = bus_dma_tag_create(sc->rl_parent_tag, sizeof(uint64_t), 0,
+	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+	    MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->rl_ldata.rl_rx_mtag);
 	if (error) {
-		device_printf(dev, "could not allocate dma tag\n");
-		return (ENOMEM);
+		device_printf(dev, "could not allocate RX DMA tag\n");
+		return (error);
 	}
 
 	/*
@@ -992,36 +1084,44 @@
 	 */
 	error = bus_dma_tag_create(sc->rl_parent_tag, RL_RING_ALIGN,
 	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
-	    NULL, RL_TX_LIST_SZ, 1, RL_TX_LIST_SZ, BUS_DMA_ALLOCNOW,
+	    NULL, tx_list_size, 1, tx_list_size, 0,
 	    NULL, NULL, &sc->rl_ldata.rl_tx_list_tag);
 	if (error) {
-		device_printf(dev, "could not allocate dma tag\n");
-		return (ENOMEM);
+		device_printf(dev, "could not allocate TX DMA ring tag\n");
+		return (error);
 	}
 
 	/* Allocate DMA'able memory for the TX ring */
 
 	error = bus_dmamem_alloc(sc->rl_ldata.rl_tx_list_tag,
-	    (void **)&sc->rl_ldata.rl_tx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
+	    (void **)&sc->rl_ldata.rl_tx_list,
+	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
 	    &sc->rl_ldata.rl_tx_list_map);
-	if (error)
-		return (ENOMEM);
+	if (error) {
+		device_printf(dev, "could not allocate TX DMA ring\n");
+		return (error);
+	}
 
 	/* Load the map for the TX ring. */
 
+	sc->rl_ldata.rl_tx_list_addr = 0;
 	error = bus_dmamap_load(sc->rl_ldata.rl_tx_list_tag,
 	     sc->rl_ldata.rl_tx_list_map, sc->rl_ldata.rl_tx_list,
-	     RL_TX_LIST_SZ, re_dma_map_addr,
+	     tx_list_size, re_dma_map_addr,
 	     &sc->rl_ldata.rl_tx_list_addr, BUS_DMA_NOWAIT);
+	if (error != 0 || sc->rl_ldata.rl_tx_list_addr == 0) {
+		device_printf(dev, "could not load TX DMA ring\n");
+		return (ENOMEM);
+	}
 
 	/* Create DMA maps for TX buffers */
 
-	for (i = 0; i < RL_TX_DESC_CNT; i++) {
-		error = bus_dmamap_create(sc->rl_ldata.rl_mtag, 0,
-			    &sc->rl_ldata.rl_tx_dmamap[i]);
+	for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++) {
+		error = bus_dmamap_create(sc->rl_ldata.rl_tx_mtag, 0,
+		    &sc->rl_ldata.rl_tx_desc[i].tx_dmamap);
 		if (error) {
-			device_printf(dev, "can't create DMA map for TX\n");
-			return (ENOMEM);
+			device_printf(dev, "could not create DMA map for TX\n");
+			return (error);
 		}
 	}
 
@@ -1030,36 +1130,50 @@
 	 */
 	error = bus_dma_tag_create(sc->rl_parent_tag, RL_RING_ALIGN,
 	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
-	    NULL, RL_RX_LIST_SZ, 1, RL_RX_LIST_SZ, BUS_DMA_ALLOCNOW,
+	    NULL, rx_list_size, 1, rx_list_size, 0,
 	    NULL, NULL, &sc->rl_ldata.rl_rx_list_tag);
 	if (error) {
-		device_printf(dev, "could not allocate dma tag\n");
-		return (ENOMEM);
+		device_printf(dev, "could not create RX DMA ring tag\n");
+		return (error);
 	}
 
 	/* Allocate DMA'able memory for the RX ring */
 
 	error = bus_dmamem_alloc(sc->rl_ldata.rl_rx_list_tag,
-	    (void **)&sc->rl_ldata.rl_rx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
+	    (void **)&sc->rl_ldata.rl_rx_list,
+	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
 	    &sc->rl_ldata.rl_rx_list_map);
-	if (error)
-		return (ENOMEM);
+	if (error) {
+		device_printf(dev, "could not allocate RX DMA ring\n");
+		return (error);
+	}
 
 	/* Load the map for the RX ring. */
 
+	sc->rl_ldata.rl_rx_list_addr = 0;
 	error = bus_dmamap_load(sc->rl_ldata.rl_rx_list_tag,
 	     sc->rl_ldata.rl_rx_list_map, sc->rl_ldata.rl_rx_list,
-	     RL_RX_LIST_SZ, re_dma_map_addr,
+	     rx_list_size, re_dma_map_addr,
 	     &sc->rl_ldata.rl_rx_list_addr, BUS_DMA_NOWAIT);
+	if (error != 0 || sc->rl_ldata.rl_rx_list_addr == 0) {
+		device_printf(dev, "could not load RX DMA ring\n");
+		return (ENOMEM);
+	}
 
 	/* Create DMA maps for RX buffers */
 
-	for (i = 0; i < RL_RX_DESC_CNT; i++) {
-		error = bus_dmamap_create(sc->rl_ldata.rl_mtag, 0,
-			    &sc->rl_ldata.rl_rx_dmamap[i]);
+	error = bus_dmamap_create(sc->rl_ldata.rl_rx_mtag, 0,
+	    &sc->rl_ldata.rl_rx_sparemap);
+	if (error) {
+		device_printf(dev, "could not create spare DMA map for RX\n");
+		return (error);
+	}
+	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
+		error = bus_dmamap_create(sc->rl_ldata.rl_rx_mtag, 0,
+		    &sc->rl_ldata.rl_rx_desc[i].rx_dmamap);
 		if (error) {
-			device_printf(dev, "can't create DMA map for RX\n");
-			return (ENOMEM);
+			device_printf(dev, "could not create DMA map for RX\n");
+			return (error);
 		}
 	}
 
@@ -1071,19 +1185,20 @@
  * setup and ethernet/BPF attach.
  */
 static int
-re_attach(dev)
-	device_t		dev;
+re_attach(device_t dev)
 {
 	u_char			eaddr[ETHER_ADDR_LEN];
-	u_int16_t		as[3];
+	u_int16_t		as[ETHER_ADDR_LEN / 2];
 	struct rl_softc		*sc;
 	struct ifnet		*ifp;
 	struct rl_hwrev		*hw_rev;
 	int			hwrev;
-	u_int16_t		re_did = 0;
+	u_int16_t		devid, re_did = 0;
 	int			error = 0, rid, i;
+	uint8_t			cfg;
 
 	sc = device_get_softc(dev);
+	sc->rl_dev = dev;
 
 	mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 	    MTX_DEF);
@@ -1094,10 +1209,32 @@
 	 */
 	pci_enable_busmaster(dev);
 
-	rid = RL_RID;
-	sc->rl_res = bus_alloc_resource_any(dev, RL_RES, &rid,
-	    RF_ACTIVE);
-
+	devid = pci_get_device(dev);
+	/*
+	 * Prefer memory space register mapping over IO space.
+	 * Because RTL8169SC does not seem to work when memory mapping
+	 * is used always activate io mapping. 
+	 */
+	if (devid == RT_DEVICEID_8169SC)
+		prefer_iomap = 1;
+	if (prefer_iomap == 0) {
+		sc->rl_res_id = PCIR_BAR(1);
+		sc->rl_res_type = SYS_RES_MEMORY;
+		/* RTL8168/8101E seems to use different BARs. */
+		if (devid == RT_DEVICEID_8168 || devid == RT_DEVICEID_8101E)
+			sc->rl_res_id = PCIR_BAR(2);
+	} else {
+		sc->rl_res_id = PCIR_BAR(0);
+		sc->rl_res_type = SYS_RES_IOPORT;
+	}
+	sc->rl_res = bus_alloc_resource_any(dev, sc->rl_res_type,
+	    &sc->rl_res_id, RF_ACTIVE);
+	if (sc->rl_res == NULL && prefer_iomap == 0) {
+		sc->rl_res_id = PCIR_BAR(0);
+		sc->rl_res_type = SYS_RES_IOPORT;
+		sc->rl_res = bus_alloc_resource_any(dev, sc->rl_res_type,
+		    &sc->rl_res_id, RF_ACTIVE);
+	}
 	if (sc->rl_res == NULL) {
 		device_printf(dev, "couldn't map ports/memory\n");
 		error = ENXIO;
@@ -1108,14 +1245,38 @@
 	sc->rl_bhandle = rman_get_bushandle(sc->rl_res);
 
 	/* Allocate interrupt */
-	rid = 0;
-	sc->rl_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
-	    RF_SHAREABLE | RF_ACTIVE);
+	if ((sc->rl_flags & RL_FLAG_MSI) == 0) {
+		rid = 0;
+		sc->rl_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+		    RF_SHAREABLE | RF_ACTIVE);
+		if (sc->rl_irq[0] == NULL) {
+			device_printf(dev, "couldn't allocate IRQ resources\n");
+			error = ENXIO;
+			goto fail;
+		}
+	} else {
+		for (i = 0, rid = 1; i < RL_MSI_MESSAGES; i++, rid++) {
+			sc->rl_irq[i] = bus_alloc_resource_any(dev,
+			    SYS_RES_IRQ, &rid, RF_ACTIVE);
+			if (sc->rl_irq[i] == NULL) {
+				device_printf(dev,
+				    "couldn't llocate IRQ resources for "
+				    "message %d\n", rid);
+				error = ENXIO;
+				goto fail;
+			}
+		}
+	}
 
-	if (sc->rl_irq == NULL) {
-		device_printf(dev, "couldn't map interrupt\n");
-		error = ENXIO;
-		goto fail;
+	if ((sc->rl_flags & RL_FLAG_MSI) == 0) {
+		CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
+		cfg = CSR_READ_1(sc, RL_CFG2);
+		if ((cfg & RL_CFG2_MSI) != 0) {
+			device_printf(dev, "turning off MSI enable bit.\n");
+			cfg &= ~RL_CFG2_MSI;
+			CSR_WRITE_1(sc, RL_CFG2, cfg);
+		}
+		CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 	}
 
 	/* Reset the adapter. */
@@ -1124,74 +1285,138 @@
 	RL_UNLOCK(sc);
 
 	hw_rev = re_hwrevs;
-	hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
+	hwrev = CSR_READ_4(sc, RL_TXCFG);
+	switch (hwrev & 0x70000000) {
+	case 0x00000000:
+	case 0x10000000:
+		device_printf(dev, "Chip rev. 0x%08x\n", hwrev & 0xfc800000);
+		hwrev &= (RL_TXCFG_HWREV | 0x80000000);
+		break;
+	default:
+		device_printf(dev, "Chip rev. 0x%08x\n", hwrev & 0x7c800000);
+		hwrev &= RL_TXCFG_HWREV;
+		break;
+	}
+	device_printf(dev, "MAC rev. 0x%08x\n", hwrev & 0x00700000);
 	while (hw_rev->rl_desc != NULL) {
 		if (hw_rev->rl_rev == hwrev) {
 			sc->rl_type = hw_rev->rl_type;
+			sc->rl_hwrev = hw_rev->rl_rev;
 			break;
 		}
 		hw_rev++;
 	}
+	if (hw_rev->rl_desc == NULL) {
+		device_printf(dev, "Unknown H/W revision: 0x%08x\n", hwrev);
+		error = ENXIO;
+		goto fail;
+	}
 
-	if (sc->rl_type == RL_8169) {
-
-		/* Set RX length mask */
-
-		sc->rl_rxlenmask = RL_RDESC_STAT_GFRAGLEN;
-
-		/* Force station address autoload from the EEPROM */
+	switch (hw_rev->rl_rev) {
+	case RL_HWREV_8139CPLUS:
+		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_FASTETHER;
+		break;
+	case RL_HWREV_8100E:
+	case RL_HWREV_8101E:
+		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_PHYWAKE |
+		    RL_FLAG_FASTETHER;
+		break;
+	case RL_HWREV_8102E:
+	case RL_HWREV_8102EL:
+		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_PHYWAKE |
+		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
+		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP;
+		break;
+	case RL_HWREV_8168_SPIN1:
+	case RL_HWREV_8168_SPIN2:
+	case RL_HWREV_8168_SPIN3:
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_MACSTAT;
+		break;
+	case RL_HWREV_8168C_SPIN2:
+		sc->rl_flags |= RL_FLAG_MACSLEEP;
+		/* FALLTHROUGH */
+	case RL_HWREV_8168C:
+		if ((hwrev & 0x00700000) == 0x00200000)
+			sc->rl_flags |= RL_FLAG_MACSLEEP;
+		/* FALLTHROUGH */
+	case RL_HWREV_8168CP:
+	case RL_HWREV_8168D:
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
+		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP;
+		/*
+		 * These controllers support jumbo frame but it seems
+		 * that enabling it requires touching additional magic
+		 * registers. Depending on MAC revisions some
+		 * controllers need to disable checksum offload. So
+		 * disable jumbo frame until I have better idea what
+		 * it really requires to make it support.
+		 * RTL8168C/CP : supports up to 6KB jumbo frame.
+		 * RTL8111C/CP : supports up to 9KB jumbo frame.
+		 */
+		sc->rl_flags |= RL_FLAG_NOJUMBO;
+		break;
+	case RL_HWREV_8169_8110SB:
+	case RL_HWREV_8169_8110SBL:
+	case RL_HWREV_8169_8110SC:
+	case RL_HWREV_8169_8110SCE:
+		sc->rl_flags |= RL_FLAG_PHYWAKE;
+		/* FALLTHROUGH */
+	case RL_HWREV_8169:
+	case RL_HWREV_8169S:
+	case RL_HWREV_8110S:
+		sc->rl_flags |= RL_FLAG_MACRESET;
+		break;
+	default:
+		break;
+	}
 
-		CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_AUTOLOAD);
-		for (i = 0; i < RL_TIMEOUT; i++) {
-			if (!(CSR_READ_1(sc, RL_EECMD) & RL_EEMODE_AUTOLOAD))
-				break;
-			DELAY(100);
-		}
-		if (i == RL_TIMEOUT)
-			device_printf(dev, "eeprom autoload timed out\n");
+	/* Enable PME. */
+	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
+	cfg = CSR_READ_1(sc, RL_CFG1);
+	cfg |= RL_CFG1_PME;
+	CSR_WRITE_1(sc, RL_CFG1, cfg);
+	cfg = CSR_READ_1(sc, RL_CFG5);
+	cfg &= RL_CFG5_PME_STS;
+	CSR_WRITE_1(sc, RL_CFG5, cfg);
+	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 
-			for (i = 0; i < ETHER_ADDR_LEN; i++)
-				eaddr[i] = CSR_READ_1(sc, RL_IDR0 + i);
+	if ((sc->rl_flags & RL_FLAG_PAR) != 0) {
+		/*
+		 * XXX Should have a better way to extract station
+		 * address from EEPROM.
+		 */
+		for (i = 0; i < ETHER_ADDR_LEN; i++)
+			eaddr[i] = CSR_READ_1(sc, RL_IDR0 + i);
 	} else {
-
-		/* Set RX length mask */
-
-		sc->rl_rxlenmask = RL_RDESC_STAT_FRAGLEN;
-
-		sc->rl_eecmd_read = RL_EECMD_READ_6BIT;
-		re_read_eeprom(sc, (caddr_t)&re_did, 0, 1, 0);
+		sc->rl_eewidth = RL_9356_ADDR_LEN;
+		re_read_eeprom(sc, (caddr_t)&re_did, 0, 1);
 		if (re_did != 0x8129)
-			sc->rl_eecmd_read = RL_EECMD_READ_8BIT;
+			sc->rl_eewidth = RL_9346_ADDR_LEN;
 
 		/*
 		 * Get station address from the EEPROM.
 		 */
-		re_read_eeprom(sc, (caddr_t)as, RL_EE_EADDR, 3, 0);
-		for (i = 0; i < 3; i++) {
-			eaddr[(i * 2) + 0] = as[i] & 0xff;
-			eaddr[(i * 2) + 1] = as[i] >> 8;
-		}
+		re_read_eeprom(sc, (caddr_t)as, RL_EE_EADDR, 3);
+		for (i = 0; i < ETHER_ADDR_LEN / 2; i++)
+			as[i] = le16toh(as[i]);
+		bcopy(as, eaddr, sizeof(eaddr));
 	}
 
-	/*
-	 * Allocate the parent bus DMA tag appropriate for PCI.
-	 */
-#define RL_NSEG_NEW 32
-	error = bus_dma_tag_create(NULL,	/* parent */
-			1, 0,			/* alignment, boundary */
-			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
-			BUS_SPACE_MAXADDR,	/* highaddr */
-			NULL, NULL,		/* filter, filterarg */
-			MAXBSIZE, RL_NSEG_NEW,	/* maxsize, nsegments */
-			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
-			BUS_DMA_ALLOCNOW,	/* flags */
-			NULL, NULL,		/* lockfunc, lockarg */
-			&sc->rl_parent_tag);
-	if (error)
-		goto fail;
+	if (sc->rl_type == RL_8169) {
+		/* Set RX length mask and number of descriptors. */
+		sc->rl_rxlenmask = RL_RDESC_STAT_GFRAGLEN;
+		sc->rl_txstart = RL_GTXSTART;
+		sc->rl_ldata.rl_tx_desc_cnt = RL_8169_TX_DESC_CNT;
+		sc->rl_ldata.rl_rx_desc_cnt = RL_8169_RX_DESC_CNT;
+	} else {
+		/* Set RX length mask and number of descriptors. */
+		sc->rl_rxlenmask = RL_RDESC_STAT_FRAGLEN;
+		sc->rl_txstart = RL_TXSTART;
+		sc->rl_ldata.rl_tx_desc_cnt = RL_8139_TX_DESC_CNT;
+		sc->rl_ldata.rl_rx_desc_cnt = RL_8139_RX_DESC_CNT;
+	}
 
 	error = re_allocmem(dev, sc);
-
 	if (error)
 		goto fail;
 
@@ -1202,6 +1427,22 @@
 		goto fail;
 	}
 
+	/* Take controller out of deep sleep mode. */
+	if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) {
+		if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80)
+			CSR_WRITE_1(sc, RL_GPIO,
+			    CSR_READ_1(sc, RL_GPIO) | 0x01);
+		else
+			CSR_WRITE_1(sc, RL_GPIO,
+			    CSR_READ_1(sc, RL_GPIO) & ~0x01);
+	}
+
+	/* Take PHY out of power down mode. */
+	if ((sc->rl_flags & RL_FLAG_PHYWAKE) != 0) {
+		re_gmii_writereg(dev, 1, 0x1f, 0);
+		re_gmii_writereg(dev, 1, 0x0e, 0);
+	}
+
 	/* Do MII setup */
 	if (mii_phy_probe(dev, &sc->rl_miibus,
 	    re_ifmedia_upd, re_ifmedia_sts)) {
@@ -1212,46 +1453,67 @@
 
 	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 = re_ioctl;
-	ifp->if_capabilities = IFCAP_VLAN_MTU;
 	ifp->if_start = re_start;
-	ifp->if_hwassist = /*RE_CSUM_FEATURES*/0;
-	ifp->if_capabilities |= IFCAP_HWCSUM|IFCAP_VLAN_HWTAGGING;
-	ifp->if_capenable = ifp->if_capabilities & ~IFCAP_HWCSUM;
-#ifdef DEVICE_POLLING
-	ifp->if_capabilities |= IFCAP_POLLING;
-#endif
-	ifp->if_watchdog = re_watchdog;
+	ifp->if_hwassist = RE_CSUM_FEATURES;
+	ifp->if_capabilities = IFCAP_HWCSUM;
+	ifp->if_capenable = ifp->if_capabilities;
 	ifp->if_init = re_init;
-	IFQ_SET_MAXLEN(&ifp->if_snd,  RL_IFQ_MAXLEN);
+	IFQ_SET_MAXLEN(&ifp->if_snd, RL_IFQ_MAXLEN);
 	ifp->if_snd.ifq_drv_maxlen = RL_IFQ_MAXLEN;
 	IFQ_SET_READY(&ifp->if_snd);
 
+	TASK_INIT(&sc->rl_txtask, 1, re_tx_task, ifp);
+	TASK_INIT(&sc->rl_inttask, 0, re_int_task, sc);
+
 	/*
 	 * Call MI attach routine.
 	 */
 	ether_ifattach(ifp, eaddr);
 
-	/* Perform hardware diagnostic. */
-	error = re_diag(sc);
+	/* VLAN capability setup */
+	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
+	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);
+
+#ifdef RE_DIAG
+	/*
+	 * Perform hardware diagnostic on the original RTL8169.
+	 * Some 32-bit cards were incorrectly wired and would
+	 * malfunction if plugged into a 64-bit slot.
+	 */
 
-	if (error) {
-		device_printf(dev, "attach aborted due to hardware diag failure\n");
-		ether_ifdetach(ifp);
-		goto fail;
+	if (hwrev == RL_HWREV_8169) {
+		error = re_diag(sc);
+		if (error) {
+			device_printf(dev,
+		    	"attach aborted due to hardware diag failure\n");
+			ether_ifdetach(ifp);
+			goto fail;
+		}
 	}
+#endif
 
 	/* Hook interrupt last to avoid having to lock softc */
-	error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET | INTR_MPSAFE,
-	    re_intr, sc, &sc->rl_intrhand);
+	error = bus_setup_intr(dev, sc->rl_irq[0],
+	    INTR_TYPE_NET | INTR_MPSAFE, re_intr, sc,
+	    &sc->rl_intrhand[0]);
 	if (error) {
 		device_printf(dev, "couldn't set up irq\n");
 		ether_ifdetach(ifp);
 	}
 
 fail:
+
 	if (error)
 		re_detach(dev);
 
@@ -1266,8 +1528,7 @@
  * allocated.
  */
 static int
-re_detach(dev)
-	device_t		dev;
+re_detach(device_t dev)
 {
 	struct rl_softc		*sc;
 	struct ifnet		*ifp;
@@ -1277,12 +1538,12 @@
 	ifp = sc->rl_ifp;
 	KASSERT(mtx_initialized(&sc->rl_mtx), ("re mutex not initialized"));
 
-#ifdef DEVICE_POLLING
-	if (ifp->if_capenable & IFCAP_POLLING)
-		ether_poll_deregister(ifp);
-#endif
 	/* These should only be active if attach succeeded */
 	if (device_is_attached(dev)) {
+#ifdef DEVICE_POLLING
+		if (ifp->if_capenable & IFCAP_POLLING)
+			ether_poll_deregister(ifp);
+#endif
 		RL_LOCK(sc);
 #if 0
 		sc->suspended = 1;
@@ -1290,6 +1551,8 @@
 		re_stop(sc);
 		RL_UNLOCK(sc);
 		callout_drain(&sc->rl_stat_callout);
+		taskqueue_drain(taskqueue_fast, &sc->rl_inttask);
+		taskqueue_drain(taskqueue_fast, &sc->rl_txtask);
 		/*
 		 * Force off the IFF_UP flag here, in case someone
 		 * still had a BPF descriptor attached to this
@@ -1314,15 +1577,23 @@
 	 * stopped here.
 	 */
 
-	if (sc->rl_intrhand)
-		bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
+	for (i = 0; i < RL_MSI_MESSAGES; i++) {
+		if (sc->rl_intrhand[i] != NULL) {
+			bus_teardown_intr(dev, sc->rl_irq[i],
+			    sc->rl_intrhand[i]);
+			sc->rl_intrhand[i] = NULL;
+		}
+	}
 	if (ifp != NULL)
 		if_free(ifp);
-	if (sc->rl_irq)
-		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
+	if (sc->rl_irq[0] != NULL) {
+		bus_release_resource(dev, SYS_RES_IRQ, 0,
+		    sc->rl_irq[0]);
+		sc->rl_irq[0] = NULL;
+	}
 	if (sc->rl_res)
-		bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res);
-
+		bus_release_resource(dev, sc->rl_res_type, sc->rl_res_id,
+		    sc->rl_res);
 
 	/* Unload and free the RX DMA ring memory and map */
 
@@ -1348,14 +1619,20 @@
 
 	/* Destroy all the RX and TX buffer maps */
 
-	if (sc->rl_ldata.rl_mtag) {
-		for (i = 0; i < RL_TX_DESC_CNT; i++)
-			bus_dmamap_destroy(sc->rl_ldata.rl_mtag,
-			    sc->rl_ldata.rl_tx_dmamap[i]);
-		for (i = 0; i < RL_RX_DESC_CNT; i++)
-			bus_dmamap_destroy(sc->rl_ldata.rl_mtag,
-			    sc->rl_ldata.rl_rx_dmamap[i]);
-		bus_dma_tag_destroy(sc->rl_ldata.rl_mtag);
+	if (sc->rl_ldata.rl_tx_mtag) {
+		for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++)
+			bus_dmamap_destroy(sc->rl_ldata.rl_tx_mtag,
+			    sc->rl_ldata.rl_tx_desc[i].tx_dmamap);
+		bus_dma_tag_destroy(sc->rl_ldata.rl_tx_mtag);
+	}
+	if (sc->rl_ldata.rl_rx_mtag) {
+		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++)
+			bus_dmamap_destroy(sc->rl_ldata.rl_rx_mtag,
+			    sc->rl_ldata.rl_rx_desc[i].rx_dmamap);
+		if (sc->rl_ldata.rl_rx_sparemap)
+			bus_dmamap_destroy(sc->rl_ldata.rl_rx_mtag,
+			    sc->rl_ldata.rl_rx_sparemap);
+		bus_dma_tag_destroy(sc->rl_ldata.rl_rx_mtag);
 	}
 
 	/* Unload and free the stats buffer and map */
@@ -1377,23 +1654,36 @@
 	return (0);
 }
 
+static __inline void
+re_discard_rxbuf(struct rl_softc *sc, int idx)
+{
+	struct rl_desc		*desc;
+	struct rl_rxdesc	*rxd;
+	uint32_t		cmdstat;
+
+	rxd = &sc->rl_ldata.rl_rx_desc[idx];
+	desc = &sc->rl_ldata.rl_rx_list[idx];
+	desc->rl_vlanctl = 0;
+	cmdstat = rxd->rx_size;
+	if (idx == sc->rl_ldata.rl_rx_desc_cnt - 1)
+		cmdstat |= RL_RDESC_CMD_EOR;
+	desc->rl_cmdstat = htole32(cmdstat | RL_RDESC_CMD_OWN);
+}
+
 static int
-re_newbuf(sc, idx, m)
-	struct rl_softc		*sc;
-	int			idx;
-	struct mbuf		*m;
+re_newbuf(struct rl_softc *sc, int idx)
 {
-	struct rl_dmaload_arg	arg;
-	struct mbuf		*n = NULL;
-	int			error;
+	struct mbuf		*m;
+	struct rl_rxdesc	*rxd;
+	bus_dma_segment_t	segs[1];
+	bus_dmamap_t		map;
+	struct rl_desc		*desc;
+	uint32_t		cmdstat;
+	int			error, nsegs;
 
-	if (m == NULL) {
-		n = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
-		if (n == NULL)
-			return (ENOBUFS);
-		m = n;
-	} else
-		m->m_data = m->m_ext.ext_buf;
+	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	if (m == NULL)
+		return (ENOBUFS);
 
 	m->m_len = m->m_pkthdr.len = MCLBYTES;
 #ifdef RE_FIXUP_RX
@@ -1409,35 +1699,44 @@
 	 */
 	m_adj(m, RE_ETHER_ALIGN);
 #endif
-	arg.sc = sc;
-	arg.rl_idx = idx;
-	arg.rl_maxsegs = 1;
-	arg.rl_flags = 0;
-	arg.rl_ring = sc->rl_ldata.rl_rx_list;
-
-	error = bus_dmamap_load_mbuf(sc->rl_ldata.rl_mtag,
-	    sc->rl_ldata.rl_rx_dmamap[idx], m, re_dma_map_desc,
-	    &arg, BUS_DMA_NOWAIT);
-	if (error || arg.rl_maxsegs != 1) {
-		if (n != NULL)
-			m_freem(n);
-		return (ENOMEM);
+	error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_rx_mtag,
+	    sc->rl_ldata.rl_rx_sparemap, m, segs, &nsegs, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		m_freem(m);
+		return (ENOBUFS);
 	}
+	KASSERT(nsegs == 1, ("%s: %d segment returned!", __func__, nsegs));
 
-	sc->rl_ldata.rl_rx_list[idx].rl_cmdstat |= htole32(RL_RDESC_CMD_OWN);
-	sc->rl_ldata.rl_rx_mbuf[idx] = m;
+	rxd = &sc->rl_ldata.rl_rx_desc[idx];
+	if (rxd->rx_m != NULL) {
+		bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag, rxd->rx_dmamap,
+		    BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->rl_ldata.rl_rx_mtag, rxd->rx_dmamap);
+	}
 
-	bus_dmamap_sync(sc->rl_ldata.rl_mtag,
-	    sc->rl_ldata.rl_rx_dmamap[idx],
+	rxd->rx_m = m;
+	map = rxd->rx_dmamap;
+	rxd->rx_dmamap = sc->rl_ldata.rl_rx_sparemap;
+	rxd->rx_size = segs[0].ds_len;
+	sc->rl_ldata.rl_rx_sparemap = map;
+	bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag, rxd->rx_dmamap,
 	    BUS_DMASYNC_PREREAD);
 
+	desc = &sc->rl_ldata.rl_rx_list[idx];
+	desc->rl_vlanctl = 0;
+	desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[0].ds_addr));
+	desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[0].ds_addr));
+	cmdstat = segs[0].ds_len;
+	if (idx == sc->rl_ldata.rl_rx_desc_cnt - 1)
+		cmdstat |= RL_RDESC_CMD_EOR;
+	desc->rl_cmdstat = htole32(cmdstat | RL_RDESC_CMD_OWN);
+
 	return (0);
 }
 
 #ifdef RE_FIXUP_RX
 static __inline void
-re_fixup_rx(m)
-	struct mbuf		*m;
+re_fixup_rx(struct mbuf *m)
 {
 	int                     i;
 	uint16_t                *src, *dst;
@@ -1449,44 +1748,47 @@
 		*dst++ = *src++;
 
 	m->m_data -= RE_ETHER_ALIGN - ETHER_ALIGN;
-
-	return;
 }
 #endif
 
 static int
-re_tx_list_init(sc)
-	struct rl_softc		*sc;
+re_tx_list_init(struct rl_softc *sc)
 {
+	struct rl_desc		*desc;
+	int			i;
 
 	RL_LOCK_ASSERT(sc);
 
-	bzero ((char *)sc->rl_ldata.rl_tx_list, RL_TX_LIST_SZ);
-	bzero ((char *)&sc->rl_ldata.rl_tx_mbuf,
-	    (RL_TX_DESC_CNT * sizeof(struct mbuf *)));
+	bzero(sc->rl_ldata.rl_tx_list,
+	    sc->rl_ldata.rl_tx_desc_cnt * sizeof(struct rl_desc));
+	for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++)
+		sc->rl_ldata.rl_tx_desc[i].tx_m = NULL;
+	/* Set EOR. */
+	desc = &sc->rl_ldata.rl_tx_list[sc->rl_ldata.rl_tx_desc_cnt - 1];
+	desc->rl_cmdstat |= htole32(RL_TDESC_CMD_EOR);
 
 	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
-	    sc->rl_ldata.rl_tx_list_map, BUS_DMASYNC_PREWRITE);
+	    sc->rl_ldata.rl_tx_list_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
 	sc->rl_ldata.rl_tx_prodidx = 0;
 	sc->rl_ldata.rl_tx_considx = 0;
-	sc->rl_ldata.rl_tx_free = RL_TX_DESC_CNT;
+	sc->rl_ldata.rl_tx_free = sc->rl_ldata.rl_tx_desc_cnt;
 
 	return (0);
 }
 
 static int
-re_rx_list_init(sc)
-	struct rl_softc		*sc;
+re_rx_list_init(struct rl_softc *sc)
 {
-	int			i;
-
-	bzero ((char *)sc->rl_ldata.rl_rx_list, RL_RX_LIST_SZ);
-	bzero ((char *)&sc->rl_ldata.rl_rx_mbuf,
-	    (RL_RX_DESC_CNT * sizeof(struct mbuf *)));
+	int			error, i;
 
-	for (i = 0; i < RL_RX_DESC_CNT; i++) {
-		if (re_newbuf(sc, i, NULL) == ENOBUFS)
-			return (ENOBUFS);
+	bzero(sc->rl_ldata.rl_rx_list,
+	    sc->rl_ldata.rl_rx_desc_cnt * sizeof(struct rl_desc));
+	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
+		sc->rl_ldata.rl_rx_desc[i].rx_m = NULL;
+		if ((error = re_newbuf(sc, i)) != 0)
+			return (error);
 	}
 
 	/* Flush the RX descriptors */
@@ -1506,43 +1808,49 @@
  * the reception of jumbo frames that have been fragmented
  * across multiple 2K mbuf cluster buffers.
  */
-static void
-re_rxeof(sc)
-	struct rl_softc		*sc;
+static int
+re_rxeof(struct rl_softc *sc)
 {
 	struct mbuf		*m;
 	struct ifnet		*ifp;
 	int			i, total_len;
 	struct rl_desc		*cur_rx;
 	u_int32_t		rxstat, rxvlan;
+	int			maxpkt = 16;
 
 	RL_LOCK_ASSERT(sc);
 
 	ifp = sc->rl_ifp;
-	i = sc->rl_ldata.rl_rx_prodidx;
 
 	/* Invalidate the descriptor memory */
 
 	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
 	    sc->rl_ldata.rl_rx_list_map,
-	    BUS_DMASYNC_POSTREAD);
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 
-	while (!RL_OWN(&sc->rl_ldata.rl_rx_list[i])) {
+	for (i = sc->rl_ldata.rl_rx_prodidx; maxpkt > 0;
+	    i = RL_RX_DESC_NXT(sc, i)) {
 		cur_rx = &sc->rl_ldata.rl_rx_list[i];
-		m = sc->rl_ldata.rl_rx_mbuf[i];
-		total_len = RL_RXBYTES(cur_rx);
 		rxstat = le32toh(cur_rx->rl_cmdstat);
+		if ((rxstat & RL_RDESC_STAT_OWN) != 0)
+			break;
+		total_len = rxstat & sc->rl_rxlenmask;
 		rxvlan = le32toh(cur_rx->rl_vlanctl);
-
-		/* Invalidate the RX mbuf and unload its map */
-
-		bus_dmamap_sync(sc->rl_ldata.rl_mtag,
-		    sc->rl_ldata.rl_rx_dmamap[i],
-		    BUS_DMASYNC_POSTWRITE);
-		bus_dmamap_unload(sc->rl_ldata.rl_mtag,
-		    sc->rl_ldata.rl_rx_dmamap[i]);
+		m = sc->rl_ldata.rl_rx_desc[i].rx_m;
 
 		if (!(rxstat & RL_RDESC_STAT_EOF)) {
+			if (re_newbuf(sc, i) != 0) {
+				/*
+				 * If this is part of a multi-fragment packet,
+				 * discard all the pieces.
+				 */
+				if (sc->rl_head != NULL) {
+					m_freem(sc->rl_head);
+					sc->rl_head = sc->rl_tail = NULL;
+				}
+				re_discard_rxbuf(sc, i);
+				continue;
+			}
 			m->m_len = RE_RX_DESC_BUFLEN;
 			if (sc->rl_head == NULL)
 				sc->rl_head = sc->rl_tail = m;
@@ -1551,8 +1859,6 @@
 				sc->rl_tail->m_next = m;
 				sc->rl_tail = m;
 			}
-			re_newbuf(sc, i, NULL);
-			RL_DESC_INC(i);
 			continue;
 		}
 
@@ -1590,8 +1896,7 @@
 				m_freem(sc->rl_head);
 				sc->rl_head = sc->rl_tail = NULL;
 			}
-			re_newbuf(sc, i, m);
-			RL_DESC_INC(i);
+			re_discard_rxbuf(sc, i);
 			continue;
 		}
 
@@ -1600,19 +1905,16 @@
 		 * reload the current one.
 		 */
 
-		if (re_newbuf(sc, i, NULL)) {
-			ifp->if_ierrors++;
+		if (re_newbuf(sc, i) != 0) {
+			ifp->if_iqdrops++;
 			if (sc->rl_head != NULL) {
 				m_freem(sc->rl_head);
 				sc->rl_head = sc->rl_tail = NULL;
 			}
-			re_newbuf(sc, i, m);
-			RL_DESC_INC(i);
+			re_discard_rxbuf(sc, i);
 			continue;
 		}
 
-		RL_DESC_INC(i);
-
 		if (sc->rl_head != NULL) {
 			m->m_len = total_len % RE_RX_DESC_BUFLEN;
 			if (m->m_len == 0)
@@ -1648,24 +1950,47 @@
 		/* Do RX checksumming if enabled */
 
 		if (ifp->if_capenable & IFCAP_RXCSUM) {
-
-			/* Check IP header checksum */
-			if (rxstat & RL_RDESC_STAT_PROTOID)
-				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
-			if (!(rxstat & RL_RDESC_STAT_IPSUMBAD))
-				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
-
-			/* Check TCP/UDP checksum */
-			if ((RL_TCPPKT(rxstat) &&
-			    !(rxstat & RL_RDESC_STAT_TCPSUMBAD)) ||
-			    (RL_UDPPKT(rxstat) &&
-			    !(rxstat & RL_RDESC_STAT_UDPSUMBAD))) {
-				m->m_pkthdr.csum_flags |=
-				    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
-				m->m_pkthdr.csum_data = 0xffff;
+			if ((sc->rl_flags & RL_FLAG_DESCV2) == 0) {
+				/* Check IP header checksum */
+				if (rxstat & RL_RDESC_STAT_PROTOID)
+					m->m_pkthdr.csum_flags |=
+					    CSUM_IP_CHECKED;
+				if (!(rxstat & RL_RDESC_STAT_IPSUMBAD))
+					m->m_pkthdr.csum_flags |=
+					    CSUM_IP_VALID;
+
+				/* Check TCP/UDP checksum */
+				if ((RL_TCPPKT(rxstat) &&
+				    !(rxstat & RL_RDESC_STAT_TCPSUMBAD)) ||
+				    (RL_UDPPKT(rxstat) &&
+				     !(rxstat & RL_RDESC_STAT_UDPSUMBAD))) {
+					m->m_pkthdr.csum_flags |=
+						CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
+					m->m_pkthdr.csum_data = 0xffff;
+				}
+			} else {
+				/*
+				 * RTL8168C/RTL816CP/RTL8111C/RTL8111CP
+				 */
+				if ((rxstat & RL_RDESC_STAT_PROTOID) &&
+				    (rxvlan & RL_RDESC_IPV4))
+					m->m_pkthdr.csum_flags |=
+					    CSUM_IP_CHECKED;
+				if (!(rxstat & RL_RDESC_STAT_IPSUMBAD) &&
+				    (rxvlan & RL_RDESC_IPV4))
+					m->m_pkthdr.csum_flags |=
+					    CSUM_IP_VALID;
+				if (((rxstat & RL_RDESC_STAT_TCP) &&
+				    !(rxstat & RL_RDESC_STAT_TCPSUMBAD)) ||
+				    ((rxstat & RL_RDESC_STAT_UDP) &&
+				    !(rxstat & RL_RDESC_STAT_UDPSUMBAD))) {
+					m->m_pkthdr.csum_flags |=
+						CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
+					m->m_pkthdr.csum_data = 0xffff;
+				}
 			}
 		}
-
+		maxpkt--;
 		if (rxvlan & RL_RDESC_VLANCTL_TAG) {
 			VLAN_INPUT_TAG_NEW(ifp, m,
 			    ntohs((rxvlan & RL_RDESC_VLANCTL_DATA)));
@@ -1684,43 +2009,52 @@
 	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
 
 	sc->rl_ldata.rl_rx_prodidx = i;
+
+	if (maxpkt)
+		return(EAGAIN);
+
+	return(0);
 }
 
 static void
-re_txeof(sc)
-	struct rl_softc		*sc;
+re_txeof(struct rl_softc *sc)
 {
 	struct ifnet		*ifp;
+	struct rl_txdesc	*txd;
 	u_int32_t		txstat;
-	int			idx;
+	int			cons;
 
-	ifp = sc->rl_ifp;
-	idx = sc->rl_ldata.rl_tx_considx;
+	cons = sc->rl_ldata.rl_tx_considx;
+	if (cons == sc->rl_ldata.rl_tx_prodidx)
+		return;
 
+	ifp = sc->rl_ifp;
 	/* Invalidate the TX descriptor list */
-
 	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
 	    sc->rl_ldata.rl_tx_list_map,
-	    BUS_DMASYNC_POSTREAD);
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 
-	while (idx != sc->rl_ldata.rl_tx_prodidx) {
-
-		txstat = le32toh(sc->rl_ldata.rl_tx_list[idx].rl_cmdstat);
-		if (txstat & RL_TDESC_CMD_OWN)
+	for (; cons != sc->rl_ldata.rl_tx_prodidx;
+	    cons = RL_TX_DESC_NXT(sc, cons)) {
+		txstat = le32toh(sc->rl_ldata.rl_tx_list[cons].rl_cmdstat);
+		if (txstat & RL_TDESC_STAT_OWN)
 			break;
-
 		/*
 		 * We only stash mbufs in the last descriptor
 		 * in a fragment chain, which also happens to
 		 * be the only place where the TX status bits
 		 * are valid.
 		 */
-
 		if (txstat & RL_TDESC_CMD_EOF) {
-			m_freem(sc->rl_ldata.rl_tx_mbuf[idx]);
-			sc->rl_ldata.rl_tx_mbuf[idx] = NULL;
-			bus_dmamap_unload(sc->rl_ldata.rl_mtag,
-			    sc->rl_ldata.rl_tx_dmamap[idx]);
+			txd = &sc->rl_ldata.rl_tx_desc[cons];
+			bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
+			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->rl_ldata.rl_tx_mtag,
+			    txd->tx_dmamap);
+			KASSERT(txd->tx_m != NULL,
+			    ("%s: freeing NULL mbufs!", __func__));
+			m_freem(txd->tx_m);
+			txd->tx_m = NULL;
 			if (txstat & (RL_TDESC_STAT_EXCESSCOL|
 			    RL_TDESC_STAT_COLCNT))
 				ifp->if_collisions++;
@@ -1730,30 +2064,28 @@
 				ifp->if_opackets++;
 		}
 		sc->rl_ldata.rl_tx_free++;
-		RL_DESC_INC(idx);
+		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 	}
+	sc->rl_ldata.rl_tx_considx = cons;
 
 	/* No changes made to the TX ring, so no flush needed */
 
-	if (idx != sc->rl_ldata.rl_tx_considx) {
-		sc->rl_ldata.rl_tx_considx = idx;
-		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-		ifp->if_timer = 0;
-	}
-
-	/*
-	 * If not all descriptors have been released reaped yet,
-	 * reload the timer so that we will eventually get another
-	 * interrupt that will cause us to re-enter this routine.
-	 * This is done in case the transmitter has gone idle.
-	 */
-	if (sc->rl_ldata.rl_tx_free != RL_TX_DESC_CNT)
+	if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt) {
+#ifdef RE_TX_MODERATION
+		/*
+		 * If not all descriptors have been reaped yet, reload
+		 * the timer so that we will eventually get another
+		 * interrupt that will cause us to re-enter this routine.
+		 * This is done in case the transmitter has gone idle.
+		 */
 		CSR_WRITE_4(sc, RL_TIMERCNT, 1);
+#endif
+	} else
+		sc->rl_watchdog_timer = 0;
 }
 
 static void
-re_tick(xsc)
-	void			*xsc;
+re_tick(void *xsc)
 {
 	struct rl_softc		*sc;
 	struct mii_data		*mii;
@@ -1763,9 +2095,17 @@
 	RL_LOCK_ASSERT(sc);
 
 	mii = device_get_softc(sc->rl_miibus);
-
 	mii_tick(mii);
-
+	if ((sc->rl_flags & RL_FLAG_LINK) == 0)
+		re_miibus_statchg(sc->rl_dev);
+	/*
+	 * Reclaim transmitted frames here. Technically it is not
+	 * necessary to do here but it ensures periodic reclamation
+	 * regardless of Tx completion interrupt which seems to be
+	 * lost on PCIe based controllers under certain situations. 
+	 */
+	re_txeof(sc);
+	re_watchdog(sc);
 	callout_reset(&sc->rl_stat_callout, hz, re_tick, sc);
 }
 
@@ -1793,7 +2133,7 @@
 	re_txeof(sc);
 
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-		re_start_locked(ifp);
+		taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask);
 
 	if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
 		u_int16_t       status;
@@ -1803,226 +2143,329 @@
 			return;
 		if (status)
 			CSR_WRITE_2(sc, RL_ISR, status);
+		if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
+		    (sc->rl_flags & RL_FLAG_PCIE))
+			CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
 
 		/*
 		 * XXX check behaviour on receiver stalls.
 		 */
 
-		if (status & RL_ISR_SYSTEM_ERR) {
-			re_reset(sc);
+		if (status & RL_ISR_SYSTEM_ERR)
 			re_init_locked(sc);
-		}
 	}
 }
 #endif /* DEVICE_POLLING */
 
 static void
-re_intr(arg)
-	void			*arg;
+re_intr(void *arg)
+{
+	struct rl_softc		*sc;
+	uint16_t		status;
+
+	sc = arg;
+
+	status = CSR_READ_2(sc, RL_ISR);
+	if (status == 0xFFFF || (status & RL_INTRS_CPLUS) == 0)
+                return;
+
+	CSR_WRITE_2(sc, RL_IMR, 0);
+
+	taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_inttask);
+
+	return;
+}
+
+static void
+re_int_task(void *arg, int npending)
 {
 	struct rl_softc		*sc;
 	struct ifnet		*ifp;
 	u_int16_t		status;
+	int			rval = 0;
 
 	sc = arg;
+	ifp = sc->rl_ifp;
 
 	RL_LOCK(sc);
 
-	ifp = sc->rl_ifp;
+	status = CSR_READ_2(sc, RL_ISR);
+        CSR_WRITE_2(sc, RL_ISR, status);
 
-	if (sc->suspended || !(ifp->if_flags & IFF_UP))
-		goto done_locked;
+	if (sc->suspended ||
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+		RL_UNLOCK(sc);
+		return;
+	}
 
 #ifdef DEVICE_POLLING
-	if  (ifp->if_capenable & IFCAP_POLLING)
-		goto done_locked;
+	if  (ifp->if_capenable & IFCAP_POLLING) {
+		RL_UNLOCK(sc);
+		return;
+	}
 #endif
 
-	for (;;) {
+	if (status & (RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_FIFO_OFLOW))
+		rval = re_rxeof(sc);
 
-		status = CSR_READ_2(sc, RL_ISR);
-		/* If the card has gone away the read returns 0xffff. */
-		if (status == 0xffff)
-			break;
-		if (status)
-			CSR_WRITE_2(sc, RL_ISR, status);
+	/*
+	 * Some chips will ignore a second TX request issued
+	 * while an existing transmission is in progress. If
+	 * the transmitter goes idle but there are still
+	 * packets waiting to be sent, we need to restart the
+	 * channel here to flush them out. This only seems to
+	 * be required with the PCIe devices.
+	 */
+	if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
+	    (sc->rl_flags & RL_FLAG_PCIE))
+		CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
+	if (status & (
+#ifdef RE_TX_MODERATION
+	    RL_ISR_TIMEOUT_EXPIRED|
+#else
+	    RL_ISR_TX_OK|
+#endif
+	    RL_ISR_TX_ERR|RL_ISR_TX_DESC_UNAVAIL))
+		re_txeof(sc);
 
-		if ((status & RL_INTRS_CPLUS) == 0)
-			break;
+	if (status & RL_ISR_SYSTEM_ERR)
+		re_init_locked(sc);
 
-		if (((status & RL_ISR_RX_OK) ||
-		    (status & RL_ISR_RX_ERR)) &&
-		    ifp->if_drv_flags & IFF_DRV_RUNNING)
-			re_rxeof(sc);
-
-		if (((status & RL_ISR_TIMEOUT_EXPIRED) ||
-		    (status & RL_ISR_TX_ERR) ||
-		    (status & RL_ISR_TX_DESC_UNAVAIL)) &&
-		    ifp->if_drv_flags & IFF_DRV_RUNNING)
-			re_txeof(sc);
+	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+		taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask);
 
-		if (status & RL_ISR_SYSTEM_ERR) {
-			re_reset(sc);
-			re_init_locked(sc);
-		}
+	RL_UNLOCK(sc);
 
-		if (status & RL_ISR_LINKCHG) {
-			callout_stop(&sc->rl_stat_callout);
-			re_tick(sc);
-		}
+        if ((CSR_READ_2(sc, RL_ISR) & RL_INTRS_CPLUS) || rval) {
+		taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_inttask);
+		return;
 	}
 
-	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-		re_start_locked(ifp);
-
-done_locked:
-	RL_UNLOCK(sc);
+	CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS);
 }
 
 static int
-re_encap(sc, m_head, idx)
-	struct rl_softc		*sc;
-	struct mbuf		**m_head;
-	int			*idx;
+re_encap(struct rl_softc *sc, struct mbuf **m_head)
 {
-	struct mbuf		*m_new = NULL;
-	struct rl_dmaload_arg	arg;
+	struct rl_txdesc	*txd, *txd_last;
+	bus_dma_segment_t	segs[RL_NTXSEGS];
 	bus_dmamap_t		map;
-	int			error;
+	struct mbuf		*m_new;
+	struct rl_desc		*desc;
+	int			nsegs, prod;
+	int			i, error, ei, si;
+	int			padlen;
+	uint32_t		cmdstat, csum_flags, vlanctl;
 	struct m_tag		*mtag;
 
 	RL_LOCK_ASSERT(sc);
-
-	if (sc->rl_ldata.rl_tx_free <= 4)
-		return (EFBIG);
+	M_ASSERTPKTHDR((*m_head));
 
 	/*
-	 * Set up checksum offload. Note: checksum offload bits must
-	 * appear in all descriptors of a multi-descriptor transmit
-	 * attempt. This is according to testing done with an 8169
-	 * chip. This is a requirement.
-	 */
-
-	arg.rl_flags = 0;
-
-	if ((*m_head)->m_pkthdr.csum_flags & CSUM_IP)
-		arg.rl_flags |= RL_TDESC_CMD_IPCSUM;
-	if ((*m_head)->m_pkthdr.csum_flags & CSUM_TCP)
-		arg.rl_flags |= RL_TDESC_CMD_TCPCSUM;
-	if ((*m_head)->m_pkthdr.csum_flags & CSUM_UDP)
-		arg.rl_flags |= RL_TDESC_CMD_UDPCSUM;
-
-	arg.sc = sc;
-	arg.rl_idx = *idx;
-	arg.rl_maxsegs = sc->rl_ldata.rl_tx_free;
-	if (arg.rl_maxsegs > 4)
-		arg.rl_maxsegs -= 4;
-	arg.rl_ring = sc->rl_ldata.rl_tx_list;
-
-	map = sc->rl_ldata.rl_tx_dmamap[*idx];
-	error = bus_dmamap_load_mbuf(sc->rl_ldata.rl_mtag, map,
-	    *m_head, re_dma_map_desc, &arg, BUS_DMA_NOWAIT);
+	 * With some of the RealTek chips, using the checksum offload
+	 * support in conjunction with the autopadding feature results
+	 * in the transmission of corrupt frames. For example, if we
+	 * need to send a really small IP fragment that's less than 60
+	 * bytes in size, and IP header checksumming is enabled, the
+	 * resulting ethernet frame that appears on the wire will
+	 * have garbled payload. To work around this, if TX IP checksum
+	 * offload is enabled, we always manually pad short frames out
+	 * to the minimum ethernet frame size.
+	 */
+	if ((sc->rl_flags & RL_FLAG_DESCV2) == 0 &&
+	    (*m_head)->m_pkthdr.len < RL_IP4CSUMTX_PADLEN &&
+	    ((*m_head)->m_pkthdr.csum_flags & CSUM_IP) != 0) {
+		padlen = RL_MIN_FRAMELEN - (*m_head)->m_pkthdr.len;
+		if (M_WRITABLE(*m_head) == 0) {
+			/* Get a writable copy. */
+			m_new = m_dup(*m_head, M_DONTWAIT);
+			m_freem(*m_head);
+			if (m_new == NULL) {
+				*m_head = NULL;
+				return (ENOBUFS);
+			}
+			*m_head = m_new;
+		}
+		if ((*m_head)->m_next != NULL ||
+		    M_TRAILINGSPACE(*m_head) < padlen) {
+			m_new = m_defrag(*m_head, M_DONTWAIT);
+			if (m_new == NULL) {
+				m_freem(*m_head);
+				*m_head = NULL;
+				return (ENOBUFS);
+			}
+		} else
+			m_new = *m_head;
 
-	if (error && error != EFBIG) {
-		if_printf(sc->rl_ifp, "can't map mbuf (error %d)\n", error);
-		return (ENOBUFS);
+		/*
+		 * Manually pad short frames, and zero the pad space
+		 * to avoid leaking data.
+		 */
+		bzero(mtod(m_new, char *) + m_new->m_pkthdr.len, padlen);
+		m_new->m_pkthdr.len += padlen;
+		m_new->m_len = m_new->m_pkthdr.len;
+		*m_head = m_new;
 	}
 
-	/* Too many segments to map, coalesce into a single mbuf */
-
-	if (error || arg.rl_maxsegs == 0) {
+	prod = sc->rl_ldata.rl_tx_prodidx;
+	txd = &sc->rl_ldata.rl_tx_desc[prod];
+	error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_tx_mtag, txd->tx_dmamap,
+	    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
+	if (error == EFBIG) {
 		m_new = m_defrag(*m_head, M_DONTWAIT);
-		if (m_new == NULL)
+		if (m_new == NULL) {
+			m_freem(*m_head);
+			*m_head = NULL;
 			return (ENOBUFS);
-		else
-			*m_head = m_new;
-
-		arg.sc = sc;
-		arg.rl_idx = *idx;
-		arg.rl_maxsegs = sc->rl_ldata.rl_tx_free;
-		arg.rl_ring = sc->rl_ldata.rl_tx_list;
-
-		error = bus_dmamap_load_mbuf(sc->rl_ldata.rl_mtag, map,
-		    *m_head, re_dma_map_desc, &arg, BUS_DMA_NOWAIT);
-		if (error) {
-			if_printf(sc->rl_ifp, "can't map mbuf (error %d)\n",
-			    error);
-			return (EFBIG);
 		}
+		*m_head = m_new;
+		error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_tx_mtag,
+		    txd->tx_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			m_freem(*m_head);
+			*m_head = NULL;
+			return (error);
+		}
+	} else if (error != 0)
+		return (error);
+	if (nsegs == 0) {
+		m_freem(*m_head);
+		*m_head = NULL;
+		return (EIO);
+	}
+
+	/* Check for number of available descriptors. */
+	if (sc->rl_ldata.rl_tx_free - nsegs <= 1) {
+		bus_dmamap_unload(sc->rl_ldata.rl_tx_mtag, txd->tx_dmamap);
+		return (ENOBUFS);
 	}
 
+	bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag, txd->tx_dmamap,
+	    BUS_DMASYNC_PREWRITE);
+
 	/*
-	 * Insure that the map for this transmission
-	 * is placed at the array index of the last descriptor
-	 * in this chain.  (Swap last and first dmamaps.)
+	 * Set up checksum offload. Note: checksum offload bits must
+	 * appear in all descriptors of a multi-descriptor transmit
+	 * attempt. This is according to testing done with an 8169
+	 * chip. This is a requirement.
 	 */
-	sc->rl_ldata.rl_tx_dmamap[*idx] =
-	    sc->rl_ldata.rl_tx_dmamap[arg.rl_idx];
-	sc->rl_ldata.rl_tx_dmamap[arg.rl_idx] = map;
-
-	sc->rl_ldata.rl_tx_mbuf[arg.rl_idx] = *m_head;
-	sc->rl_ldata.rl_tx_free -= arg.rl_maxsegs;
+	vlanctl = 0;
+	csum_flags = 0;
+	{
+		/*
+		 * Unconditionally enable IP checksum if TCP or UDP
+		 * checksum is required. Otherwise, TCP/UDP checksum
+		 * does't make effects.
+		 */
+		if (((*m_head)->m_pkthdr.csum_flags & RE_CSUM_FEATURES) != 0) {
+			if ((sc->rl_flags & RL_FLAG_DESCV2) == 0) {
+				csum_flags |= RL_TDESC_CMD_IPCSUM;
+				if (((*m_head)->m_pkthdr.csum_flags &
+				    CSUM_TCP) != 0)
+					csum_flags |= RL_TDESC_CMD_TCPCSUM;
+				if (((*m_head)->m_pkthdr.csum_flags &
+				    CSUM_UDP) != 0)
+					csum_flags |= RL_TDESC_CMD_UDPCSUM;
+			} else {
+				vlanctl |= RL_TDESC_CMD_IPCSUMV2;
+				if (((*m_head)->m_pkthdr.csum_flags &
+				    CSUM_TCP) != 0)
+					vlanctl |= RL_TDESC_CMD_TCPCSUMV2;
+				if (((*m_head)->m_pkthdr.csum_flags &
+				    CSUM_UDP) != 0)
+					vlanctl |= RL_TDESC_CMD_UDPCSUMV2;
+			}
+		}
+	}
 
 	/*
 	 * Set up hardware VLAN tagging. Note: vlan tag info must
-	 * appear in the first descriptor of a multi-descriptor
+	 * appear in all descriptors of a multi-descriptor
 	 * transmission attempt.
 	 */
+        mtag = VLAN_OUTPUT_TAG(sc->rl_ifp, *m_head);
+        if (mtag != NULL)
+		vlanctl |= bswap16(VLAN_TAG_VALUE(mtag) | RL_TDESC_VLANCTL_TAG);
+
+	si = prod;
+	for (i = 0; i < nsegs; i++, prod = RL_TX_DESC_NXT(sc, prod)) {
+		desc = &sc->rl_ldata.rl_tx_list[prod];
+		desc->rl_vlanctl = htole32(vlanctl);
+		desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[i].ds_addr));
+		desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[i].ds_addr));
+		cmdstat = segs[i].ds_len;
+		if (i != 0)
+			cmdstat |= RL_TDESC_CMD_OWN;
+		if (prod == sc->rl_ldata.rl_tx_desc_cnt - 1)
+			cmdstat |= RL_TDESC_CMD_EOR;
+		desc->rl_cmdstat = htole32(cmdstat | csum_flags);
+		sc->rl_ldata.rl_tx_free--;
+	}
+	/* Update producer index. */
+	sc->rl_ldata.rl_tx_prodidx = prod;
 
-	mtag = VLAN_OUTPUT_TAG(sc->rl_ifp, *m_head);
-	if (mtag != NULL)
-		sc->rl_ldata.rl_tx_list[*idx].rl_vlanctl =
-		    htole32(htons(VLAN_TAG_VALUE(mtag)) | RL_TDESC_VLANCTL_TAG);
-
-	/* Transfer ownership of packet to the chip. */
-
-	sc->rl_ldata.rl_tx_list[arg.rl_idx].rl_cmdstat |=
-	    htole32(RL_TDESC_CMD_OWN);
-	if (*idx != arg.rl_idx)
-		sc->rl_ldata.rl_tx_list[*idx].rl_cmdstat |=
-		    htole32(RL_TDESC_CMD_OWN);
+	/* Set EOF on the last descriptor. */
+	ei = RL_TX_DESC_PRV(sc, prod);
+	desc = &sc->rl_ldata.rl_tx_list[ei];
+	desc->rl_cmdstat |= htole32(RL_TDESC_CMD_EOF);
 
-	RL_DESC_INC(arg.rl_idx);
-	*idx = arg.rl_idx;
+	desc = &sc->rl_ldata.rl_tx_list[si];
+
+	/* Set SOF and transfer ownership of packet to the chip. */
+	desc->rl_cmdstat |= htole32(RL_TDESC_CMD_OWN | RL_TDESC_CMD_SOF);
+
+	/*
+	 * Insure that the map for this transmission
+	 * is placed at the array index of the last descriptor
+	 * in this chain.  (Swap last and first dmamaps.)
+	 */
+	txd_last = &sc->rl_ldata.rl_tx_desc[ei];
+	map = txd->tx_dmamap;
+	txd->tx_dmamap = txd_last->tx_dmamap;
+	txd_last->tx_dmamap = map;
+	txd_last->tx_m = *m_head;
 
 	return (0);
 }
 
 static void
-re_start(ifp)
-	struct ifnet		*ifp;
+re_tx_task(void *arg, int npending)
 {
-	struct rl_softc		*sc;
+	struct ifnet		*ifp;
 
-	sc = ifp->if_softc;
-	RL_LOCK(sc);
-	re_start_locked(ifp);
-	RL_UNLOCK(sc);
+	ifp = arg;
+	re_start(ifp);
 }
 
 /*
  * Main transmit routine for C+ and gigE NICs.
  */
 static void
-re_start_locked(ifp)
-	struct ifnet		*ifp;
+re_start(struct ifnet *ifp)
 {
 	struct rl_softc		*sc;
-	struct mbuf		*m_head = NULL;
-	int			idx, queued = 0;
+	struct mbuf		*m_head;
+	int			queued;
 
 	sc = ifp->if_softc;
 
-	RL_LOCK_ASSERT(sc);
+	RL_LOCK(sc);
 
-	idx = sc->rl_ldata.rl_tx_prodidx;
+	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+	    IFF_DRV_RUNNING || (sc->rl_flags & RL_FLAG_LINK) == 0) {
+		RL_UNLOCK(sc);
+		return;
+	}
 
-	while (sc->rl_ldata.rl_tx_mbuf[idx] == NULL) {
+	for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+	    sc->rl_ldata.rl_tx_free > 1;) {
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
-		if (re_encap(sc, &m_head, &idx)) {
+		if (re_encap(sc, &m_head) != 0) {
+			if (m_head == NULL)
+				break;
 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 			break;
@@ -2037,8 +2480,14 @@
 		queued++;
 	}
 
-	if (queued == 0)
+	if (queued == 0) {
+#ifdef RE_TX_MODERATION
+		if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt)
+			CSR_WRITE_4(sc, RL_TIMERCNT, 1);
+#endif
+		RL_UNLOCK(sc);
 		return;
+	}
 
 	/* Flush the TX descriptors */
 
@@ -2046,18 +2495,9 @@
 	    sc->rl_ldata.rl_tx_list_map,
 	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
 
-	sc->rl_ldata.rl_tx_prodidx = idx;
-
-	/*
-	 * RealTek put the TX poll request register in a different
-	 * location on the 8169 gigE chip. I don't know why.
-	 */
-
-	if (sc->rl_type == RL_8169)
-		CSR_WRITE_2(sc, RL_GTXSTART, RL_TXSTART_START);
-	else
-		CSR_WRITE_2(sc, RL_TXSTART, RL_TXSTART_START);
+	CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
 
+#ifdef RE_TX_MODERATION
 	/*
 	 * Use the countdown timer for interrupt moderation.
 	 * 'TX done' interrupts are disabled. Instead, we reset the
@@ -2067,16 +2507,18 @@
 	 * the timer count is reset to 0.
 	 */
 	CSR_WRITE_4(sc, RL_TIMERCNT, 1);
+#endif
 
 	/*
 	 * Set a timeout in case the chip goes out to lunch.
 	 */
-	ifp->if_timer = 5;
+	sc->rl_watchdog_timer = 5;
+
+	RL_UNLOCK(sc);
 }
 
 static void
-re_init(xsc)
-	void			*xsc;
+re_init(void *xsc)
 {
 	struct rl_softc		*sc = xsc;
 
@@ -2086,12 +2528,16 @@
 }
 
 static void
-re_init_locked(sc)
-	struct rl_softc		*sc;
+re_init_locked(struct rl_softc *sc)
 {
 	struct ifnet		*ifp = sc->rl_ifp;
 	struct mii_data		*mii;
-	u_int32_t		rxcfg = 0;
+	uint32_t		reg;
+	uint16_t		cfg;
+	union {
+		uint32_t align_dummy;
+		u_char eaddr[ETHER_ADDR_LEN];
+        } eaddr;
 
 	RL_LOCK_ASSERT(sc);
 
@@ -2102,27 +2548,48 @@
 	 */
 	re_stop(sc);
 
+	/* Put controller into known state. */
+	re_reset(sc);
+
 	/*
 	 * Enable C+ RX and TX mode, as well as VLAN stripping and
 	 * RX checksum offload. We must configure the C+ register
 	 * before all others.
 	 */
-	CSR_WRITE_2(sc, RL_CPLUS_CMD, RL_CPLUSCMD_RXENB|
-	    RL_CPLUSCMD_TXENB|RL_CPLUSCMD_PCI_MRW|
-	    RL_CPLUSCMD_VLANSTRIP|
-	    (ifp->if_capenable & IFCAP_RXCSUM ?
-	    RL_CPLUSCMD_RXCSUM_ENB : 0));
+	cfg = RL_CPLUSCMD_PCI_MRW;
+	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+		cfg |= RL_CPLUSCMD_RXCSUM_ENB;
+	if ((sc->rl_flags & RL_FLAG_MACSTAT) != 0) {
+		cfg |= RL_CPLUSCMD_MACSTAT_DIS;
+		/* XXX magic. */
+		cfg |= 0x0001;
+	} else
+		cfg |= RL_CPLUSCMD_RXENB | RL_CPLUSCMD_TXENB;
+	CSR_WRITE_2(sc, RL_CPLUS_CMD, cfg);
+	if (sc->rl_hwrev == RL_HWREV_8169_8110SC ||
+	    sc->rl_hwrev == RL_HWREV_8169_8110SCE) {
+		reg = 0x000fff00;
+		if ((CSR_READ_1(sc, RL_CFG2) & RL_CFG2_PCI66MHZ) != 0)
+			reg |= 0x000000ff;
+		if (sc->rl_hwrev == RL_HWREV_8169_8110SCE)
+			reg |= 0x00f00000;
+		CSR_WRITE_4(sc, 0x7c, reg);
+		/* Disable interrupt mitigation. */
+		CSR_WRITE_2(sc, 0xe2, 0);
+	}
 
 	/*
 	 * Init our MAC address.  Even though the chipset
 	 * documentation doesn't mention it, we need to enter "Config
 	 * register write enable" mode to modify the ID registers.
 	 */
+	/* Copy MAC address on stack to align. */
+	bcopy(IF_LLADDR(ifp), eaddr.eaddr, ETHER_ADDR_LEN);
 	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG);
-	CSR_WRITE_STREAM_4(sc, RL_IDR0,
-	    *(u_int32_t *)(&IFP2ENADDR(sc->rl_ifp)[0]));
-	CSR_WRITE_STREAM_4(sc, RL_IDR4,
-	    *(u_int32_t *)(&IFP2ENADDR(sc->rl_ifp)[4]));
+	CSR_WRITE_4(sc, RL_IDR0,
+	    htole32(*(u_int32_t *)(&eaddr.eaddr[0])));
+	CSR_WRITE_4(sc, RL_IDR4,
+	    htole32(*(u_int32_t *)(&eaddr.eaddr[4])));
 	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 
 	/*
@@ -2132,12 +2599,26 @@
 	re_tx_list_init(sc);
 
 	/*
+	 * Load the addresses of the RX and TX lists into the chip.
+	 */
+
+	CSR_WRITE_4(sc, RL_RXLIST_ADDR_HI,
+	    RL_ADDR_HI(sc->rl_ldata.rl_rx_list_addr));
+	CSR_WRITE_4(sc, RL_RXLIST_ADDR_LO,
+	    RL_ADDR_LO(sc->rl_ldata.rl_rx_list_addr));
+
+	CSR_WRITE_4(sc, RL_TXLIST_ADDR_HI,
+	    RL_ADDR_HI(sc->rl_ldata.rl_tx_list_addr));
+	CSR_WRITE_4(sc, RL_TXLIST_ADDR_LO,
+	    RL_ADDR_LO(sc->rl_ldata.rl_tx_list_addr));
+
+	/*
 	 * Enable transmit and receive.
 	 */
 	CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
 
 	/*
-	 * Set the initial TX and RX configuration.
+	 * Set the initial TX configuration.
 	 */
 	if (sc->rl_testmode) {
 		if (sc->rl_type == RL_8169)
@@ -2148,32 +2629,13 @@
 			    RL_TXCFG_CONFIG|RL_LOOPTEST_ON_CPLUS);
 	} else
 		CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG);
-	CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG);
 
-	/* Set the individual bit to receive frames for this host only. */
-	rxcfg = CSR_READ_4(sc, RL_RXCFG);
-	rxcfg |= RL_RXCFG_RX_INDIV;
-
-	/* If we want promiscuous mode, set the allframes bit. */
-	if (ifp->if_flags & IFF_PROMISC)
-		rxcfg |= RL_RXCFG_RX_ALLPHYS;
-	else
-		rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
-	CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
-
-	/*
-	 * Set capture broadcast bit to capture broadcast frames.
-	 */
-	if (ifp->if_flags & IFF_BROADCAST)
-		rxcfg |= RL_RXCFG_RX_BROAD;
-	else
-		rxcfg &= ~RL_RXCFG_RX_BROAD;
-	CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+	CSR_WRITE_1(sc, RL_EARLY_TX_THRESH, 16);
 
 	/*
-	 * Program the multicast filter, if necessary.
+	 * Set the initial RX configuration.
 	 */
-	re_setmulti(sc);
+	re_set_rxmode(sc);
 
 #ifdef DEVICE_POLLING
 	/*
@@ -2183,6 +2645,7 @@
 		CSR_WRITE_2(sc, RL_IMR, 0);
 	else	/* otherwise ... */
 #endif
+
 	/*
 	 * Enable interrupts.
 	 */
@@ -2190,6 +2653,7 @@
 		CSR_WRITE_2(sc, RL_IMR, 0);
 	else
 		CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS);
+	CSR_WRITE_2(sc, RL_ISR, RL_INTRS_CPLUS);
 
 	/* Set initial TX threshold */
 	sc->rl_txthresh = RL_TX_THRESH_INIT;
@@ -2200,22 +2664,8 @@
 	/* Enable receiver and transmitter. */
 	CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
 #endif
-	/*
-	 * Load the addresses of the RX and TX lists into the chip.
-	 */
-
-	CSR_WRITE_4(sc, RL_RXLIST_ADDR_HI,
-	    RL_ADDR_HI(sc->rl_ldata.rl_rx_list_addr));
-	CSR_WRITE_4(sc, RL_RXLIST_ADDR_LO,
-	    RL_ADDR_LO(sc->rl_ldata.rl_rx_list_addr));
-
-	CSR_WRITE_4(sc, RL_TXLIST_ADDR_HI,
-	    RL_ADDR_HI(sc->rl_ldata.rl_tx_list_addr));
-	CSR_WRITE_4(sc, RL_TXLIST_ADDR_LO,
-	    RL_ADDR_LO(sc->rl_ldata.rl_tx_list_addr));
-
-	CSR_WRITE_1(sc, RL_EARLY_TX_THRESH, 16);
 
+#ifdef RE_TX_MODERATION
 	/*
 	 * Initialize the timer interrupt register so that
 	 * a timer interrupt will be generated once the timer
@@ -2227,6 +2677,7 @@
 		CSR_WRITE_4(sc, RL_TIMERINT_8169, 0x800);
 	else
 		CSR_WRITE_4(sc, RL_TIMERINT, 0x400);
+#endif
 
 	/*
 	 * For 8169 gigE NICs, set the max allowed RX packet
@@ -2240,11 +2691,13 @@
 
 	mii_mediachg(mii);
 
-	CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX);
+	CSR_WRITE_1(sc, RL_CFG1, CSR_READ_1(sc, RL_CFG1) | RL_CFG1_DRVLOAD);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
+	sc->rl_flags &= ~RL_FLAG_LINK;
+	sc->rl_watchdog_timer = 0;
 	callout_reset(&sc->rl_stat_callout, hz, re_tick, sc);
 }
 
@@ -2252,28 +2705,26 @@
  * Set media options.
  */
 static int
-re_ifmedia_upd(ifp)
-	struct ifnet		*ifp;
+re_ifmedia_upd(struct ifnet *ifp)
 {
 	struct rl_softc		*sc;
 	struct mii_data		*mii;
+	int			error;
 
 	sc = ifp->if_softc;
 	mii = device_get_softc(sc->rl_miibus);
 	RL_LOCK(sc);
-	mii_mediachg(mii);
+	error = mii_mediachg(mii);
 	RL_UNLOCK(sc);
 
-	return (0);
+	return (error);
 }
 
 /*
  * Report current media status.
  */
 static void
-re_ifmedia_sts(ifp, ifmr)
-	struct ifnet		*ifp;
-	struct ifmediareq	*ifmr;
+re_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
 	struct rl_softc		*sc;
 	struct mii_data		*mii;
@@ -2289,10 +2740,7 @@
 }
 
 static int
-re_ioctl(ifp, command, data)
-	struct ifnet		*ifp;
-	u_long			command;
-	caddr_t			data;
+re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
 	struct rl_softc		*sc = ifp->if_softc;
 	struct ifreq		*ifr = (struct ifreq *) data;
@@ -2301,24 +2749,40 @@
 
 	switch (command) {
 	case SIOCSIFMTU:
-		RL_LOCK(sc);
-		if (ifr->ifr_mtu > RL_JUMBO_MTU)
+		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > RL_JUMBO_MTU) {
+			error = EINVAL;
+			break;
+		}
+		if ((sc->rl_flags & RL_FLAG_NOJUMBO) != 0 &&
+		    ifr->ifr_mtu > RL_MAX_FRAMELEN) {
 			error = EINVAL;
-		ifp->if_mtu = ifr->ifr_mtu;
+			break;
+		}
+		RL_LOCK(sc);
+		if (ifp->if_mtu != ifr->ifr_mtu)
+			ifp->if_mtu = ifr->ifr_mtu;
 		RL_UNLOCK(sc);
 		break;
 	case SIOCSIFFLAGS:
 		RL_LOCK(sc);
-		if (ifp->if_flags & IFF_UP)
-			re_init_locked(sc);
-		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-			re_stop(sc);
+		if ((ifp->if_flags & IFF_UP) != 0) {
+			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
+				if (((ifp->if_flags ^ sc->rl_if_flags)
+				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
+					re_set_rxmode(sc);
+			} else
+				re_init_locked(sc);
+		} else {
+			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+				re_stop(sc);
+		}
+		sc->rl_if_flags = ifp->if_flags;
 		RL_UNLOCK(sc);
 		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		RL_LOCK(sc);
-		re_setmulti(sc);
+		re_set_rxmode(sc);
 		RL_UNLOCK(sc);
 		break;
 	case SIOCGIFMEDIA:
@@ -2343,7 +2807,6 @@
 				CSR_WRITE_2(sc, RL_IMR, 0x0000);
 				ifp->if_capenable |= IFCAP_POLLING;
 				RL_UNLOCK(sc);
-				
 			} else {
 				error = ether_poll_deregister(ifp);
 				/* Enable interrupts. */
@@ -2357,13 +2820,9 @@
 		if (mask & IFCAP_HWCSUM) {
 			ifp->if_capenable ^= IFCAP_HWCSUM;
 			if (ifp->if_capenable & IFCAP_TXCSUM)
-				ifp->if_hwassist = RE_CSUM_FEATURES;
+				ifp->if_hwassist |= RE_CSUM_FEATURES;
 			else
-				ifp->if_hwassist = 0;
-			reinit = 1;
-		}
-		if (mask & IFCAP_VLAN_HWTAGGING) {
-			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+				ifp->if_hwassist &= ~RE_CSUM_FEATURES;
 			reinit = 1;
 		}
 		if (reinit && ifp->if_drv_flags & IFF_DRV_RUNNING)
@@ -2379,21 +2838,32 @@
 }
 
 static void
-re_watchdog(ifp)
-	struct ifnet		*ifp;
+re_watchdog(struct rl_softc *sc)
 {
-	struct rl_softc		*sc;
+	struct ifnet		*ifp;
+
+	RL_LOCK_ASSERT(sc);
+
+	if (sc->rl_watchdog_timer == 0 || --sc->rl_watchdog_timer != 0)
+		return;
+
+	ifp = sc->rl_ifp;
+	re_txeof(sc);
+	if (sc->rl_ldata.rl_tx_free == sc->rl_ldata.rl_tx_desc_cnt) {
+		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
+		    "-- recovering\n");
+		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+			taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask);
+		return;
+	}
 
-	sc = ifp->if_softc;
-	RL_LOCK(sc);
 	if_printf(ifp, "watchdog timeout\n");
 	ifp->if_oerrors++;
 
-	re_txeof(sc);
 	re_rxeof(sc);
 	re_init_locked(sc);
-
-	RL_UNLOCK(sc);
+	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+		taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask);
 }
 
 /*
@@ -2401,22 +2871,29 @@
  * RX and TX lists.
  */
 static void
-re_stop(sc)
-	struct rl_softc		*sc;
+re_stop(struct rl_softc *sc)
 {
-	register int		i;
+	int			i;
 	struct ifnet		*ifp;
+	struct rl_txdesc	*txd;
+	struct rl_rxdesc	*rxd;
 
 	RL_LOCK_ASSERT(sc);
 
 	ifp = sc->rl_ifp;
-	ifp->if_timer = 0;
 
+	sc->rl_watchdog_timer = 0;
 	callout_stop(&sc->rl_stat_callout);
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 
-	CSR_WRITE_1(sc, RL_COMMAND, 0x00);
+	if ((sc->rl_flags & RL_FLAG_CMDSTOP) != 0)
+		CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_STOPREQ | RL_CMD_TX_ENB |
+		    RL_CMD_RX_ENB);
+	else
+		CSR_WRITE_1(sc, RL_COMMAND, 0x00);
+	DELAY(1000);
 	CSR_WRITE_2(sc, RL_IMR, 0x0000);
+	CSR_WRITE_2(sc, RL_ISR, 0xFFFF);
 
 	if (sc->rl_head != NULL) {
 		m_freem(sc->rl_head);
@@ -2425,23 +2902,29 @@
 
 	/* Free the TX list buffers. */
 
-	for (i = 0; i < RL_TX_DESC_CNT; i++) {
-		if (sc->rl_ldata.rl_tx_mbuf[i] != NULL) {
-			bus_dmamap_unload(sc->rl_ldata.rl_mtag,
-			    sc->rl_ldata.rl_tx_dmamap[i]);
-			m_freem(sc->rl_ldata.rl_tx_mbuf[i]);
-			sc->rl_ldata.rl_tx_mbuf[i] = NULL;
+	for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++) {
+		txd = &sc->rl_ldata.rl_tx_desc[i];
+		if (txd->tx_m != NULL) {
+			bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
+			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->rl_ldata.rl_tx_mtag,
+			    txd->tx_dmamap);
+			m_freem(txd->tx_m);
+			txd->tx_m = NULL;
 		}
 	}
 
 	/* Free the RX list buffers. */
 
-	for (i = 0; i < RL_RX_DESC_CNT; i++) {
-		if (sc->rl_ldata.rl_rx_mbuf[i] != NULL) {
-			bus_dmamap_unload(sc->rl_ldata.rl_mtag,
-			    sc->rl_ldata.rl_rx_dmamap[i]);
-			m_freem(sc->rl_ldata.rl_rx_mbuf[i]);
-			sc->rl_ldata.rl_rx_mbuf[i] = NULL;
+	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
+		rxd = &sc->rl_ldata.rl_rx_desc[i];
+		if (rxd->rx_m != NULL) {
+			bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
+			    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
+			bus_dmamap_unload(sc->rl_ldata.rl_rx_mtag,
+			    rxd->rx_dmamap);
+			m_freem(rxd->rx_m);
+			rxd->rx_m = NULL;
 		}
 	}
 }
@@ -2452,8 +2935,7 @@
  * resume.
  */
 static int
-re_suspend(dev)
-	device_t		dev;
+re_suspend(device_t dev)
 {
 	struct rl_softc		*sc;
 
@@ -2473,8 +2955,7 @@
  * appropriate.
  */
 static int
-re_resume(dev)
-	device_t		dev;
+re_resume(device_t dev)
 {
 	struct rl_softc		*sc;
 	struct ifnet		*ifp;
@@ -2484,6 +2965,12 @@
 	RL_LOCK(sc);
 
 	ifp = sc->rl_ifp;
+	/* Take controller out of sleep mode. */
+	if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) {
+		if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80)
+			CSR_WRITE_1(sc, RL_GPIO,
+			    CSR_READ_1(sc, RL_GPIO) | 0x01);
+	}
 
 	/* reinitialize interface if necessary */
 	if (ifp->if_flags & IFF_UP)
@@ -2499,9 +2986,8 @@
  * Stop all chip I/O so that the kernel's probe routines don't
  * get confused by errant DMAs when rebooting.
  */
-static void
-re_shutdown(dev)
-	device_t		dev;
+static int
+re_shutdown(device_t dev)
 {
 	struct rl_softc		*sc;
 
@@ -2512,9 +2998,10 @@
 	/*
 	 * Mark interface as down since otherwise we will panic if
 	 * interrupt comes in later on, which can happen in some
-	 * cases. Another option is to call re_detach() instead of
-	 * re_stop(), like ve(4) does.
+	 * cases.
 	 */
 	sc->rl_ifp->if_flags &= ~IFF_UP;
 	RL_UNLOCK(sc);
+
+	return (0);
 }
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-i386 mailing list