Subject: Re: ohare interrupt problem (Re: HEADS UP: merging the newlock2 branch)
To: None <port-macppc@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-macppc
Date: 02/11/2007 15:33:11
I wrote:

> NetBSD-3.1_RC4 (well, I have its bootable CD) kernel
> with the latest re(4) driver (with some modification to
> make it compile on netbsd-3)

Just FYI, here is a patch for NetBSD-3.1:
---

Index: arch/macppc/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/conf/GENERIC,v
retrieving revision 1.194.4.7
diff -u -r1.194.4.7 GENERIC
--- arch/macppc/conf/GENERIC	5 Nov 2005 00:39:47 -0000	1.194.4.7
+++ arch/macppc/conf/GENERIC	11 Feb 2007 03:41:55 -0000
@@ -292,6 +292,8 @@
 nsphyter* at mii? phy ?			# NS83843 PHYs
 pnaphy* at mii? phy ?			# generic HomePNA PHYs
 qsphy*	at mii? phy ?			# Quality Semiconductor QS6612 PHYs
+rgephy*	at mii? phy ?			# Realtek 8169S/8110S internal PHYs
+rlphy*	at mii? phy ?			# Realtek 8139/8201L PHYs
 sqphy*	at mii? phy ?			# Seeq 80220/80221/80223 PHYs
 tlphy*	at mii? phy ?			# ThunderLAN PHYs
 tqphy*	at mii? phy ?			# TDK Semiconductor PHYs
Index: arch/macppc/conf/INSTALL
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/conf/INSTALL,v
retrieving revision 1.87.4.3
diff -u -r1.87.4.3 INSTALL
--- arch/macppc/conf/INSTALL	18 Jun 2005 05:25:51 -0000	1.87.4.3
+++ arch/macppc/conf/INSTALL	11 Feb 2007 03:53:46 -0000
@@ -123,6 +123,8 @@
 nsphy*	at mii? phy ?			# NS83840 PHYs
 nsphyter* at mii? phy ?			# NS83843 PHYs
 qsphy*	at mii? phy ?			# Quality Semiconductor QS6612 PHYs
+rgephy*	at mii? phy ?			# Realtek 8169S/8110S internal PHYs
+rlphy*	at mii? phy ?			# Realtek 8139/8201L PHYs
 sqphy*	at mii? phy ?			# Seeq 80220/80221/80223 PHYs
 tqphy*	at mii? phy ?			# TDK Semiconductor PHYs
 ukphy*	at mii? phy ?			# generic unknown PHYs
Index: dev/cardbus/if_re_cardbus.c
===================================================================
RCS file: /cvsroot/src/sys/dev/cardbus/if_re_cardbus.c,v
retrieving revision 1.5
diff -u -r1.5 if_re_cardbus.c
--- dev/cardbus/if_re_cardbus.c	27 Feb 2005 00:26:59 -0000	1.5
+++ dev/cardbus/if_re_cardbus.c	11 Feb 2007 03:42:00 -0000
@@ -294,7 +294,7 @@
 	    PCI_CAP_PWRMGMT, &pmreg, 0)) {
 		command = cardbus_conf_read(cc, cf, csc->sc_tag,
 		    pmreg + PCI_PMCSR);
-		if (command & RTK_PSTATE_MASK) {
+		if (command & PCI_PMCSR_STATE_MASK) {
 			pcireg_t		iobase, membase, irq;
 
 			/* Save important PCI config data. */
@@ -308,8 +308,8 @@
 			/* Reset the power state. */
 			aprint_normal("%s: chip is in D%d power mode "
 			    "-- setting to D0\n", sc->sc_dev.dv_xname,
-			    command & RTK_PSTATE_MASK);
-			command &= ~RTK_PSTATE_MASK;
+			    command & PCI_PMCSR_STATE_MASK);
+			command &= ~PCI_PMCSR_STATE_MASK;
 			cardbus_conf_write(cc, cf, csc->sc_tag,
 			    pmreg + PCI_PMCSR, command);
 
@@ -402,7 +402,7 @@
 }
 
 void
-re_cardbus_power(struct rtk_softc *sc,	int why)
+re_cardbus_power(struct rtk_softc *sc, int why)
 {
 	struct re_cardbus_softc *csc = (void *) sc;
 
Index: dev/cardbus/if_rtk_cardbus.c
===================================================================
RCS file: /cvsroot/src/sys/dev/cardbus/if_rtk_cardbus.c,v
retrieving revision 1.25
diff -u -r1.25 if_rtk_cardbus.c
--- dev/cardbus/if_rtk_cardbus.c	27 Feb 2005 00:26:59 -0000	1.25
+++ dev/cardbus/if_rtk_cardbus.c	11 Feb 2007 03:42:00 -0000
@@ -171,10 +171,8 @@
 }
 
 int
-rtk_cardbus_match(parent, match, aux)
-	struct device *parent;
-	struct cfdata *match;
-	void *aux;
+rtk_cardbus_match(struct device *parent, struct cfdata *match,
+    void *aux)
 {
 	struct cardbus_attach_args *ca = aux;
 
@@ -186,9 +184,8 @@
 
 
 void
-rtk_cardbus_attach(parent, self, aux)
-	struct device *parent, *self;
-	void *aux;
+rtk_cardbus_attach(struct device *parent, struct device *self,
+    void *aux)
 {
 	struct rtk_cardbus_softc *csc = (struct rtk_cardbus_softc *)self;
 	struct rtk_softc *sc = &csc->sc_rtk;
@@ -266,9 +263,7 @@
 }
 
 int
-rtk_cardbus_detach(self, flags)
-	struct device *self;
-	int flags;
+rtk_cardbus_detach(struct device *self, int flags)
 {
 	struct rtk_cardbus_softc *csc = (void *) self;
 	struct rtk_softc *sc = &csc->sc_rtk;
@@ -316,7 +311,7 @@
 	    PCI_CAP_PWRMGMT, &pmreg, 0)) {
 		command = cardbus_conf_read(cc, cf, csc->sc_tag,
 		    pmreg + PCI_PMCSR);
-		if (command & RTK_PSTATE_MASK) {
+		if (command & PCI_PMCSR_STATE_MASK) {
 			pcireg_t		iobase, membase, irq;
 
 			/* Save important PCI config data. */
@@ -330,8 +325,8 @@
 			/* Reset the power state. */
 			printf("%s: chip is in D%d power mode "
 			    "-- setting to D0\n", sc->sc_dev.dv_xname,
-			    command & RTK_PSTATE_MASK);
-			command &= ~RTK_PSTATE_MASK;
+			    command & PCI_PMCSR_STATE_MASK);
+			command &= ~PCI_PMCSR_STATE_MASK;
 			cardbus_conf_write(cc, cf, csc->sc_tag,
 			    pmreg + PCI_PMCSR, command);
 
Index: dev/ic/rtl8169.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/rtl8169.c,v
retrieving revision 1.14.2.5
diff -u -r1.14.2.5 rtl8169.c
--- dev/ic/rtl8169.c	31 May 2006 21:32:56 -0000	1.14.2.5
+++ dev/ic/rtl8169.c	11 Feb 2007 03:42:01 -0000
@@ -143,17 +143,12 @@
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
 
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcidevs.h>
-
 #include <dev/ic/rtl81x9reg.h>
 #include <dev/ic/rtl81x9var.h>
 
 #include <dev/ic/rtl8169var.h>
 
-
-static int re_encap(struct rtk_softc *, struct mbuf *, int *);
+static inline void re_set_bufaddr(struct re_desc *, bus_addr_t);
 
 static int re_newbuf(struct rtk_softc *, int, struct mbuf *);
 static int re_rx_list_init(struct rtk_softc *);
@@ -184,11 +179,22 @@
 
 static void re_reset(struct rtk_softc *);
 
+static inline void
+re_set_bufaddr(struct re_desc *d, bus_addr_t addr)
+{
+
+	d->re_bufaddr_lo = htole32((uint32_t)addr);
+	if (sizeof(bus_addr_t) == sizeof(uint64_t))
+		d->re_bufaddr_hi = htole32((uint64_t)addr >> 32);
+	else
+		d->re_bufaddr_hi = 0;
+}
+
 static int
 re_gmii_readreg(struct device *self, int phy, int reg)
 {
 	struct rtk_softc	*sc = (void *)self;
-	u_int32_t		rval;
+	uint32_t		rval;
 	int			i;
 
 	if (phy != 7)
@@ -223,7 +229,7 @@
 re_gmii_writereg(struct device *dev, int phy, int reg, int data)
 {
 	struct rtk_softc	*sc = (void *)dev;
-	u_int32_t		rval;
+	uint32_t		rval;
 	int			i;
 
 	CSR_WRITE_4(sc, RTK_PHYAR, (reg << 16) |
@@ -240,18 +246,15 @@
 	if (i == RTK_TIMEOUT) {
 		aprint_error("%s: PHY write reg %x <- %x failed\n",
 		    sc->sc_dev.dv_xname, reg, data);
-		return;
 	}
-
-	return;
 }
 
 static int
 re_miibus_readreg(struct device *dev, int phy, int reg)
 {
 	struct rtk_softc	*sc = (void *)dev;
-	u_int16_t		rval = 0;
-	u_int16_t		re8139_reg = 0;
+	uint16_t		rval = 0;
+	uint16_t		re8139_reg = 0;
 	int			s;
 
 	s = splnet();
@@ -303,6 +306,10 @@
 		return 0;
 	}
 	rval = CSR_READ_2(sc, re8139_reg);
+	if (sc->rtk_type == RTK_8139CPLUS && re8139_reg == RTK_BMCR) {
+		/* 8139C+ has different bit layout. */
+		rval &= ~(BMCR_LOOP | BMCR_ISO);
+	}
 	splx(s);
 	return rval;
 }
@@ -311,7 +318,7 @@
 re_miibus_writereg(struct device *dev, int phy, int reg, int data)
 {
 	struct rtk_softc	*sc = (void *)dev;
-	u_int16_t		re8139_reg = 0;
+	uint16_t		re8139_reg = 0;
 	int			s;
 
 	s = splnet();
@@ -330,6 +337,10 @@
 	switch (reg) {
 	case MII_BMCR:
 		re8139_reg = RTK_BMCR;
+		if (sc->rtk_type == RTK_8139CPLUS) {
+			/* 8139C+ has different bit layout. */
+			data &= ~(BMCR_LOOP | BMCR_ISO);
+		}
 		break;
 	case MII_BMSR:
 		re8139_reg = RTK_BMSR;
@@ -368,13 +379,13 @@
 static void
 re_reset(struct rtk_softc *sc)
 {
-	register int		i;
+	int		i;
 
 	CSR_WRITE_1(sc, RTK_COMMAND, RTK_CMD_RESET);
 
 	for (i = 0; i < RTK_TIMEOUT; i++) {
 		DELAY(10);
-		if (!(CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_RESET))
+		if ((CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_RESET) == 0)
 			break;
 	}
 	if (i == RTK_TIMEOUT)
@@ -386,7 +397,7 @@
 	 * MCFG_METHOD_2, which corresponds to sc->sc_rev == 2.
 	 */
 	if (1) /* XXX check softc flag for 8169s version */
-		CSR_WRITE_1(sc, 0x82, 1);
+		CSR_WRITE_1(sc, RTK_LDPS, 1);
 
 	return;
 }
@@ -417,13 +428,14 @@
 	struct ifnet		*ifp = &sc->ethercom.ec_if;
 	struct mbuf		*m0;
 	struct ether_header	*eh;
-	struct rtk_desc		*cur_rx;
+	struct re_rxsoft	*rxs;
+	struct re_desc		*cur_rx;
 	bus_dmamap_t		dmamap;
-	u_int16_t		status;
-	u_int32_t		rxstat;
+	uint16_t		status;
+	uint32_t		rxstat;
 	int			total_len, i, s, error = 0;
-	u_int8_t		dst[] = { 0x00, 'h', 'e', 'l', 'l', 'o' };
-	u_int8_t		src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' };
+	static const uint8_t	dst[] = { 0x00, 'h', 'e', 'l', 'l', 'o' };
+	static const uint8_t	src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' };
 
 	/* Allocate a single mbuf */
 
@@ -441,7 +453,7 @@
 	 */
 
 	ifp->if_flags |= IFF_PROMISC;
-	sc->rtk_testmode = 1;
+	sc->re_testmode = 1;
 	re_init(ifp);
 	re_stop(ifp, 0);
 	DELAY(100000);
@@ -450,8 +462,8 @@
 	/* Put some data in the mbuf */
 
 	eh = mtod(m0, struct ether_header *);
-	bcopy((char *)&dst, eh->ether_dhost, ETHER_ADDR_LEN);
-	bcopy((char *)&src, eh->ether_shost, ETHER_ADDR_LEN);
+	memcpy(eh->ether_dhost, (char *)&dst, ETHER_ADDR_LEN);
+	memcpy(eh->ether_shost, (char *)&src, ETHER_ADDR_LEN);
 	eh->ether_type = htons(ETHERTYPE_IP);
 	m0->m_pkthdr.len = m0->m_len = ETHER_MIN_LEN - ETHER_CRC_LEN;
 
@@ -488,22 +500,20 @@
 	 * entry in the RX DMA ring. Grab it from there.
 	 */
 
-	dmamap = sc->rtk_ldata.rtk_rx_list_map;
-	bus_dmamap_sync(sc->sc_dmat,
-	    dmamap, 0, dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
-	dmamap = sc->rtk_ldata.rtk_rx_dmamap[0];
+	rxs = &sc->re_ldata.re_rxsoft[0];
+	dmamap = rxs->rxs_dmamap;
 	bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
-	    BUS_DMASYNC_POSTWRITE);
-	bus_dmamap_unload(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_rx_dmamap[0]);
+	    BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(sc->sc_dmat, dmamap);
 
-	m0 = sc->rtk_ldata.rtk_rx_mbuf[0];
-	sc->rtk_ldata.rtk_rx_mbuf[0] = NULL;
+	m0 = rxs->rxs_mbuf;
+	rxs->rxs_mbuf = NULL;
 	eh = mtod(m0, struct ether_header *);
 
-	cur_rx = &sc->rtk_ldata.rtk_rx_list[0];
-	total_len = RTK_RXBYTES(cur_rx);
-	rxstat = le32toh(cur_rx->rtk_cmdstat);
+	RE_RXDESCSYNC(sc, 0, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+	cur_rx = &sc->re_ldata.re_rx_list[0];
+	rxstat = le32toh(cur_rx->re_cmdstat);
+	total_len = rxstat & sc->re_rxlenmask;
 
 	if (total_len != ETHER_MIN_LEN) {
 		aprint_error("%s: diagnostic failed, received short packet\n",
@@ -514,8 +524,8 @@
 
 	/* Test that the received packet data matches what we sent. */
 
-	if (bcmp((char *)&eh->ether_dhost, (char *)&dst, ETHER_ADDR_LEN) ||
-	    bcmp((char *)&eh->ether_shost, (char *)&src, ETHER_ADDR_LEN) ||
+	if (memcmp((char *)&eh->ether_dhost, (char *)&dst, ETHER_ADDR_LEN) ||
+	    memcmp((char *)&eh->ether_shost, (char *)&src, ETHER_ADDR_LEN) ||
 	    ntohs(eh->ether_type) != ETHERTYPE_IP) {
 		aprint_error("%s: WARNING, DMA FAILURE!\n",
 		    sc->sc_dev.dv_xname);
@@ -536,10 +546,10 @@
 		error = EIO;
 	}
 
-done:
+ done:
 	/* Turn interface off, release resources */
 
-	sc->rtk_testmode = 0;
+	sc->re_testmode = 0;
 	ifp->if_flags &= ~IFF_PROMISC;
 	re_stop(ifp, 0);
 	if (m0 != NULL)
@@ -557,108 +567,99 @@
 re_attach(struct rtk_softc *sc)
 {
 	u_char			eaddr[ETHER_ADDR_LEN];
-	u_int16_t		val;
+	uint16_t		val;
 	struct ifnet		*ifp;
 	int			error = 0, i, addr_len;
 
-
-	/* XXX JRS: bus-attach-independent code begins approximately here */
-
 	/* Reset the adapter. */
 	re_reset(sc);
 
+	if (rtk_read_eeprom(sc, RTK_EE_ID, RTK_EEADDR_LEN1) == 0x8129)
+		addr_len = RTK_EEADDR_LEN1;
+	else
+		addr_len = RTK_EEADDR_LEN0;
+
+	/*
+	 * Get station address from the EEPROM.
+	 */
+	for (i = 0; i < 3; i++) {
+		val = rtk_read_eeprom(sc, RTK_EE_EADDR0 + i, addr_len);
+		eaddr[(i * 2) + 0] = val & 0xff;
+		eaddr[(i * 2) + 1] = val >> 8;
+	}
+
 	if (sc->rtk_type == RTK_8169) {
 		uint32_t hwrev;
 
 		/* Revision of 8169/8169S/8110s in bits 30..26, 23 */
-		hwrev = CSR_READ_4(sc, RTK_TXCFG) & 0x7c800000;
-		if (hwrev == (0x1 << 28)) {
+		hwrev = CSR_READ_4(sc, RTK_TXCFG) & RTK_TXCFG_HWREV;
+		/* These rev numbers are taken from Realtek's driver */
+		if (hwrev == 0x38800000 /* XXX */) {
+			sc->sc_rev = 15;
+		} else if (hwrev == RTK_HWREV_8100E) {
+			sc->sc_rev = 14;
+		} else if (hwrev == RTK_HWREV_8101E) {
+			sc->sc_rev = 13;
+		} else if (hwrev == RTK_HWREV_8168_SPIN2) {
+			sc->sc_rev = 12;
+		} else if (hwrev == RTK_HWREV_8168_SPIN1) {
+			sc->sc_rev = 11;
+		} else if (hwrev == RTK_HWREV_8169_8110SC) {
+			sc->sc_rev = 5;
+		} else if (hwrev == RTK_HWREV_8169_8110SB) {
 			sc->sc_rev = 4;
-		} else if (hwrev == (0x1 << 26)) {
+		} else if (hwrev == RTK_HWREV_8169S) {
 			sc->sc_rev = 3;
-		} else if (hwrev == (0x1 << 23)) {
+		} else if (hwrev == RTK_HWREV_8110S) {
 			sc->sc_rev = 2;
-		} else
+		} else /* RTK_HWREV_8169 */
 			sc->sc_rev = 1;
 
 		/* Set RX length mask */
-
-		sc->rtk_rxlenmask = RTK_RDESC_STAT_GFRAGLEN;
-
-		/* Force station address autoload from the EEPROM */
-
-		CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_AUTOLOAD);
-		for (i = 0; i < RTK_TIMEOUT; i++) {
-			if (!(CSR_READ_1(sc, RTK_EECMD) & RTK_EEMODE_AUTOLOAD))
-				break;
-			DELAY(100);
-		}
-		if (i == RTK_TIMEOUT)
-			aprint_error("%s: eeprom autoload timed out\n",
-			    sc->sc_dev.dv_xname);
-
-		for (i = 0; i < ETHER_ADDR_LEN; i++)
-			eaddr[i] = CSR_READ_1(sc, RTK_IDR0 + i);
-
-		sc->rtk_ldata.rtk_tx_desc_cnt = RTK_TX_DESC_CNT_8169;
+		sc->re_rxlenmask = RE_RDESC_STAT_GFRAGLEN;
+		sc->re_ldata.re_tx_desc_cnt = RE_TX_DESC_CNT_8169;
 	} else {
-
 		/* Set RX length mask */
-
-		sc->rtk_rxlenmask = RTK_RDESC_STAT_FRAGLEN;
-
-		if (rtk_read_eeprom(sc, RTK_EE_ID, RTK_EEADDR_LEN1) == 0x8129)
-			addr_len = RTK_EEADDR_LEN1;
-		else
-			addr_len = RTK_EEADDR_LEN0;
-
-		/*
-		 * Get station address from the EEPROM.
-		 */
-		for (i = 0; i < 3; i++) {
-			val = rtk_read_eeprom(sc, RTK_EE_EADDR0 + i, addr_len);
-			eaddr[(i * 2) + 0] = val & 0xff;
-			eaddr[(i * 2) + 1] = val >> 8;
-		}
-
-		sc->rtk_ldata.rtk_tx_desc_cnt = RTK_TX_DESC_CNT_8139;
+		sc->re_rxlenmask = RE_RDESC_STAT_FRAGLEN;
+		sc->re_ldata.re_tx_desc_cnt = RE_TX_DESC_CNT_8139;
 	}
 
 	aprint_normal("%s: Ethernet address %s\n",
 	    sc->sc_dev.dv_xname, ether_sprintf(eaddr));
 
-	if (sc->rtk_ldata.rtk_tx_desc_cnt >
-	    PAGE_SIZE / sizeof(struct rtk_desc)) {
-		sc->rtk_ldata.rtk_tx_desc_cnt =
-		    PAGE_SIZE / sizeof(struct rtk_desc);
+	if (sc->re_ldata.re_tx_desc_cnt >
+	    PAGE_SIZE / sizeof(struct re_desc)) {
+		sc->re_ldata.re_tx_desc_cnt =
+		    PAGE_SIZE / sizeof(struct re_desc);
 	}
 
 	aprint_verbose("%s: using %d tx descriptors\n",
-	    sc->sc_dev.dv_xname, sc->rtk_ldata.rtk_tx_desc_cnt);
+	    sc->sc_dev.dv_xname, sc->re_ldata.re_tx_desc_cnt);
+	KASSERT(RE_NEXT_TX_DESC(sc, RE_TX_DESC_CNT(sc) - 1) == 0);
 
 	/* Allocate DMA'able memory for the TX ring */
-	if ((error = bus_dmamem_alloc(sc->sc_dmat, RTK_TX_LIST_SZ(sc),
-		    RTK_ETHER_ALIGN, 0, &sc->rtk_ldata.rtk_tx_listseg,
-		    1, &sc->rtk_ldata.rtk_tx_listnseg, BUS_DMA_NOWAIT)) != 0) {
+	if ((error = bus_dmamem_alloc(sc->sc_dmat, RE_TX_LIST_SZ(sc),
+	    RE_RING_ALIGN, 0, &sc->re_ldata.re_tx_listseg, 1,
+	    &sc->re_ldata.re_tx_listnseg, BUS_DMA_NOWAIT)) != 0) {
 		aprint_error("%s: can't allocate tx listseg, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_0;
 	}
 
 	/* Load the map for the TX ring. */
-	if ((error = bus_dmamem_map(sc->sc_dmat, &sc->rtk_ldata.rtk_tx_listseg,
-		    sc->rtk_ldata.rtk_tx_listnseg, RTK_TX_LIST_SZ(sc),
-		    (caddr_t *)&sc->rtk_ldata.rtk_tx_list,
-		    BUS_DMA_NOWAIT)) != 0) {
+	if ((error = bus_dmamem_map(sc->sc_dmat, &sc->re_ldata.re_tx_listseg,
+	    sc->re_ldata.re_tx_listnseg, RE_TX_LIST_SZ(sc),
+	    (caddr_t *)&sc->re_ldata.re_tx_list,
+	    BUS_DMA_COHERENT | BUS_DMA_NOWAIT)) != 0) {
 		aprint_error("%s: can't map tx list, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 	  	goto fail_1;
 	}
-	memset(sc->rtk_ldata.rtk_tx_list, 0, RTK_TX_LIST_SZ(sc));
+	memset(sc->re_ldata.re_tx_list, 0, RE_TX_LIST_SZ(sc));
 
-	if ((error = bus_dmamap_create(sc->sc_dmat, RTK_TX_LIST_SZ(sc), 1,
-		    RTK_TX_LIST_SZ(sc), 0, BUS_DMA_ALLOCNOW,
-		    &sc->rtk_ldata.rtk_tx_list_map)) != 0) {
+	if ((error = bus_dmamap_create(sc->sc_dmat, RE_TX_LIST_SZ(sc), 1,
+	    RE_TX_LIST_SZ(sc), 0, 0,
+	    &sc->re_ldata.re_tx_list_map)) != 0) {
 		aprint_error("%s: can't create tx list map, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_2;
@@ -666,20 +667,19 @@
 
 
 	if ((error = bus_dmamap_load(sc->sc_dmat,
-		    sc->rtk_ldata.rtk_tx_list_map, sc->rtk_ldata.rtk_tx_list,
-		    RTK_TX_LIST_SZ(sc), NULL, BUS_DMA_NOWAIT)) != 0) {
+	    sc->re_ldata.re_tx_list_map, sc->re_ldata.re_tx_list,
+	    RE_TX_LIST_SZ(sc), NULL, BUS_DMA_NOWAIT)) != 0) {
 		aprint_error("%s: can't load tx list, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_3;
 	}
 
 	/* Create DMA maps for TX buffers */
-	for (i = 0; i < RTK_TX_QLEN; i++) {
+	for (i = 0; i < RE_TX_QLEN; i++) {
 		error = bus_dmamap_create(sc->sc_dmat,
 		    round_page(IP_MAXPACKET),
-		    RTK_TX_DESC_CNT(sc) - 4, RTK_TDESC_CMD_FRAGLEN,
-		    0, BUS_DMA_ALLOCNOW,
-		    &sc->rtk_ldata.rtk_txq[i].txq_dmamap);
+		    RE_TX_DESC_CNT(sc) - RE_NTXDESC_RSVD, RE_TDESC_CMD_FRAGLEN,
+		    0, 0, &sc->re_ldata.re_txq[i].txq_dmamap);
 		if (error) {
 			aprint_error("%s: can't create DMA map for TX\n",
 			    sc->sc_dev.dv_xname);
@@ -688,45 +688,46 @@
 	}
 
 	/* Allocate DMA'able memory for the RX ring */
-        if ((error = bus_dmamem_alloc(sc->sc_dmat, RTK_RX_LIST_SZ,
-		    RTK_RING_ALIGN, 0, &sc->rtk_ldata.rtk_rx_listseg, 1,
-		    &sc->rtk_ldata.rtk_rx_listnseg, BUS_DMA_NOWAIT)) != 0) {
+	/* XXX see also a comment about RE_RX_DMAMEM_SZ in rtl81x9var.h */
+	if ((error = bus_dmamem_alloc(sc->sc_dmat,
+	    RE_RX_DMAMEM_SZ, RE_RING_ALIGN, 0, &sc->re_ldata.re_rx_listseg, 1,
+	    &sc->re_ldata.re_rx_listnseg, BUS_DMA_NOWAIT)) != 0) {
 		aprint_error("%s: can't allocate rx listseg, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_4;
 	}
 
 	/* Load the map for the RX ring. */
-	if ((error = bus_dmamem_map(sc->sc_dmat, &sc->rtk_ldata.rtk_rx_listseg,
-		    sc->rtk_ldata.rtk_rx_listnseg, RTK_RX_LIST_SZ,
-		    (caddr_t *)&sc->rtk_ldata.rtk_rx_list,
-		    BUS_DMA_NOWAIT)) != 0) {
+	if ((error = bus_dmamem_map(sc->sc_dmat, &sc->re_ldata.re_rx_listseg,
+	    sc->re_ldata.re_rx_listnseg, RE_RX_DMAMEM_SZ,
+	    (caddr_t *)&sc->re_ldata.re_rx_list,
+	    BUS_DMA_COHERENT | BUS_DMA_NOWAIT)) != 0) {
 		aprint_error("%s: can't map rx list, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_5;
 	}
-	memset(sc->rtk_ldata.rtk_rx_list, 0, RTK_RX_LIST_SZ);
+	memset(sc->re_ldata.re_rx_list, 0, RE_RX_DMAMEM_SZ);
 
-	if ((error = bus_dmamap_create(sc->sc_dmat, RTK_RX_LIST_SZ, 1,
-		    RTK_RX_LIST_SZ, 0, BUS_DMA_ALLOCNOW,
-		    &sc->rtk_ldata.rtk_rx_list_map)) != 0) {
+	if ((error = bus_dmamap_create(sc->sc_dmat,
+	    RE_RX_DMAMEM_SZ, 1, RE_RX_DMAMEM_SZ, 0, 0,
+	    &sc->re_ldata.re_rx_list_map)) != 0) {
 		aprint_error("%s: can't create rx list map, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_6;
 	}
 
 	if ((error = bus_dmamap_load(sc->sc_dmat,
-		    sc->rtk_ldata.rtk_rx_list_map, sc->rtk_ldata.rtk_rx_list,
-		    RTK_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT)) != 0) {
+	    sc->re_ldata.re_rx_list_map, sc->re_ldata.re_rx_list,
+	    RE_RX_DMAMEM_SZ, NULL, BUS_DMA_NOWAIT)) != 0) {
 		aprint_error("%s: can't load rx list, error = %d\n",
 		    sc->sc_dev.dv_xname, error);
 		goto fail_7;
 	}
 
 	/* Create DMA maps for RX buffers */
-	for (i = 0; i < RTK_RX_DESC_CNT; i++) {
+	for (i = 0; i < RE_RX_DESC_CNT; i++) {
 		error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
-		    0, BUS_DMA_ALLOCNOW, &sc->rtk_ldata.rtk_rx_dmamap[i]);
+		    0, 0, &sc->re_ldata.re_rxsoft[i].rxs_dmamap);
 		if (error) {
 			aprint_error("%s: can't create DMA map for RX\n",
 			    sc->sc_dev.dv_xname);
@@ -745,20 +746,20 @@
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = re_ioctl;
-	sc->ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
-
-	/* 
-	 * This is a way to disable hw VLAN tagging by default
-	 * (RE_VLAN is undefined), as it is problematic. PR 32643
-	 */
-
-#ifdef RE_VLAN
-	sc->ethercom.ec_capabilities |= ETHERCAP_VLAN_HWTAGGING;
-#endif
+	sc->ethercom.ec_capabilities |=
+	    ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING;
 	ifp->if_start = re_start;
 	ifp->if_stop = re_stop;
+
+	/*
+	 * IFCAP_CSUM_IPv4_Tx on re(4) is broken for small packets,
+	 * so we have a workaround to handle the bug by padding
+	 * such packets manually.
+	 */
 	ifp->if_capabilities |=
-	    IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 |
+	    IFCAP_CSUM_IPv4 |
+	    IFCAP_CSUM_TCPv4 |
+	    IFCAP_CSUM_UDPv4 |
 	    IFCAP_TSOv4;
 	ifp->if_watchdog = re_watchdog;
 	ifp->if_init = re_init;
@@ -766,7 +767,7 @@
 		ifp->if_baudrate = 1000000000;
 	else
 		ifp->if_baudrate = 100000000;
-	ifp->if_snd.ifq_maxlen = RTK_IFQ_MAXLEN;
+	ifp->if_snd.ifq_maxlen = RE_IFQ_MAXLEN;
 	ifp->if_capenable = ifp->if_capabilities;
 	IFQ_SET_READY(&ifp->if_snd);
 
@@ -809,42 +810,42 @@
 
 	return;
 
-fail_8:
+ fail_8:
 	/* Destroy DMA maps for RX buffers. */
-	for (i = 0; i < RTK_RX_DESC_CNT; i++)
-		if (sc->rtk_ldata.rtk_rx_dmamap[i] != NULL)
+	for (i = 0; i < RE_RX_DESC_CNT; i++)
+		if (sc->re_ldata.re_rxsoft[i].rxs_dmamap != NULL)
 			bus_dmamap_destroy(sc->sc_dmat,
-			    sc->rtk_ldata.rtk_rx_dmamap[i]);
+			    sc->re_ldata.re_rxsoft[i].rxs_dmamap);
 
 	/* Free DMA'able memory for the RX ring. */
-	bus_dmamap_unload(sc->sc_dmat, sc->rtk_ldata.rtk_rx_list_map);
-fail_7:
-	bus_dmamap_destroy(sc->sc_dmat, sc->rtk_ldata.rtk_rx_list_map);
-fail_6:
+	bus_dmamap_unload(sc->sc_dmat, sc->re_ldata.re_rx_list_map);
+ fail_7:
+	bus_dmamap_destroy(sc->sc_dmat, sc->re_ldata.re_rx_list_map);
+ fail_6:
 	bus_dmamem_unmap(sc->sc_dmat,
-	    (caddr_t)sc->rtk_ldata.rtk_rx_list, RTK_RX_LIST_SZ);
-fail_5:
+	    (caddr_t)sc->re_ldata.re_rx_list, RE_RX_DMAMEM_SZ);
+ fail_5:
 	bus_dmamem_free(sc->sc_dmat,
-	    &sc->rtk_ldata.rtk_rx_listseg, sc->rtk_ldata.rtk_rx_listnseg);
+	    &sc->re_ldata.re_rx_listseg, sc->re_ldata.re_rx_listnseg);
 
-fail_4:
+ fail_4:
 	/* Destroy DMA maps for TX buffers. */
-	for (i = 0; i < RTK_TX_QLEN; i++)
-		if (sc->rtk_ldata.rtk_txq[i].txq_dmamap != NULL)
+	for (i = 0; i < RE_TX_QLEN; i++)
+		if (sc->re_ldata.re_txq[i].txq_dmamap != NULL)
 			bus_dmamap_destroy(sc->sc_dmat,
-			    sc->rtk_ldata.rtk_txq[i].txq_dmamap);
+			    sc->re_ldata.re_txq[i].txq_dmamap);
 
 	/* Free DMA'able memory for the TX ring. */
-	bus_dmamap_unload(sc->sc_dmat, sc->rtk_ldata.rtk_tx_list_map);
-fail_3:
-	bus_dmamap_destroy(sc->sc_dmat, sc->rtk_ldata.rtk_tx_list_map);
-fail_2:
+	bus_dmamap_unload(sc->sc_dmat, sc->re_ldata.re_tx_list_map);
+ fail_3:
+	bus_dmamap_destroy(sc->sc_dmat, sc->re_ldata.re_tx_list_map);
+ fail_2:
 	bus_dmamem_unmap(sc->sc_dmat,
-	    (caddr_t)sc->rtk_ldata.rtk_tx_list, RTK_TX_LIST_SZ(sc));
-fail_1:
+	    (caddr_t)sc->re_ldata.re_tx_list, RE_TX_LIST_SZ(sc));
+ fail_1:
 	bus_dmamem_free(sc->sc_dmat,
-	    &sc->rtk_ldata.rtk_tx_listseg, sc->rtk_ldata.rtk_tx_listnseg);
-fail_0:
+	    &sc->re_ldata.re_tx_listseg, sc->re_ldata.re_tx_listnseg);
+ fail_0:
 	return;
 }
 
@@ -856,7 +857,7 @@
 int
 re_activate(struct device *self, enum devact act)
 {
-	struct rtk_softc *sc = (void *) self;
+	struct rtk_softc *sc = (void *)self;
 	int s, error = 0;
 
 	s = splnet();
@@ -902,35 +903,33 @@
 	ether_ifdetach(ifp);
 	if_detach(ifp);
 
-	/* XXX undo re_allocmem() */
-
 	/* Destroy DMA maps for RX buffers. */
-	for (i = 0; i < RTK_RX_DESC_CNT; i++)
-		if (sc->rtk_ldata.rtk_rx_dmamap[i] != NULL)
+	for (i = 0; i < RE_RX_DESC_CNT; i++)
+		if (sc->re_ldata.re_rxsoft[i].rxs_dmamap != NULL)
 			bus_dmamap_destroy(sc->sc_dmat,
-			    sc->rtk_ldata.rtk_rx_dmamap[i]);
+			    sc->re_ldata.re_rxsoft[i].rxs_dmamap);
 
 	/* Free DMA'able memory for the RX ring. */
-	bus_dmamap_unload(sc->sc_dmat, sc->rtk_ldata.rtk_rx_list_map);
-	bus_dmamap_destroy(sc->sc_dmat, sc->rtk_ldata.rtk_rx_list_map);
+	bus_dmamap_unload(sc->sc_dmat, sc->re_ldata.re_rx_list_map);
+	bus_dmamap_destroy(sc->sc_dmat, sc->re_ldata.re_rx_list_map);
 	bus_dmamem_unmap(sc->sc_dmat,
-	    (caddr_t)sc->rtk_ldata.rtk_rx_list, RTK_RX_LIST_SZ);
+	    (caddr_t)sc->re_ldata.re_rx_list, RE_RX_DMAMEM_SZ);
 	bus_dmamem_free(sc->sc_dmat,
-	    &sc->rtk_ldata.rtk_rx_listseg, sc->rtk_ldata.rtk_rx_listnseg);
+	    &sc->re_ldata.re_rx_listseg, sc->re_ldata.re_rx_listnseg);
 
 	/* Destroy DMA maps for TX buffers. */
-	for (i = 0; i < RTK_TX_QLEN; i++)
-		if (sc->rtk_ldata.rtk_txq[i].txq_dmamap != NULL)
+	for (i = 0; i < RE_TX_QLEN; i++)
+		if (sc->re_ldata.re_txq[i].txq_dmamap != NULL)
 			bus_dmamap_destroy(sc->sc_dmat,
-			    sc->rtk_ldata.rtk_txq[i].txq_dmamap);
+			    sc->re_ldata.re_txq[i].txq_dmamap);
 
 	/* Free DMA'able memory for the TX ring. */
-	bus_dmamap_unload(sc->sc_dmat, sc->rtk_ldata.rtk_tx_list_map);
-	bus_dmamap_destroy(sc->sc_dmat, sc->rtk_ldata.rtk_tx_list_map);
+	bus_dmamap_unload(sc->sc_dmat, sc->re_ldata.re_tx_list_map);
+	bus_dmamap_destroy(sc->sc_dmat, sc->re_ldata.re_tx_list_map);
 	bus_dmamem_unmap(sc->sc_dmat,
-	    (caddr_t)sc->rtk_ldata.rtk_tx_list, RTK_TX_LIST_SZ(sc));
+	    (caddr_t)sc->re_ldata.re_tx_list, RE_TX_LIST_SZ(sc));
 	bus_dmamem_free(sc->sc_dmat,
-	    &sc->rtk_ldata.rtk_tx_listseg, sc->rtk_ldata.rtk_tx_listnseg);
+	    &sc->re_ldata.re_tx_listseg, sc->re_ldata.re_tx_listnseg);
 
 
 	shutdownhook_disestablish(sc->sc_sdhook);
@@ -946,6 +945,7 @@
 static int
 re_enable(struct rtk_softc *sc)
 {
+
 	if (RTK_IS_ENABLED(sc) == 0 && sc->sc_enable != NULL) {
 		if ((*sc->sc_enable)(sc) != 0) {
 			aprint_error("%s: device enable failed\n",
@@ -978,7 +978,7 @@
 void
 re_power(int why, void *arg)
 {
-	struct rtk_softc *sc = (void *) arg;
+	struct rtk_softc *sc = (void *)arg;
 	struct ifnet *ifp = &sc->ethercom.ec_if;
 	int s;
 
@@ -1011,21 +1011,22 @@
 {
 	struct mbuf		*n = NULL;
 	bus_dmamap_t		map;
-	struct rtk_desc		*d;
-	u_int32_t		cmdstat;
+	struct re_desc		*d;
+	struct re_rxsoft	*rxs;
+	uint32_t		cmdstat;
 	int			error;
 
 	if (m == NULL) {
 		MGETHDR(n, M_DONTWAIT, MT_DATA);
 		if (n == NULL)
 			return ENOBUFS;
-		m = n;
 
-		MCLGET(m, M_DONTWAIT);
-		if (!(m->m_flags & M_EXT)) {
-			m_freem(m);
+		MCLGET(n, M_DONTWAIT);
+		if ((n->m_flags & M_EXT) == 0) {
+			m_freem(n);
 			return ENOBUFS;
 		}
+		m = n;
 	} else
 		m->m_data = m->m_ext.ext_buf;
 
@@ -1034,37 +1035,46 @@
 	 * alignment so that the frame payload is
 	 * longword aligned.
 	 */
-	m->m_len = m->m_pkthdr.len = MCLBYTES;
-	m_adj(m, RTK_ETHER_ALIGN);
+	m->m_len = m->m_pkthdr.len = MCLBYTES - RE_ETHER_ALIGN;
+	m->m_data += RE_ETHER_ALIGN;
 
-	map = sc->rtk_ldata.rtk_rx_dmamap[idx];
+	rxs = &sc->re_ldata.re_rxsoft[idx];
+	map = rxs->rxs_dmamap;
 	error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
 	    BUS_DMA_READ|BUS_DMA_NOWAIT);
 
 	if (error)
 		goto out;
 
-	d = &sc->rtk_ldata.rtk_rx_list[idx];
-	if (le32toh(d->rtk_cmdstat) & RTK_RDESC_STAT_OWN)
-		goto out;
+	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+	    BUS_DMASYNC_PREREAD);
 
-	cmdstat = map->dm_segs[0].ds_len;
-	d->rtk_bufaddr_lo = htole32(RTK_ADDR_LO(map->dm_segs[0].ds_addr));
-	d->rtk_bufaddr_hi = htole32(RTK_ADDR_HI(map->dm_segs[0].ds_addr));
-	if (idx == (RTK_RX_DESC_CNT - 1))
-		cmdstat |= RTK_RDESC_CMD_EOR;
-	d->rtk_cmdstat = htole32(cmdstat);
-
-	sc->rtk_ldata.rtk_rx_list[idx].rtk_cmdstat |=
-	    htole32(RTK_RDESC_CMD_OWN);
-	sc->rtk_ldata.rtk_rx_mbuf[idx] = m;
+	d = &sc->re_ldata.re_rx_list[idx];
+#ifdef DIAGNOSTIC
+	RE_RXDESCSYNC(sc, idx, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+	cmdstat = le32toh(d->re_cmdstat);
+	RE_RXDESCSYNC(sc, idx, BUS_DMASYNC_PREREAD);
+	if (cmdstat & RE_RDESC_STAT_OWN) {
+		panic("%s: tried to map busy RX descriptor",
+		    sc->sc_dev.dv_xname);
+	}
+#endif
 
-	bus_dmamap_sync(sc->sc_dmat, sc->rtk_ldata.rtk_rx_dmamap[idx], 0,
-	    sc->rtk_ldata.rtk_rx_dmamap[idx]->dm_mapsize,
-	    BUS_DMASYNC_PREREAD);
+	rxs->rxs_mbuf = m;
+
+	d->re_vlanctl = 0;
+	cmdstat = map->dm_segs[0].ds_len;
+	if (idx == (RE_RX_DESC_CNT - 1))
+		cmdstat |= RE_RDESC_CMD_EOR;
+	re_set_bufaddr(d, map->dm_segs[0].ds_addr);
+	d->re_cmdstat = htole32(cmdstat);
+	RE_RXDESCSYNC(sc, idx, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+	cmdstat |= RE_RDESC_CMD_OWN;
+	d->re_cmdstat = htole32(cmdstat);
+	RE_RXDESCSYNC(sc, idx, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 
 	return 0;
-out:
+ out:
 	if (n != NULL)
 		m_freem(n);
 	return ENOMEM;
@@ -1075,18 +1085,20 @@
 {
 	int i;
 
-	memset(sc->rtk_ldata.rtk_tx_list, 0, RTK_TX_LIST_SZ(sc));
-	for (i = 0; i < RTK_TX_QLEN; i++) {
-		sc->rtk_ldata.rtk_txq[i].txq_mbuf = NULL;
+	memset(sc->re_ldata.re_tx_list, 0, RE_TX_LIST_SZ(sc));
+	for (i = 0; i < RE_TX_QLEN; i++) {
+		sc->re_ldata.re_txq[i].txq_mbuf = NULL;
 	}
 
 	bus_dmamap_sync(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_tx_list_map, 0,
-	    sc->rtk_ldata.rtk_tx_list_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
-	sc->rtk_ldata.rtk_txq_prodidx = 0;
-	sc->rtk_ldata.rtk_txq_considx = 0;
-	sc->rtk_ldata.rtk_tx_free = RTK_TX_DESC_CNT(sc);
-	sc->rtk_ldata.rtk_tx_nextfree = 0;
+	    sc->re_ldata.re_tx_list_map, 0,
+	    sc->re_ldata.re_tx_list_map->dm_mapsize,
+	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+	sc->re_ldata.re_txq_prodidx = 0;
+	sc->re_ldata.re_txq_considx = 0;
+	sc->re_ldata.re_txq_free = RE_TX_QLEN;
+	sc->re_ldata.re_tx_free = RE_TX_DESC_CNT(sc);
+	sc->re_ldata.re_tx_nextfree = 0;
 
 	return 0;
 }
@@ -1096,24 +1108,15 @@
 {
 	int			i;
 
-	memset((char *)sc->rtk_ldata.rtk_rx_list, 0, RTK_RX_LIST_SZ);
-	memset((char *)&sc->rtk_ldata.rtk_rx_mbuf, 0,
-	    (RTK_RX_DESC_CNT * sizeof(struct mbuf *)));
+	memset((char *)sc->re_ldata.re_rx_list, 0, RE_RX_LIST_SZ);
 
-	for (i = 0; i < RTK_RX_DESC_CNT; i++) {
+	for (i = 0; i < RE_RX_DESC_CNT; i++) {
 		if (re_newbuf(sc, i, NULL) == ENOBUFS)
 			return ENOBUFS;
 	}
 
-	/* Flush the RX descriptors */
-
-	bus_dmamap_sync(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_rx_list_map,
-	    0, sc->rtk_ldata.rtk_rx_list_map->dm_mapsize,
-	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-	sc->rtk_ldata.rtk_rx_prodidx = 0;
-	sc->rtk_head = sc->rtk_tail = NULL;
+	sc->re_ldata.re_rx_prodidx = 0;
+	sc->re_head = sc->re_tail = NULL;
 
 	return 0;
 }
@@ -1129,47 +1132,43 @@
 	struct mbuf		*m;
 	struct ifnet		*ifp;
 	int			i, total_len;
-	struct rtk_desc		*cur_rx;
-	u_int32_t		rxstat, rxvlan;
+	struct re_desc		*cur_rx;
+	struct re_rxsoft	*rxs;
+	uint32_t		rxstat, rxvlan;
 
 	ifp = &sc->ethercom.ec_if;
-	i = sc->rtk_ldata.rtk_rx_prodidx;
-
-	/* Invalidate the descriptor memory */
-
-	bus_dmamap_sync(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_rx_list_map,
-	    0, sc->rtk_ldata.rtk_rx_list_map->dm_mapsize,
-	    BUS_DMASYNC_POSTREAD);
-
-	while (!RTK_OWN(&sc->rtk_ldata.rtk_rx_list[i])) {
 
-		cur_rx = &sc->rtk_ldata.rtk_rx_list[i];
-		m = sc->rtk_ldata.rtk_rx_mbuf[i];
-		total_len = RTK_RXBYTES(cur_rx);
-		rxstat = le32toh(cur_rx->rtk_cmdstat);
-		rxvlan = le32toh(cur_rx->rtk_vlanctl);
+	for (i = sc->re_ldata.re_rx_prodidx;; i = RE_NEXT_RX_DESC(sc, i)) {
+		cur_rx = &sc->re_ldata.re_rx_list[i];
+		RE_RXDESCSYNC(sc, i,
+		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+		rxstat = le32toh(cur_rx->re_cmdstat);
+		RE_RXDESCSYNC(sc, i, BUS_DMASYNC_PREREAD);
+		if ((rxstat & RE_RDESC_STAT_OWN) != 0) {
+			break;
+		}
+		total_len = rxstat & sc->re_rxlenmask;
+		rxvlan = le32toh(cur_rx->re_vlanctl);
+		rxs = &sc->re_ldata.re_rxsoft[i];
+		m = rxs->rxs_mbuf;
 
 		/* Invalidate the RX mbuf and unload its map */
 
 		bus_dmamap_sync(sc->sc_dmat,
-		    sc->rtk_ldata.rtk_rx_dmamap[i],
-		    0, sc->rtk_ldata.rtk_rx_dmamap[i]->dm_mapsize,
-		    BUS_DMASYNC_POSTWRITE);
-		bus_dmamap_unload(sc->sc_dmat,
-		    sc->rtk_ldata.rtk_rx_dmamap[i]);
-
-		if (!(rxstat & RTK_RDESC_STAT_EOF)) {
-			m->m_len = MCLBYTES - RTK_ETHER_ALIGN;
-			if (sc->rtk_head == NULL)
-				sc->rtk_head = sc->rtk_tail = m;
+		    rxs->rxs_dmamap, 0, rxs->rxs_dmamap->dm_mapsize,
+		    BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
+
+		if ((rxstat & RE_RDESC_STAT_EOF) == 0) {
+			m->m_len = MCLBYTES - RE_ETHER_ALIGN;
+			if (sc->re_head == NULL)
+				sc->re_head = sc->re_tail = m;
 			else {
 				m->m_flags &= ~M_PKTHDR;
-				sc->rtk_tail->m_next = m;
-				sc->rtk_tail = m;
+				sc->re_tail->m_next = m;
+				sc->re_tail = m;
 			}
 			re_newbuf(sc, i, NULL);
-			RTK_RX_DESC_INC(sc, i);
 			continue;
 		}
 
@@ -1192,18 +1191,34 @@
 		if (sc->rtk_type == RTK_8169)
 			rxstat >>= 1;
 
-		if (rxstat & RTK_RDESC_STAT_RXERRSUM) {
+		if (__predict_false((rxstat & RE_RDESC_STAT_RXERRSUM) != 0)) {
+#ifdef RE_DEBUG
+			aprint_error("%s: RX error (rxstat = 0x%08x)",
+			    sc->sc_dev.dv_xname, rxstat);
+			if (rxstat & RE_RDESC_STAT_FRALIGN)
+				aprint_error(", frame alignment error");
+			if (rxstat & RE_RDESC_STAT_BUFOFLOW)
+				aprint_error(", out of buffer space");
+			if (rxstat & RE_RDESC_STAT_FIFOOFLOW)
+				aprint_error(", FIFO overrun");
+			if (rxstat & RE_RDESC_STAT_GIANT)
+				aprint_error(", giant packet");
+			if (rxstat & RE_RDESC_STAT_RUNT)
+				aprint_error(", runt packet");
+			if (rxstat & RE_RDESC_STAT_CRCERR)
+				aprint_error(", CRC error");
+			aprint_error("\n");
+#endif
 			ifp->if_ierrors++;
 			/*
 			 * If this is part of a multi-fragment packet,
 			 * discard all the pieces.
 			 */
-			if (sc->rtk_head != NULL) {
-				m_freem(sc->rtk_head);
-				sc->rtk_head = sc->rtk_tail = NULL;
+			if (sc->re_head != NULL) {
+				m_freem(sc->re_head);
+				sc->re_head = sc->re_tail = NULL;
 			}
 			re_newbuf(sc, i, m);
-			RTK_RX_DESC_INC(sc, i);
 			continue;
 		}
 
@@ -1212,21 +1227,18 @@
 		 * reload the current one.
 		 */
 
-		if (re_newbuf(sc, i, NULL)) {
+		if (__predict_false(re_newbuf(sc, i, NULL) != 0)) {
 			ifp->if_ierrors++;
-			if (sc->rtk_head != NULL) {
-				m_freem(sc->rtk_head);
-				sc->rtk_head = sc->rtk_tail = NULL;
+			if (sc->re_head != NULL) {
+				m_freem(sc->re_head);
+				sc->re_head = sc->re_tail = NULL;
 			}
 			re_newbuf(sc, i, m);
-			RTK_RX_DESC_INC(sc, i);
 			continue;
 		}
 
-		RTK_RX_DESC_INC(sc, i);
-
-		if (sc->rtk_head != NULL) {
-			m->m_len = total_len % (MCLBYTES - RTK_ETHER_ALIGN);
+		if (sc->re_head != NULL) {
+			m->m_len = total_len % (MCLBYTES - RE_ETHER_ALIGN);
 			/*
 			 * Special case: if there's 4 bytes or less
 			 * in this buffer, the mbuf can be discarded:
@@ -1234,16 +1246,16 @@
 			 * care about anyway.
 			 */
 			if (m->m_len <= ETHER_CRC_LEN) {
-				sc->rtk_tail->m_len -=
+				sc->re_tail->m_len -=
 				    (ETHER_CRC_LEN - m->m_len);
 				m_freem(m);
 			} else {
 				m->m_len -= ETHER_CRC_LEN;
 				m->m_flags &= ~M_PKTHDR;
-				sc->rtk_tail->m_next = m;
+				sc->re_tail->m_next = m;
 			}
-			m = sc->rtk_head;
-			sc->rtk_head = sc->rtk_tail = NULL;
+			m = sc->re_head;
+			sc->re_head = sc->re_tail = NULL;
 			m->m_pkthdr.len = total_len - ETHER_CRC_LEN;
 		} else
 			m->m_pkthdr.len = m->m_len =
@@ -1252,38 +1264,31 @@
 		ifp->if_ipackets++;
 		m->m_pkthdr.rcvif = ifp;
 
-		/* Do RX checksumming if enabled */
+		/* Do RX checksumming */
 
-		if (ifp->if_capenable & IFCAP_CSUM_IPv4) {
-
-			/* Check IP header checksum */
-			if (rxstat & RTK_RDESC_STAT_PROTOID)
-				m->m_pkthdr.csum_flags |= M_CSUM_IPv4;;
-			if (rxstat & RTK_RDESC_STAT_IPSUMBAD)
+		/* Check IP header checksum */
+		if (rxstat & RE_RDESC_STAT_PROTOID) {
+			m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
+			if (rxstat & RE_RDESC_STAT_IPSUMBAD)
 				m->m_pkthdr.csum_flags |= M_CSUM_IPv4_BAD;
 		}
 
 		/* Check TCP/UDP checksum */
-		if (RTK_TCPPKT(rxstat) &&
-		    (ifp->if_capenable & IFCAP_CSUM_TCPv4)) {
+		if (RE_TCPPKT(rxstat)) {
 			m->m_pkthdr.csum_flags |= M_CSUM_TCPv4;
-			if (rxstat & RTK_RDESC_STAT_TCPSUMBAD)
+			if (rxstat & RE_RDESC_STAT_TCPSUMBAD)
 				m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
-		}
-		if (RTK_UDPPKT(rxstat) &&
-		    (ifp->if_capenable & IFCAP_CSUM_UDPv4)) {
+		} else if (RE_UDPPKT(rxstat)) {
 			m->m_pkthdr.csum_flags |= M_CSUM_UDPv4;
-			if (rxstat & RTK_RDESC_STAT_UDPSUMBAD)
+			if (rxstat & RE_RDESC_STAT_UDPSUMBAD)
 				m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
 		}
 
-#ifdef RE_VLAN
-		if (rxvlan & RTK_RDESC_VLANCTL_TAG) {
+		if (rxvlan & RE_RDESC_VLANCTL_TAG) {
 			VLAN_INPUT_TAG(ifp, m,
-			     be16toh(rxvlan & RTK_RDESC_VLANCTL_DATA),
+			     bswap16(rxvlan & RE_RDESC_VLANCTL_DATA),
 			     continue);
 		}
-#endif
 #if NBPFILTER > 0
 		if (ifp->if_bpf)
 			bpf_mtap(ifp->if_bpf, m);
@@ -1291,74 +1296,56 @@
 		(*ifp->if_input)(ifp, m);
 	}
 
-	/* Flush the RX DMA ring */
-
-	bus_dmamap_sync(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_rx_list_map,
-	    0, sc->rtk_ldata.rtk_rx_list_map->dm_mapsize,
-	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-	sc->rtk_ldata.rtk_rx_prodidx = i;
-
-	return;
+	sc->re_ldata.re_rx_prodidx = i;
 }
 
 static void
 re_txeof(struct rtk_softc *sc)
 {
 	struct ifnet		*ifp;
-	int			idx;
+	struct re_txq		*txq;
+	uint32_t		txstat;
+	int			idx, descidx;
 
 	ifp = &sc->ethercom.ec_if;
-	idx = sc->rtk_ldata.rtk_txq_considx;
-
-	/* Invalidate the TX descriptor list */
 
-	bus_dmamap_sync(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_tx_list_map,
-	    0, sc->rtk_ldata.rtk_tx_list_map->dm_mapsize,
-	    BUS_DMASYNC_POSTREAD);
-
-	while (/* CONSTCOND */ 1) {
-		struct rtk_txq *txq = &sc->rtk_ldata.rtk_txq[idx];
-		int descidx;
-		u_int32_t txstat;
-
-		if (txq->txq_mbuf == NULL) {
-			KASSERT(idx == sc->rtk_ldata.rtk_txq_prodidx);
-			break;
-		}
+	for (idx = sc->re_ldata.re_txq_considx;
+	    sc->re_ldata.re_txq_free < RE_TX_QLEN;
+	    idx = RE_NEXT_TXQ(sc, idx), sc->re_ldata.re_txq_free++) {
+		txq = &sc->re_ldata.re_txq[idx];
+		KASSERT(txq->txq_mbuf != NULL);
 
 		descidx = txq->txq_descidx;
+		RE_TXDESCSYNC(sc, descidx,
+		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 		txstat =
-		    le32toh(sc->rtk_ldata.rtk_tx_list[descidx].rtk_cmdstat);
-		KASSERT((txstat & RTK_TDESC_CMD_EOF) != 0);
-		if (txstat & RTK_TDESC_CMD_OWN)
+		    le32toh(sc->re_ldata.re_tx_list[descidx].re_cmdstat);
+		RE_TXDESCSYNC(sc, descidx, BUS_DMASYNC_PREREAD);
+		KASSERT((txstat & RE_TDESC_CMD_EOF) != 0);
+		if (txstat & RE_TDESC_CMD_OWN) {
 			break;
+		}
 
-		sc->rtk_ldata.rtk_tx_free += txq->txq_dmamap->dm_nsegs;
-		KASSERT(sc->rtk_ldata.rtk_tx_free <= RTK_TX_DESC_CNT(sc));
+		sc->re_ldata.re_tx_free += txq->txq_nsegs;
+		KASSERT(sc->re_ldata.re_tx_free <= RE_TX_DESC_CNT(sc));
+		bus_dmamap_sync(sc->sc_dmat, txq->txq_dmamap,
+		    0, txq->txq_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
 		bus_dmamap_unload(sc->sc_dmat, txq->txq_dmamap);
 		m_freem(txq->txq_mbuf);
 		txq->txq_mbuf = NULL;
 
-		if (txstat & (RTK_TDESC_STAT_EXCESSCOL | RTK_TDESC_STAT_COLCNT))
+		if (txstat & (RE_TDESC_STAT_EXCESSCOL | RE_TDESC_STAT_COLCNT))
 			ifp->if_collisions++;
-		if (txstat & RTK_TDESC_STAT_TXERRSUM)
+		if (txstat & RE_TDESC_STAT_TXERRSUM)
 			ifp->if_oerrors++;
 		else
 			ifp->if_opackets++;
-
-		idx = (idx + 1) % RTK_TX_QLEN;
 	}
 
-	/* No changes made to the TX ring, so no flush needed */
+	sc->re_ldata.re_txq_considx = idx;
 
-	if (idx != sc->rtk_ldata.rtk_txq_considx) {
-		sc->rtk_ldata.rtk_txq_considx = idx;
+	if (sc->re_ldata.re_txq_free > RE_NTXDESC_RSVD)
 		ifp->if_flags &= ~IFF_OACTIVE;
-		ifp->if_timer = 0;
-	}
 
 	/*
 	 * If not all descriptors have been released reaped yet,
@@ -1366,10 +1353,10 @@
 	 * interrupt that will cause us to re-enter this routine.
 	 * This is done in case the transmitter has gone idle.
 	 */
-	if (sc->rtk_ldata.rtk_tx_free != RTK_TX_DESC_CNT(sc))
+	if (sc->re_ldata.re_txq_free < RE_TX_QLEN)
 		CSR_WRITE_4(sc, RTK_TIMERCNT, 1);
-
-	return;
+	else
+		ifp->if_timer = 0;
 }
 
 /*
@@ -1380,7 +1367,7 @@
 re_shutdown(void *vsc)
 
 {
-	struct rtk_softc	*sc = (struct rtk_softc *)vsc;
+	struct rtk_softc	*sc = vsc;
 
 	re_stop(&sc->ethercom.ec_if, 0);
 }
@@ -1408,7 +1395,7 @@
 	struct rtk_softc *sc = ifp->if_softc;
 
 	RTK_LOCK(sc);
-	if (!(ifp->if_capenable & IFCAP_POLLING)) {
+	if ((ifp->if_capenable & IFCAP_POLLING) == 0) {
 		ether_poll_deregister(ifp);
 		cmd = POLL_DEREGISTER;
 	}
@@ -1421,11 +1408,11 @@
 	re_rxeof(sc);
 	re_txeof(sc);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
 		(*ifp->if_start)(ifp);
 
 	if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
-		u_int16_t       status;
+		uint16_t       status;
 
 		status = CSR_READ_2(sc, RTK_ISR);
 		if (status == 0xffff)
@@ -1438,11 +1425,10 @@
 		 */
 
 		if (status & RTK_ISR_SYSTEM_ERR) {
-			re_reset(sc);
 			re_init(sc);
 		}
 	}
-done:
+ done:
 	RTK_UNLOCK(sc);
 }
 #endif /* DEVICE_POLLING */
@@ -1452,12 +1438,12 @@
 {
 	struct rtk_softc	*sc = arg;
 	struct ifnet		*ifp;
-	u_int16_t		status;
+	uint16_t		status;
 	int			handled = 0;
 
 	ifp = &sc->ethercom.ec_if;
 
-	if (!(ifp->if_flags & IFF_UP))
+	if ((ifp->if_flags & IFF_UP) == 0)
 		return 0;
 
 #ifdef DEVICE_POLLING
@@ -1485,17 +1471,14 @@
 		if ((status & RTK_INTRS_CPLUS) == 0)
 			break;
 
-		if ((status & RTK_ISR_RX_OK) ||
-		    (status & RTK_ISR_RX_ERR))
+		if (status & (RTK_ISR_RX_OK | RTK_ISR_RX_ERR))
 			re_rxeof(sc);
 
-		if ((status & RTK_ISR_TIMEOUT_EXPIRED) ||
-		    (status & RTK_ISR_TX_ERR) ||
-		    (status & RTK_ISR_TX_DESC_UNAVAIL))
+		if (status & (RTK_ISR_TIMEOUT_EXPIRED | RTK_ISR_TX_ERR |
+		    RTK_ISR_TX_DESC_UNAVAIL))
 			re_txeof(sc);
 
 		if (status & RTK_ISR_SYSTEM_ERR) {
-			re_reset(sc);
 			re_init(ifp);
 		}
 
@@ -1505,166 +1488,17 @@
 		}
 	}
 
-	if (ifp->if_flags & IFF_UP) /* kludge for interrupt during re_init() */
-		if (ifp->if_snd.ifq_head != NULL)
-			(*ifp->if_start)(ifp);
+	if (handled && !IFQ_IS_EMPTY(&ifp->if_snd))
+		re_start(ifp);
 
 #ifdef DEVICE_POLLING
-done:
+ done:
 #endif
 
 	return handled;
 }
 
-static int
-re_encap(struct rtk_softc *sc, struct mbuf *m, int *idx)
-{
-	bus_dmamap_t		map;
-	int			error, i, startidx, curidx;
-#ifdef RE_VLAN
-	struct m_tag		*mtag;
-#endif
-	struct rtk_desc		*d;
-	u_int32_t		cmdstat, rtk_flags;
-	struct rtk_txq		*txq;
-
-	if (sc->rtk_ldata.rtk_tx_free <= 4) {
-		return EFBIG;
-	}
-
-	/*
-	 * 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. I'm not sure if this is a requirement or a bug.)
-	 */
-
-	if ((m->m_pkthdr.csum_flags & M_CSUM_TSOv4) != 0) {
-		u_int32_t segsz = m->m_pkthdr.segsz;
-
-		rtk_flags = RTK_TDESC_CMD_LGSEND |
-		    (segsz << RTK_TDESC_CMD_MSSVAL_SHIFT);
-	} else {
-
-		/*
-		 * set RTK_TDESC_CMD_IPCSUM if any checksum offloading
-		 * is requested.  otherwise, RTK_TDESC_CMD_TCPCSUM/
-		 * RTK_TDESC_CMD_UDPCSUM doesn't make effects.
-		 */
 
-		rtk_flags = 0;
-		if ((m->m_pkthdr.csum_flags &
-		    (M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4)) != 0) {
-			rtk_flags |= RTK_TDESC_CMD_IPCSUM;
-			if (m->m_pkthdr.csum_flags & M_CSUM_TCPv4) {
-				rtk_flags |= RTK_TDESC_CMD_TCPCSUM;
-			} else if (m->m_pkthdr.csum_flags & M_CSUM_UDPv4) {
-				rtk_flags |= RTK_TDESC_CMD_UDPCSUM;
-			}
-		}
-	}
-
-	txq = &sc->rtk_ldata.rtk_txq[*idx];
-	map = txq->txq_dmamap;
-	error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
-	    BUS_DMA_WRITE|BUS_DMA_NOWAIT);
-
-	if (error) {
-		/* XXX try to defrag if EFBIG? */
-
-		aprint_error("%s: can't map mbuf (error %d)\n",
-		    sc->sc_dev.dv_xname, error);
-
-		return error;
-	}
-
-	if (map->dm_nsegs > sc->rtk_ldata.rtk_tx_free - 4) {
-		error = EFBIG;
-		goto fail_unload;
-	}
-	/*
-	 * 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.)
-	 */
-	i = 0;
-	curidx = startidx = sc->rtk_ldata.rtk_tx_nextfree;
-	while (1) {
-		d = &sc->rtk_ldata.rtk_tx_list[curidx];
-		if (le32toh(d->rtk_cmdstat) & RTK_TDESC_STAT_OWN) {
-			while (i > 0) {
-				sc->rtk_ldata.rtk_tx_list[
-				    (curidx + RTK_TX_DESC_CNT(sc) - i) %
-				    RTK_TX_DESC_CNT(sc)].rtk_cmdstat = 0;
-				i--;
-			}
-			error = ENOBUFS;
-			goto fail_unload;
-		}
-
-		cmdstat = map->dm_segs[i].ds_len;
-		d->rtk_bufaddr_lo =
-		    htole32(RTK_ADDR_LO(map->dm_segs[i].ds_addr));
-		d->rtk_bufaddr_hi =
-		    htole32(RTK_ADDR_HI(map->dm_segs[i].ds_addr));
-		if (i == 0)
-			cmdstat |= RTK_TDESC_CMD_SOF;
-		else
-			cmdstat |= RTK_TDESC_CMD_OWN;
-		if (curidx == (RTK_TX_DESC_CNT(sc) - 1))
-			cmdstat |= RTK_TDESC_CMD_EOR;
-		d->rtk_cmdstat = htole32(cmdstat | rtk_flags);
-		i++;
-		if (i == map->dm_nsegs)
-			break;
-		RTK_TX_DESC_INC(sc, curidx);
-	}
-
-	d->rtk_cmdstat |= htole32(RTK_TDESC_CMD_EOF);
-
-	txq->txq_mbuf = m;
-	sc->rtk_ldata.rtk_tx_free -= map->dm_nsegs;
-
-	/*
-	 * Set up hardware VLAN tagging. Note: vlan tag info must
-	 * appear in the first descriptor of a multi-descriptor
-	 * transmission attempt.
-	 */
-
-#ifdef RE_VLAN
-	if ((mtag = VLAN_OUTPUT_TAG(&sc->ethercom, m)) != NULL) {
-		sc->rtk_ldata.rtk_tx_list[startidx].rtk_vlanctl =
-		    htole32(htons(VLAN_TAG_VALUE(mtag)) |
-		    RTK_TDESC_VLANCTL_TAG);
-	}
-#endif
-
-	/* Transfer ownership of packet to the chip. */
-
-	sc->rtk_ldata.rtk_tx_list[curidx].rtk_cmdstat |=
-	    htole32(RTK_TDESC_CMD_OWN);
-	if (startidx != curidx)
-		sc->rtk_ldata.rtk_tx_list[startidx].rtk_cmdstat |=
-		    htole32(RTK_TDESC_CMD_OWN);
-
-	txq->txq_descidx = curidx;
-	RTK_TX_DESC_INC(sc, curidx);
-	sc->rtk_ldata.rtk_tx_nextfree = curidx;
-	*idx = (*idx + 1) % RTK_TX_QLEN;
-
-	return 0;
-
-fail_unload:
-	bus_dmamap_unload(sc->sc_dmat, map);
-
-	return error;
-}
 
 /*
  * Main transmit routine for C+ and gigE NICs.
@@ -1674,40 +1508,200 @@
 re_start(struct ifnet *ifp)
 {
 	struct rtk_softc	*sc;
-	int			idx;
+	struct mbuf		*m;
+	bus_dmamap_t		map;
+	struct re_txq		*txq;
+	struct re_desc		*d;
+	struct m_tag		*mtag;
+	uint32_t		cmdstat, re_flags;
+	int			ofree, idx, error, nsegs, seg;
+	int			startdesc, curdesc, lastdesc;
+	boolean_t		pad;
 
 	sc = ifp->if_softc;
+	ofree = sc->re_ldata.re_txq_free;
 
-	idx = sc->rtk_ldata.rtk_txq_prodidx;
-	while (/* CONSTCOND */ 1) {
-		struct mbuf *m;
-		int error;
+	for (idx = sc->re_ldata.re_txq_prodidx;; idx = RE_NEXT_TXQ(sc, idx)) {
 
 		IFQ_POLL(&ifp->if_snd, m);
 		if (m == NULL)
 			break;
 
-		if (sc->rtk_ldata.rtk_txq[idx].txq_mbuf != NULL) {
-			KASSERT(idx == sc->rtk_ldata.rtk_txq_considx);
+		if (sc->re_ldata.re_txq_free == 0 ||
+		    sc->re_ldata.re_tx_free <= RE_NTXDESC_RSVD) {
+			/* no more free slots left */
 			ifp->if_flags |= IFF_OACTIVE;
 			break;
 		}
 
-		error = re_encap(sc, m, &idx);
-		if (error == EFBIG &&
-		    sc->rtk_ldata.rtk_tx_free == RTK_TX_DESC_CNT(sc)) {
+		/*
+		 * 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. I'm not sure if this is a requirement or a bug.)
+		 */
+
+		if ((m->m_pkthdr.csum_flags & M_CSUM_TSOv4) != 0) {
+			uint32_t segsz = m->m_pkthdr.segsz;
+
+			re_flags = RE_TDESC_CMD_LGSEND |
+			    (segsz << RE_TDESC_CMD_MSSVAL_SHIFT);
+		} else {
+			/*
+			 * set RE_TDESC_CMD_IPCSUM if any checksum offloading
+			 * is requested.  otherwise, RE_TDESC_CMD_TCPCSUM/
+			 * RE_TDESC_CMD_UDPCSUM doesn't make effects.
+			 */
+			re_flags = 0;
+			if ((m->m_pkthdr.csum_flags &
+			    (M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4))
+			    != 0) {
+				re_flags |= RE_TDESC_CMD_IPCSUM;
+				if (m->m_pkthdr.csum_flags & M_CSUM_TCPv4) {
+					re_flags |= RE_TDESC_CMD_TCPCSUM;
+				} else if (m->m_pkthdr.csum_flags &
+				    M_CSUM_UDPv4) {
+					re_flags |= RE_TDESC_CMD_UDPCSUM;
+				}
+			}
+		}
+
+		txq = &sc->re_ldata.re_txq[idx];
+		map = txq->txq_dmamap;
+		error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
+		    BUS_DMA_WRITE|BUS_DMA_NOWAIT);
+
+		if (__predict_false(error)) {
+			/* XXX try to defrag if EFBIG? */
+			aprint_error("%s: can't map mbuf (error %d)\n",
+			    sc->sc_dev.dv_xname, error);
+
 			IFQ_DEQUEUE(&ifp->if_snd, m);
 			m_freem(m);
 			ifp->if_oerrors++;
 			continue;
 		}
-		if (error) {
+
+		nsegs = map->dm_nsegs;
+		pad = FALSE;
+		if (__predict_false(m->m_pkthdr.len <= RE_IP4CSUMTX_PADLEN &&
+		    (re_flags & RE_TDESC_CMD_IPCSUM) != 0)) {
+			pad = TRUE;
+			nsegs++;
+		}
+
+		if (nsegs > sc->re_ldata.re_tx_free - RE_NTXDESC_RSVD) {
+			/*
+			 * Not enough free descriptors to transmit this packet.
+			 */
 			ifp->if_flags |= IFF_OACTIVE;
+			bus_dmamap_unload(sc->sc_dmat, map);
 			break;
 		}
 
 		IFQ_DEQUEUE(&ifp->if_snd, m);
 
+		/*
+		 * Make sure that the caches are synchronized before we
+		 * ask the chip to start DMA for the packet data.
+		 */
+		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+		    BUS_DMASYNC_PREWRITE);
+
+		/*
+		 * 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.)
+		 */
+		curdesc = startdesc = sc->re_ldata.re_tx_nextfree;
+		lastdesc = -1;
+		for (seg = 0; seg < map->dm_nsegs;
+		    seg++, curdesc = RE_NEXT_TX_DESC(sc, curdesc)) {
+			d = &sc->re_ldata.re_tx_list[curdesc];
+#ifdef DIAGNOSTIC
+			RE_TXDESCSYNC(sc, curdesc,
+			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+			cmdstat = le32toh(d->re_cmdstat);
+			RE_TXDESCSYNC(sc, curdesc, BUS_DMASYNC_PREREAD);
+			if (cmdstat & RE_TDESC_STAT_OWN) {
+				panic("%s: tried to map busy TX descriptor",
+				    sc->sc_dev.dv_xname);
+			}
+#endif
+
+			d->re_vlanctl = 0;
+			re_set_bufaddr(d, map->dm_segs[seg].ds_addr);
+			cmdstat = re_flags | map->dm_segs[seg].ds_len;
+			if (seg == 0)
+				cmdstat |= RE_TDESC_CMD_SOF;
+			else
+				cmdstat |= RE_TDESC_CMD_OWN;
+			if (curdesc == (RE_TX_DESC_CNT(sc) - 1))
+				cmdstat |= RE_TDESC_CMD_EOR;
+			if (seg == nsegs - 1) {
+				cmdstat |= RE_TDESC_CMD_EOF;
+				lastdesc = curdesc;
+			}
+			d->re_cmdstat = htole32(cmdstat);
+			RE_TXDESCSYNC(sc, curdesc,
+			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		}
+		if (__predict_false(pad)) {
+			bus_addr_t paddaddr;
+
+			d = &sc->re_ldata.re_tx_list[curdesc];
+			d->re_vlanctl = 0;
+			paddaddr = RE_TXPADDADDR(sc);
+			re_set_bufaddr(d, paddaddr);
+			cmdstat = re_flags |
+			    RE_TDESC_CMD_OWN | RE_TDESC_CMD_EOF |
+			    (RE_IP4CSUMTX_PADLEN + 1 - m->m_pkthdr.len);
+			if (curdesc == (RE_TX_DESC_CNT(sc) - 1))
+				cmdstat |= RE_TDESC_CMD_EOR;
+			d->re_cmdstat = htole32(cmdstat);
+			RE_TXDESCSYNC(sc, curdesc,
+			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+			lastdesc = curdesc;
+			curdesc = RE_NEXT_TX_DESC(sc, curdesc);
+		}
+		KASSERT(lastdesc != -1);
+
+		/*
+		 * Set up hardware VLAN tagging. Note: vlan tag info must
+		 * appear in the first descriptor of a multi-descriptor
+		 * transmission attempt.
+		 */
+		if ((mtag = VLAN_OUTPUT_TAG(&sc->ethercom, m)) != NULL) {
+			sc->re_ldata.re_tx_list[startdesc].re_vlanctl =
+			    htole32(bswap16(VLAN_TAG_VALUE(mtag)) |
+			    RE_TDESC_VLANCTL_TAG);
+		}
+
+		/* Transfer ownership of packet to the chip. */
+
+		sc->re_ldata.re_tx_list[startdesc].re_cmdstat |=
+		    htole32(RE_TDESC_CMD_OWN);
+		RE_TXDESCSYNC(sc, startdesc,
+		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+		/* update info of TX queue and descriptors */
+		txq->txq_mbuf = m;
+		txq->txq_descidx = lastdesc;
+		txq->txq_nsegs = nsegs;
+
+		sc->re_ldata.re_txq_free--;
+		sc->re_ldata.re_tx_free -= nsegs;
+		sc->re_ldata.re_tx_nextfree = curdesc;
+
 #if NBPFILTER > 0
 		/*
 		 * If there's a BPF listener, bounce a copy of this frame
@@ -1718,52 +1712,47 @@
 #endif
 	}
 
-	if (sc->rtk_ldata.rtk_txq_prodidx == idx) {
-		return;
-	}
-	sc->rtk_ldata.rtk_txq_prodidx = idx;
-
-	/* Flush the TX descriptors */
-
-	bus_dmamap_sync(sc->sc_dmat,
-	    sc->rtk_ldata.rtk_tx_list_map,
-	    0, sc->rtk_ldata.rtk_tx_list_map->dm_mapsize,
-	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-	/*
-	 * RealTek put the TX poll request register in a different
-	 * location on the 8169 gigE chip. I don't know why.
-	 */
-
-	if (sc->rtk_type == RTK_8169)
-		CSR_WRITE_2(sc, RTK_GTXSTART, RTK_TXSTART_START);
-	else
-		CSR_WRITE_2(sc, RTK_TXSTART, RTK_TXSTART_START);
+	if (sc->re_ldata.re_txq_free < ofree) {
+		/*
+		 * TX packets are enqueued.
+		 */
+		sc->re_ldata.re_txq_prodidx = idx;
 
-	/*
-	 * Use the countdown timer for interrupt moderation.
-	 * 'TX done' interrupts are disabled. Instead, we reset the
-	 * countdown timer, which will begin counting until it hits
-	 * the value in the TIMERINT register, and then trigger an
-	 * interrupt. Each time we write to the TIMERCNT register,
-	 * the timer count is reset to 0.
-	 */
-	CSR_WRITE_4(sc, RTK_TIMERCNT, 1);
+		/*
+		 * Start the transmitter to poll.
+		 *
+		 * RealTek put the TX poll request register in a different
+		 * location on the 8169 gigE chip. I don't know why.
+		 */
+		if (sc->rtk_type == RTK_8169)
+			CSR_WRITE_2(sc, RTK_GTXSTART, RTK_TXSTART_START);
+		else
+			CSR_WRITE_1(sc, RTK_TXSTART, RTK_TXSTART_START);
 
-	/*
-	 * Set a timeout in case the chip goes out to lunch.
-	 */
-	ifp->if_timer = 5;
+		/*
+		 * Use the countdown timer for interrupt moderation.
+		 * 'TX done' interrupts are disabled. Instead, we reset the
+		 * countdown timer, which will begin counting until it hits
+		 * the value in the TIMERINT register, and then trigger an
+		 * interrupt. Each time we write to the TIMERCNT register,
+		 * the timer count is reset to 0.
+		 */
+		CSR_WRITE_4(sc, RTK_TIMERCNT, 1);
 
-	return;
+		/*
+		 * Set a timeout in case the chip goes out to lunch.
+		 */
+		ifp->if_timer = 5;
+	}
 }
 
 static int
 re_init(struct ifnet *ifp)
 {
 	struct rtk_softc	*sc = ifp->if_softc;
-	u_int32_t		rxcfg = 0;
-	u_int32_t		reg;
+	uint8_t			*enaddr;
+	uint32_t		rxcfg = 0;
+	uint32_t		reg;
 	int error;
 
 	if ((error = re_enable(sc)) != 0)
@@ -1774,6 +1763,8 @@
 	 */
 	re_stop(ifp, 0);
 
+	re_reset(sc);
+
 	/*
 	 * Enable C+ RX and TX mode, as well as VLAN stripping and
 	 * RX checksum offload. We must configure the C+ register
@@ -1788,19 +1779,18 @@
 	 */
 
 	/*
-	 * XXX: For 8169 and 8196S revs below 2, set bit 14.
+	 * XXX: For 8169 and 8169S revs below 2, set bit 14.
 	 * For 8169S/8110S rev 2 and above, do not set bit 14.
 	 */
 	if (sc->rtk_type == RTK_8169 && sc->sc_rev == 1)
 		reg |= (0x1 << 14) | RTK_CPLUSCMD_PCI_MRW;;
 
 	if (1)  {/* not for 8169S ? */
-		reg |= 
-#ifdef RE_VLAN
+		reg |=
 		    RTK_CPLUSCMD_VLANSTRIP |
-#endif
 		    (ifp->if_capenable &
-		    (IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4) ?
+		    (IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
+		     IFCAP_CSUM_UDPv4) ?
 		    RTK_CPLUSCMD_RXCSUM_ENB : 0);
 	}
 
@@ -1809,7 +1799,7 @@
 
 	/* XXX: from Realtek-supplied Linux driver. Wholly undocumented. */
 	if (sc->rtk_type == RTK_8169)
-		CSR_WRITE_2(sc, RTK_CPLUS_CMD+0x2, 0x0000);
+		CSR_WRITE_2(sc, RTK_IM, 0x0000);
 
 	DELAY(10000);
 
@@ -1819,11 +1809,12 @@
 	 * register write enable" mode to modify the ID registers.
 	 */
 	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_WRITECFG);
-	memcpy(&reg, LLADDR(ifp->if_sadl), 4);
-	CSR_WRITE_STREAM_4(sc, RTK_IDR0, reg);
-	reg = 0;
-	memcpy(&reg, LLADDR(ifp->if_sadl) + 4, 4);
-	CSR_WRITE_STREAM_4(sc, RTK_IDR4, reg);
+	enaddr = LLADDR(ifp->if_sadl);
+	reg = enaddr[0] | (enaddr[1] << 8) |
+	    (enaddr[2] << 16) | (enaddr[3] << 24);
+	CSR_WRITE_4(sc, RTK_IDR0, reg);
+	reg = enaddr[4] | (enaddr[5] << 8);
+	CSR_WRITE_4(sc, RTK_IDR4, reg);
 	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_OFF);
 
 	/*
@@ -1833,6 +1824,19 @@
 	re_tx_list_init(sc);
 
 	/*
+	 * Load the addresses of the RX and TX lists into the chip.
+	 */
+	CSR_WRITE_4(sc, RTK_RXLIST_ADDR_HI,
+	    RE_ADDR_HI(sc->re_ldata.re_rx_list_map->dm_segs[0].ds_addr));
+	CSR_WRITE_4(sc, RTK_RXLIST_ADDR_LO,
+	    RE_ADDR_LO(sc->re_ldata.re_rx_list_map->dm_segs[0].ds_addr));
+
+	CSR_WRITE_4(sc, RTK_TXLIST_ADDR_HI,
+	    RE_ADDR_HI(sc->re_ldata.re_tx_list_map->dm_segs[0].ds_addr));
+	CSR_WRITE_4(sc, RTK_TXLIST_ADDR_LO,
+	    RE_ADDR_LO(sc->re_ldata.re_tx_list_map->dm_segs[0].ds_addr));
+
+	/*
 	 * Enable transmit and receive.
 	 */
 	CSR_WRITE_1(sc, RTK_COMMAND, RTK_CMD_TX_ENB | RTK_CMD_RX_ENB);
@@ -1840,16 +1844,19 @@
 	/*
 	 * Set the initial TX and RX configuration.
 	 */
-	if (sc->rtk_testmode) {
+	if (sc->re_testmode) {
 		if (sc->rtk_type == RTK_8169)
 			CSR_WRITE_4(sc, RTK_TXCFG,
-			    RTK_TXCFG_CONFIG | RTK_LOOPTEST_ON);
+			    RE_TXCFG_CONFIG | RTK_LOOPTEST_ON);
 		else
 			CSR_WRITE_4(sc, RTK_TXCFG,
-			    RTK_TXCFG_CONFIG | RTK_LOOPTEST_ON_CPLUS);
+			    RE_TXCFG_CONFIG | RTK_LOOPTEST_ON_CPLUS);
 	} else
-		CSR_WRITE_4(sc, RTK_TXCFG, RTK_TXCFG_CONFIG);
-	CSR_WRITE_4(sc, RTK_RXCFG, RTK_RXCFG_CONFIG);
+		CSR_WRITE_4(sc, RTK_TXCFG, RE_TXCFG_CONFIG);
+
+	CSR_WRITE_1(sc, RTK_EARLY_TX_THRESH, 16);
+
+	CSR_WRITE_4(sc, RTK_RXCFG, RE_RXCFG_CONFIG);
 
 	/* Set the individual bit to receive frames for this host only. */
 	rxcfg = CSR_READ_4(sc, RTK_RXCFG);
@@ -1887,7 +1894,7 @@
 	/*
 	 * Enable interrupts.
 	 */
-	if (sc->rtk_testmode)
+	if (sc->re_testmode)
 		CSR_WRITE_2(sc, RTK_IMR, 0);
 	else
 		CSR_WRITE_2(sc, RTK_IMR, RTK_INTRS_CPLUS);
@@ -1898,21 +1905,6 @@
 	/* Enable receiver and transmitter. */
 	CSR_WRITE_1(sc, RTK_COMMAND, RTK_CMD_TX_ENB | RTK_CMD_RX_ENB);
 #endif
-	/*
-	 * Load the addresses of the RX and TX lists into the chip.
-	 */
-
-	CSR_WRITE_4(sc, RTK_RXLIST_ADDR_HI,
-	    RTK_ADDR_HI(sc->rtk_ldata.rtk_rx_list_map->dm_segs[0].ds_addr));
-	CSR_WRITE_4(sc, RTK_RXLIST_ADDR_LO,
-	    RTK_ADDR_LO(sc->rtk_ldata.rtk_rx_list_map->dm_segs[0].ds_addr));
-
-	CSR_WRITE_4(sc, RTK_TXLIST_ADDR_HI,
-	    RTK_ADDR_HI(sc->rtk_ldata.rtk_tx_list_map->dm_segs[0].ds_addr));
-	CSR_WRITE_4(sc, RTK_TXLIST_ADDR_LO,
-	    RTK_ADDR_LO(sc->rtk_ldata.rtk_tx_list_map->dm_segs[0].ds_addr));
-
-	CSR_WRITE_1(sc, RTK_EARLY_TX_THRESH, 16);
 
 	/*
 	 * Initialize the timer interrupt register so that
@@ -1934,19 +1926,17 @@
 	if (sc->rtk_type == RTK_8169)
 		CSR_WRITE_2(sc, RTK_MAXRXPKTLEN, 16383);
 
-	if (sc->rtk_testmode)
+	if (sc->re_testmode)
 		return 0;
 
-	mii_mediachg(&sc->mii);
-
-	CSR_WRITE_1(sc, RTK_CFG1, RTK_CFG1_DRVLOAD | RTK_CFG1_FULLDUPLEX);
+	CSR_WRITE_1(sc, RTK_CFG1, RTK_CFG1_DRVLOAD);
 
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
 	callout_reset(&sc->rtk_tick_ch, hz, re_tick, sc);
 
-out:
+ out:
 	if (error) {
 		ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 		ifp->if_timer = 0;
@@ -1955,7 +1945,6 @@
 	}
 
 	return error;
-
 }
 
 /*
@@ -1984,8 +1973,6 @@
 	mii_pollstat(&sc->mii);
 	ifmr->ifm_active = sc->mii.mii_media_active;
 	ifmr->ifm_status = sc->mii.mii_media_status;
-
-	return;
 }
 
 static int
@@ -1999,7 +1986,7 @@
 
 	switch (command) {
 	case SIOCSIFMTU:
-		if (ifr->ifr_mtu > RTK_JUMBO_MTU)
+		if (ifr->ifr_mtu > RE_JUMBO_MTU)
 			error = EINVAL;
 		ifp->if_mtu = ifr->ifr_mtu;
 		break;
@@ -2048,7 +2035,7 @@
 static void
 re_stop(struct ifnet *ifp, int disable)
 {
-	register int		i;
+	int		i;
 	struct rtk_softc *sc = ifp->if_softc;
 
 	callout_stop(&sc->rtk_tick_ch);
@@ -2062,28 +2049,28 @@
 	CSR_WRITE_1(sc, RTK_COMMAND, 0x00);
 	CSR_WRITE_2(sc, RTK_IMR, 0x0000);
 
-	if (sc->rtk_head != NULL) {
-		m_freem(sc->rtk_head);
-		sc->rtk_head = sc->rtk_tail = NULL;
+	if (sc->re_head != NULL) {
+		m_freem(sc->re_head);
+		sc->re_head = sc->re_tail = NULL;
 	}
 
 	/* Free the TX list buffers. */
-	for (i = 0; i < RTK_TX_QLEN; i++) {
-		if (sc->rtk_ldata.rtk_txq[i].txq_mbuf != NULL) {
+	for (i = 0; i < RE_TX_QLEN; i++) {
+		if (sc->re_ldata.re_txq[i].txq_mbuf != NULL) {
 			bus_dmamap_unload(sc->sc_dmat,
-			    sc->rtk_ldata.rtk_txq[i].txq_dmamap);
-			m_freem(sc->rtk_ldata.rtk_txq[i].txq_mbuf);
-			sc->rtk_ldata.rtk_txq[i].txq_mbuf = NULL;
+			    sc->re_ldata.re_txq[i].txq_dmamap);
+			m_freem(sc->re_ldata.re_txq[i].txq_mbuf);
+			sc->re_ldata.re_txq[i].txq_mbuf = NULL;
 		}
 	}
 
 	/* Free the RX list buffers. */
-	for (i = 0; i < RTK_RX_DESC_CNT; i++) {
-		if (sc->rtk_ldata.rtk_rx_mbuf[i] != NULL) {
+	for (i = 0; i < RE_RX_DESC_CNT; i++) {
+		if (sc->re_ldata.re_rxsoft[i].rxs_mbuf != NULL) {
 			bus_dmamap_unload(sc->sc_dmat,
-			    sc->rtk_ldata.rtk_rx_dmamap[i]);
-			m_freem(sc->rtk_ldata.rtk_rx_mbuf[i]);
-			sc->rtk_ldata.rtk_rx_mbuf[i] = NULL;
+			    sc->re_ldata.re_rxsoft[i].rxs_dmamap);
+			m_freem(sc->re_ldata.re_rxsoft[i].rxs_mbuf);
+			sc->re_ldata.re_rxsoft[i].rxs_mbuf = NULL;
 		}
 	}
 
@@ -2092,6 +2079,4 @@
 
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 	ifp->if_timer = 0;
-
-	return;
 }
Index: dev/ic/rtl81x9.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/rtl81x9.c,v
retrieving revision 1.51
diff -u -r1.51 rtl81x9.c
--- dev/ic/rtl81x9.c	27 Feb 2005 00:27:02 -0000	1.51
+++ dev/ic/rtl81x9.c	11 Feb 2007 03:42:01 -0000
@@ -131,13 +131,13 @@
 #define STATIC static
 #endif
 
-STATIC void rtk_reset		(struct rtk_softc *);
-STATIC void rtk_rxeof		(struct rtk_softc *);
-STATIC void rtk_txeof		(struct rtk_softc *);
-STATIC void rtk_start		(struct ifnet *);
-STATIC int rtk_ioctl		(struct ifnet *, u_long, caddr_t);
-STATIC int rtk_init		(struct ifnet *);
-STATIC void rtk_stop		(struct ifnet *, int);
+STATIC void rtk_reset(struct rtk_softc *);
+STATIC void rtk_rxeof(struct rtk_softc *);
+STATIC void rtk_txeof(struct rtk_softc *);
+STATIC void rtk_start(struct ifnet *);
+STATIC int rtk_ioctl(struct ifnet *, u_long, caddr_t);
+STATIC int rtk_init(struct ifnet *);
+STATIC void rtk_stop(struct ifnet *, int);
 
 STATIC void rtk_watchdog(struct ifnet *);
 STATIC void rtk_shutdown(void *);
@@ -146,18 +146,18 @@
 
 STATIC void rtk_eeprom_putbyte(struct rtk_softc *, int, int);
 STATIC void rtk_mii_sync(struct rtk_softc *);
-STATIC void rtk_mii_send(struct rtk_softc *, u_int32_t, int);
+STATIC void rtk_mii_send(struct rtk_softc *, uint32_t, int);
 STATIC int rtk_mii_readreg(struct rtk_softc *, struct rtk_mii_frame *);
 STATIC int rtk_mii_writereg(struct rtk_softc *, struct rtk_mii_frame *);
 
 STATIC int rtk_phy_readreg(struct device *, int, int);
 STATIC void rtk_phy_writereg(struct device *, int, int, int);
 STATIC void rtk_phy_statchg(struct device *);
-STATIC void rtk_tick		(void *);
+STATIC void rtk_tick(void *);
 
-STATIC int rtk_enable		(struct rtk_softc *);
-STATIC void rtk_disable		(struct rtk_softc *);
-STATIC void rtk_power		(int, void *);
+STATIC int rtk_enable(struct rtk_softc *);
+STATIC void rtk_disable(struct rtk_softc *);
+STATIC void rtk_power(int, void *);
 
 STATIC int rtk_list_tx_init(struct rtk_softc *);
 
@@ -169,17 +169,17 @@
 	CSR_WRITE_1(sc, RTK_EECMD,			\
 		CSR_READ_1(sc, RTK_EECMD) & ~(x))
 
+#define EE_DELAY()	DELAY(100)
+
 #define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
 
 /*
  * Send a read command and address to the EEPROM, check for ACK.
  */
 STATIC void
-rtk_eeprom_putbyte(sc, addr, addr_len)
-	struct rtk_softc	*sc;
-	int			addr, addr_len;
+rtk_eeprom_putbyte(struct rtk_softc *sc, int addr, int addr_len)
 {
-	int			d, i;
+	int d, i;
 
 	d = (RTK_EECMD_READ << addr_len) | addr;
 
@@ -192,51 +192,50 @@
 		} else {
 			EE_CLR(RTK_EE_DATAIN);
 		}
-		DELAY(4);
+		EE_DELAY();
 		EE_SET(RTK_EE_CLK);
-		DELAY(4);
+		EE_DELAY();
 		EE_CLR(RTK_EE_CLK);
-		DELAY(4);
+		EE_DELAY();
 	}
 }
 
 /*
  * Read a word of data stored in the EEPROM at address 'addr.'
  */
-u_int16_t
-rtk_read_eeprom(sc, addr, addr_len)
-	struct rtk_softc	*sc;
-	int			addr, addr_len;
+uint16_t
+rtk_read_eeprom(struct rtk_softc *sc, int addr, int addr_len)
 {
-	u_int16_t		word = 0;
-	int			i;
+	uint16_t word;
+	int i;
 
 	/* Enter EEPROM access mode. */
-	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_PROGRAM|RTK_EE_SEL);
+	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_PROGRAM);
+	EE_DELAY();
+	EE_SET(RTK_EE_SEL);
 
 	/*
 	 * Send address of word we want to read.
 	 */
 	rtk_eeprom_putbyte(sc, addr, addr_len);
 
-	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_PROGRAM|RTK_EE_SEL);
-
 	/*
 	 * Start reading bits from EEPROM.
 	 */
+	word = 0;
 	for (i = 16; i > 0; i--) {
 		EE_SET(RTK_EE_CLK);
-		DELAY(4);
+		EE_DELAY();
 		if (CSR_READ_1(sc, RTK_EECMD) & RTK_EE_DATAOUT)
 			word |= 1 << (i - 1);
 		EE_CLR(RTK_EE_CLK);
-		DELAY(4);
+		EE_DELAY();
 	}
 
 	/* Turn off EEPROM access mode. */
 	CSR_WRITE_1(sc, RTK_EECMD, RTK_EEMODE_OFF);
 
-	return (word);
+	return word;
 }
 
 /*
@@ -257,10 +256,9 @@
  * Sync the PHYs by setting data bit and strobing the clock 32 times.
  */
 STATIC void
-rtk_mii_sync(sc)
-	struct rtk_softc	*sc;
+rtk_mii_sync(struct rtk_softc *sc)
 {
-	int			i;
+	int i;
 
 	MII_SET(RTK_MII_DIR|RTK_MII_DATAOUT);
 
@@ -276,21 +274,18 @@
  * Clock a series of bits through the MII.
  */
 STATIC void
-rtk_mii_send(sc, bits, cnt)
-	struct rtk_softc	*sc;
-	u_int32_t		bits;
-	int			cnt;
+rtk_mii_send(struct rtk_softc *sc, uint32_t bits, int cnt)
 {
-	int			i;
+	int i;
 
 	MII_CLR(RTK_MII_CLK);
 
 	for (i = cnt; i > 0; i--) {
-                if (bits & (1 << (i - 1))) {
+		if (bits & (1 << (i - 1))) {
 			MII_SET(RTK_MII_DATAOUT);
-                } else {
+		} else {
 			MII_CLR(RTK_MII_DATAOUT);
-                }
+		}
 		DELAY(1);
 		MII_CLR(RTK_MII_CLK);
 		DELAY(1);
@@ -302,11 +297,9 @@
  * Read an PHY register through the MII.
  */
 STATIC int
-rtk_mii_readreg(sc, frame)
-	struct rtk_softc	*sc;
-	struct rtk_mii_frame	*frame;
+rtk_mii_readreg(struct rtk_softc *sc, struct rtk_mii_frame *frame)
 {
-	int			i, ack, s;
+	int i, ack, s;
 
 	s = splnet();
 
@@ -321,7 +314,7 @@
 	CSR_WRITE_2(sc, RTK_MII, 0);
 
 	/*
- 	 * Turn on data xmit.
+	 * Turn on data xmit.
 	 */
 	MII_SET(RTK_MII_DIR);
 
@@ -347,9 +340,9 @@
 	/* Check for ack */
 	MII_CLR(RTK_MII_CLK);
 	DELAY(1);
+	ack = CSR_READ_2(sc, RTK_MII) & RTK_MII_DATAIN;
 	MII_SET(RTK_MII_CLK);
 	DELAY(1);
-	ack = CSR_READ_2(sc, RTK_MII) & RTK_MII_DATAIN;
 
 	/*
 	 * Now try reading data bits. If the ack failed, we still
@@ -386,19 +379,17 @@
 	splx(s);
 
 	if (ack)
-		return (1);
-	return (0);
+		return 1;
+	return 0;
 }
 
 /*
  * Write to a PHY register through the MII.
  */
 STATIC int
-rtk_mii_writereg(sc, frame)
-	struct rtk_softc	*sc;
-	struct rtk_mii_frame	*frame;
+rtk_mii_writereg(struct rtk_softc *sc, struct rtk_mii_frame *frame)
 {
-	int			s;
+	int s;
 
 	s = splnet();
 	/*
@@ -409,7 +400,7 @@
 	frame->mii_turnaround = RTK_MII_TURNAROUND;
 
 	/*
- 	 * Turn on data output.
+	 * Turn on data output.
 	 */
 	MII_SET(RTK_MII_DIR);
 
@@ -435,24 +426,22 @@
 
 	splx(s);
 
-	return (0);
+	return 0;
 }
 
 STATIC int
-rtk_phy_readreg(self, phy, reg)
-	struct device		*self;
-	int			phy, reg;
-{
-	struct rtk_softc	*sc = (void *)self;
-	struct rtk_mii_frame	frame;
-	int			rval = 0;
-	int			rtk8139_reg = 0;
+rtk_phy_readreg(struct device *self, int phy, int reg)
+{
+	struct rtk_softc *sc = (void *)self;
+	struct rtk_mii_frame frame;
+	int rval;
+	int rtk8139_reg;
 
 	if (sc->rtk_type == RTK_8139) {
 		if (phy != 7)
-			return (0);
+			return 0;
 
-		switch(reg) {
+		switch (reg) {
 		case MII_BMCR:
 			rtk8139_reg = RTK_BMCR;
 			break;
@@ -472,10 +461,10 @@
 #if 0
 			printf("%s: bad phy register\n", sc->sc_dev.dv_xname);
 #endif
-			return (0);
+			return 0;
 		}
 		rval = CSR_READ_2(sc, rtk8139_reg);
-		return (rval);
+		return rval;
 	}
 
 	memset((char *)&frame, 0, sizeof(frame));
@@ -484,23 +473,20 @@
 	frame.mii_regaddr = reg;
 	rtk_mii_readreg(sc, &frame);
 
-	return (frame.mii_data);
+	return frame.mii_data;
 }
 
-STATIC void rtk_phy_writereg(self, phy, reg, data)
-	struct device		*self;
-	int			phy, reg;
-	int			data;
+STATIC void rtk_phy_writereg(struct device *self, int phy, int reg, int data)
 {
-	struct rtk_softc	*sc = (void *)self;
-	struct rtk_mii_frame	frame;
-	int			rtk8139_reg = 0;
+	struct rtk_softc *sc = (void *)self;
+	struct rtk_mii_frame frame;
+	int rtk8139_reg;
 
 	if (sc->rtk_type == RTK_8139) {
 		if (phy != 7)
 			return;
 
-		switch(reg) {
+		switch (reg) {
 		case MII_BMCR:
 			rtk8139_reg = RTK_BMCR;
 			break;
@@ -536,8 +522,7 @@
 }
 
 STATIC void
-rtk_phy_statchg(v)
-	struct device *v;
+rtk_phy_statchg(struct device *v)
 {
 
 	/* Nothing to do. */
@@ -550,23 +535,21 @@
  * Program the 64-bit multicast hash filter.
  */
 void
-rtk_setmulti(sc)
-	struct rtk_softc	*sc;
+rtk_setmulti(struct rtk_softc *sc)
 {
-	struct ifnet		*ifp;
-	int			h = 0;
-	u_int32_t		hashes[2] = { 0, 0 };
-	u_int32_t		rxfilt;
-	int			mcnt = 0;
+	struct ifnet *ifp;
+	uint32_t hashes[2] = { 0, 0 };
+	uint32_t rxfilt, hwrev;
 	struct ether_multi *enm;
 	struct ether_multistep step;
+	int h, mcnt;
 
 	ifp = &sc->ethercom.ec_if;
 
 	rxfilt = CSR_READ_4(sc, RTK_RXCFG);
 
 	if (ifp->if_flags & IFF_PROMISC) {
-allmulti:
+ allmulti:
 		ifp->if_flags |= IFF_ALLMULTI;
 		rxfilt |= RTK_RXCFG_RX_MULTI;
 		CSR_WRITE_4(sc, RTK_RXCFG, rxfilt);
@@ -581,6 +564,7 @@
 
 	/* now program new ones */
 	ETHER_FIRST_MULTI(step, &sc->ethercom, enm);
+	mcnt = 0;
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0)
@@ -603,15 +587,28 @@
 		rxfilt &= ~RTK_RXCFG_RX_MULTI;
 
 	CSR_WRITE_4(sc, RTK_RXCFG, rxfilt);
-	CSR_WRITE_4(sc, RTK_MAR0, hashes[0]);
-	CSR_WRITE_4(sc, RTK_MAR4, hashes[1]);
+
+	/*
+	 * 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.
+	 */
+	hwrev = CSR_READ_4(sc, RTK_TXCFG) & RTK_TXCFG_HWREV;
+	if (hwrev == RTK_HWREV_8100E || hwrev == RTK_HWREV_8101E ||
+	    hwrev == RTK_HWREV_8168_SPIN1 || hwrev == RTK_HWREV_8168_SPIN2) {
+		CSR_WRITE_4(sc, RTK_MAR0, bswap32(hashes[1]));
+		CSR_WRITE_4(sc, RTK_MAR4, bswap32(hashes[0]));
+	} else {
+		CSR_WRITE_4(sc, RTK_MAR0, hashes[0]);
+		CSR_WRITE_4(sc, RTK_MAR4, hashes[1]);
+	}
 }
 
 void
-rtk_reset(sc)
-	struct rtk_softc	*sc;
+rtk_reset(struct rtk_softc *sc)
 {
-	int			i;
+	int i;
 
 	CSR_WRITE_1(sc, RTK_COMMAND, RTK_CMD_RESET);
 
@@ -629,13 +626,12 @@
  * setup and ethernet/BPF attach.
  */
 void
-rtk_attach(sc)
-	struct rtk_softc *sc;
+rtk_attach(struct rtk_softc *sc)
 {
 	struct ifnet *ifp;
 	struct rtk_tx_desc *txd;
-	u_int16_t val;
-	u_int8_t eaddr[ETHER_ADDR_LEN];
+	uint16_t val;
+	uint8_t eaddr[ETHER_ADDR_LEN];
 	int error;
 	int i, addr_len;
 
@@ -666,7 +662,7 @@
 	    RTK_RXBUFLEN + 16, PAGE_SIZE, 0, &sc->sc_dmaseg, 1, &sc->sc_dmanseg,
 	    BUS_DMA_NOWAIT)) != 0) {
 		printf("%s: can't allocate recv buffer, error = %d\n",
-		       sc->sc_dev.dv_xname, error);
+		    sc->sc_dev.dv_xname, error);
 		goto fail_0;
 	}
 
@@ -674,7 +670,7 @@
 	    RTK_RXBUFLEN + 16, (caddr_t *)&sc->rtk_rx_buf,
 	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
 		printf("%s: can't map recv buffer, error = %d\n",
-		       sc->sc_dev.dv_xname, error);
+		    sc->sc_dev.dv_xname, error);
 		goto fail_1;
 	}
 
@@ -682,7 +678,7 @@
 	    RTK_RXBUFLEN + 16, 1, RTK_RXBUFLEN + 16, 0, BUS_DMA_NOWAIT,
 	    &sc->recv_dmamap)) != 0) {
 		printf("%s: can't create recv buffer DMA map, error = %d\n",
-		       sc->sc_dev.dv_xname, error);
+		    sc->sc_dev.dv_xname, error);
 		goto fail_2;
 	}
 
@@ -690,7 +686,7 @@
 	    sc->rtk_rx_buf, RTK_RXBUFLEN + 16,
 	    NULL, BUS_DMA_READ|BUS_DMA_NOWAIT)) != 0) {
 		printf("%s: can't load recv buffer DMA map, error = %d\n",
-		       sc->sc_dev.dv_xname, error);
+		    sc->sc_dev.dv_xname, error);
 		goto fail_3;
 	}
 
@@ -716,9 +712,6 @@
 	 */
 	sc->sc_flags |= RTK_ATTACHED;
 
-	/* Init Early TX threshold. */
-	sc->sc_txthresh = TXTH_256;
-
 	/* Reset the adapter. */
 	rtk_reset(sc);
 
@@ -743,7 +736,8 @@
 	sc->mii.mii_readreg = rtk_phy_readreg;
 	sc->mii.mii_writereg = rtk_phy_writereg;
 	sc->mii.mii_statchg = rtk_phy_statchg;
-	ifmedia_init(&sc->mii.mii_media, IFM_IMASK, rtk_ifmedia_upd, rtk_ifmedia_sts);
+	ifmedia_init(&sc->mii.mii_media, IFM_IMASK, rtk_ifmedia_upd,
+	    rtk_ifmedia_sts);
 	mii_attach(&sc->sc_dev, &sc->mii, 0xffffffff,
 	    MII_PHY_ANY, MII_OFFSET_ANY, 0);
 
@@ -805,8 +799,7 @@
  * Initialize the transmit descriptors.
  */
 STATIC int
-rtk_list_tx_init(sc)
-	struct rtk_softc	*sc;
+rtk_list_tx_init(struct rtk_softc *sc)
 {
 	struct rtk_tx_desc *txd;
 	int i;
@@ -822,7 +815,7 @@
 		SIMPLEQ_INSERT_TAIL(&sc->rtk_tx_free, txd, txd_q);
 	}
 
-	return (0);
+	return 0;
 }
 
 /*
@@ -830,13 +823,12 @@
  *     Handle device activation/deactivation requests.
  */
 int
-rtk_activate(self, act)
-	struct device *self;
-	enum devact act;
+rtk_activate(struct device *self, enum devact act)
 {
-	struct rtk_softc *sc = (void *) self;
-	int s, error = 0;
+	struct rtk_softc *sc = (void *)self;
+	int s, error;
 
+	error = 0;
 	s = splnet();
 	switch (act) {
 	case DVACT_ACTIVATE:
@@ -849,7 +841,7 @@
 	}
 	splx(s);
 
-	return (error);
+	return error;
 }
 
 /*
@@ -857,8 +849,7 @@
  *     Detach a rtk interface.
  */
 int
-rtk_detach(sc)
-	struct rtk_softc *sc;
+rtk_detach(struct rtk_softc *sc)
 {
 	struct ifnet *ifp = &sc->ethercom.ec_if;
 	struct rtk_tx_desc *txd;
@@ -868,7 +859,7 @@
 	 * Succeed now if there isn't any work to do.
 	 */
 	if ((sc->sc_flags & RTK_ATTACHED) == 0)
-		return (0);
+		return 0;
 
 	/* Unhook our tick handler. */
 	callout_stop(&sc->rtk_tick_ch);
@@ -899,7 +890,7 @@
 	shutdownhook_disestablish(sc->sc_sdhook);
 	powerhook_disestablish(sc->sc_powerhook);
 
-	return (0);
+	return 0;
 }
 
 /*
@@ -907,19 +898,18 @@
  *     Enable the RTL81X9 chip.
  */
 int
-rtk_enable(sc)
-	struct rtk_softc *sc;
+rtk_enable(struct rtk_softc *sc)
 {
 
 	if (RTK_IS_ENABLED(sc) == 0 && sc->sc_enable != NULL) {
 		if ((*sc->sc_enable)(sc) != 0) {
 			printf("%s: device enable failed\n",
 			    sc->sc_dev.dv_xname);
-			return (EIO);
+			return EIO;
 		}
 		sc->sc_flags |= RTK_ENABLED;
 	}
-	return (0);
+	return 0;
 }
 
 /*
@@ -927,8 +917,7 @@
  *     Disable the RTL81X9 chip.
  */
 void
-rtk_disable(sc)
-	struct rtk_softc *sc;
+rtk_disable(struct rtk_softc *sc)
 {
 
 	if (RTK_IS_ENABLED(sc) && sc->sc_disable != NULL) {
@@ -942,11 +931,9 @@
  *     Power management (suspend/resume) hook.
  */
 void
-rtk_power(why, arg)
-	int why;
-	void *arg;
+rtk_power(int why, void *arg)
 {
-	struct rtk_softc *sc = (void *) arg;
+	struct rtk_softc *sc = (void *)arg;
 	struct ifnet *ifp = &sc->ethercom.ec_if;
 	int s;
 
@@ -994,17 +981,16 @@
  * shifted forward 2 bytes.
  */
 STATIC void
-rtk_rxeof(sc)
-	struct rtk_softc	*sc;
+rtk_rxeof(struct rtk_softc *sc)
 {
-        struct mbuf		*m;
-        struct ifnet		*ifp;
-	caddr_t			rxbufpos, dst;
-	u_int			total_len, wrap = 0;
-	u_int32_t		rxstat;
-	u_int16_t		cur_rx, new_rx;
-	u_int16_t		limit;
-	u_int16_t		rx_bytes = 0, max_bytes;
+	struct mbuf *m;
+	struct ifnet *ifp;
+	caddr_t rxbufpos, dst;
+	u_int total_len, wrap;
+	uint32_t rxstat;
+	uint16_t cur_rx, new_rx;
+	uint16_t limit;
+	uint16_t rx_bytes, max_bytes;
 
 	ifp = &sc->ethercom.ec_if;
 
@@ -1017,12 +1003,13 @@
 		max_bytes = (RTK_RXBUFLEN - cur_rx) + limit;
 	else
 		max_bytes = limit - cur_rx;
+	rx_bytes = 0;
 
-	while((CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_EMPTY_RXBUF) == 0) {
+	while ((CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_EMPTY_RXBUF) == 0) {
 		rxbufpos = sc->rtk_rx_buf + cur_rx;
 		bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx,
 		    RTK_RXSTAT_LEN, BUS_DMASYNC_POSTREAD);
-		rxstat = le32toh(*(u_int32_t *)rxbufpos);
+		rxstat = le32toh(*(uint32_t *)rxbufpos);
 		bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx,
 		    RTK_RXSTAT_LEN, BUS_DMASYNC_PREREAD);
 
@@ -1039,7 +1026,8 @@
 			break;
 
 		if ((rxstat & RTK_RXSTAT_RXOK) == 0 ||
-		    total_len > ETHER_MAX_LEN) {
+		    total_len < ETHER_MIN_LEN ||
+		    total_len > (MCLBYTES - RTK_ETHER_ALIGN)) {
 			ifp->if_ierrors++;
 
 			/*
@@ -1099,7 +1087,13 @@
 		else
 			new_rx = cur_rx + total_len;
 		/* Round up to 32-bit boundary. */
-		new_rx = (new_rx + 3) & ~3;
+		new_rx = ((new_rx + 3) & ~3) % RTK_RXBUFLEN;
+
+		/*
+		 * The RealTek chip includes the CRC with every
+		 * incoming packet; trim it off here.
+		 */
+		total_len -= ETHER_CRC_LEN;
 
 		/*
 		 * Now allocate an mbuf (and possibly a cluster) to hold
@@ -1154,18 +1148,12 @@
 		    cur_rx, total_len, BUS_DMASYNC_PREREAD);
 
  next_packet:
-		CSR_WRITE_2(sc, RTK_CURRXADDR, new_rx - 16);
+		CSR_WRITE_2(sc, RTK_CURRXADDR, (new_rx - 16) % RTK_RXBUFLEN);
 		cur_rx = new_rx;
 
 		if (m == NULL)
 			continue;
 
-		/*
-		 * The RealTek chip includes the CRC with every
-		 * incoming packet.
-		 */
-		m->m_flags |= M_HASFCS;
-
 		ifp->if_ipackets++;
 
 #if NBPFILTER > 0
@@ -1182,18 +1170,14 @@
  * the list buffers.
  */
 STATIC void
-rtk_txeof(sc)
-	struct rtk_softc	*sc;
+rtk_txeof(struct rtk_softc *sc)
 {
 	struct ifnet *ifp;
 	struct rtk_tx_desc *txd;
-	u_int32_t txstat;
+	uint32_t txstat;
 
 	ifp = &sc->ethercom.ec_if;
 
-	/* Clear the timeout timer. */
-	ifp->if_timer = 0;
-
 	/*
 	 * Go through our tx list and free mbufs for those
 	 * frames that have been uploaded.
@@ -1224,12 +1208,16 @@
 			 * Increase step 64 bytes.
 			 */
 			if (txstat & RTK_TXSTAT_TX_UNDERRUN) {
+#ifdef DEBUG
 				printf("%s: transmit underrun;",
 				    sc->sc_dev.dv_xname);
-				if (sc->sc_txthresh < TXTH_MAX) {
+#endif
+				if (sc->sc_txthresh < RTK_TXTH_MAX) {
 					sc->sc_txthresh += 2;
+#ifdef DEBUG
 					printf(" new threshold: %d bytes",
 					    sc->sc_txthresh * 32);
+#endif
 				}
 				printf("\n");
 			}
@@ -1239,16 +1227,20 @@
 		SIMPLEQ_INSERT_TAIL(&sc->rtk_tx_free, txd, txd_q);
 		ifp->if_flags &= ~IFF_OACTIVE;
 	}
+
+	/* Clear the timeout timer if there is no pending packet. */
+	if (SIMPLEQ_EMPTY(&sc->rtk_tx_dirty))
+		ifp->if_timer = 0;
+
 }
 
 int
-rtk_intr(arg)
-	void			*arg;
+rtk_intr(void *arg)
 {
-	struct rtk_softc	*sc;
-	struct ifnet		*ifp;
-	u_int16_t		status;
-	int handled = 0;
+	struct rtk_softc *sc;
+	struct ifnet *ifp;
+	uint16_t status;
+	int handled;
 
 	sc = arg;
 	ifp = &sc->ethercom.ec_if;
@@ -1256,17 +1248,18 @@
 	/* Disable interrupts. */
 	CSR_WRITE_2(sc, RTK_IMR, 0x0000);
 
+	handled = 0;
 	for (;;) {
 
 		status = CSR_READ_2(sc, RTK_ISR);
 		if (status)
 			CSR_WRITE_2(sc, RTK_ISR, status);
 
-		handled = 1;
-
 		if ((status & RTK_INTRS) == 0)
 			break;
 
+		handled = 1;
+
 		if (status & RTK_ISR_RX_OK)
 			rtk_rxeof(sc);
 
@@ -1293,7 +1286,7 @@
 		rnd_add_uint32(&sc->rnd_source, status);
 #endif
 
-	return (handled);
+	return handled;
 }
 
 /*
@@ -1301,12 +1294,11 @@
  */
 
 STATIC void
-rtk_start(ifp)
-	struct ifnet		*ifp;
+rtk_start(struct ifnet *ifp)
 {
 	struct rtk_softc *sc;
 	struct rtk_tx_desc *txd;
-	struct mbuf *m_head = NULL, *m_new;
+	struct mbuf *m_head, *m_new;
 	int error, len;
 
 	sc = ifp->if_softc;
@@ -1383,7 +1375,7 @@
 
 		/*
 		 * Transmit the frame.
-	 	 */
+		 */
 		bus_dmamap_sync(sc->sc_dmat,
 		    txd->txd_dmamap, 0, txd->txd_dmamap->dm_mapsize,
 		    BUS_DMASYNC_PREWRITE);
@@ -1392,7 +1384,13 @@
 
 		CSR_WRITE_4(sc, txd->txd_txaddr,
 		    txd->txd_dmamap->dm_segs[0].ds_addr);
-		CSR_WRITE_4(sc, txd->txd_txstat, RTK_TX_THRESH(sc) | len);
+		CSR_WRITE_4(sc, txd->txd_txstat,
+		    RTK_TXSTAT_THRESH(sc->sc_txthresh) | len);
+
+		/*
+		 * Set a timeout in case the chip goes out to lunch.
+		 */
+		ifp->if_timer = 5;
 	}
 
 	/*
@@ -1402,20 +1400,14 @@
 	 */
 	if (SIMPLEQ_EMPTY(&sc->rtk_tx_free))
 		ifp->if_flags |= IFF_OACTIVE;
-
-	/*
-	 * Set a timeout in case the chip goes out to lunch.
-	 */
-	ifp->if_timer = 5;
 }
 
 STATIC int
-rtk_init(ifp)
-	struct ifnet *ifp;
+rtk_init(struct ifnet *ifp)
 {
-	struct rtk_softc	*sc = ifp->if_softc;
-	int			error = 0, i;
-	u_int32_t		rxcfg;
+	struct rtk_softc *sc = ifp->if_softc;
+	int error, i;
+	uint32_t rxcfg;
 
 	if ((error = rtk_enable(sc)) != 0)
 		goto out;
@@ -1439,7 +1431,7 @@
 	rtk_list_tx_init(sc);
 
 	/* Init Early TX threshold. */
-	sc->sc_txthresh = TXTH_256;
+	sc->sc_txthresh = RTK_TXTH_256;
 	/*
 	 * Enable transmit and receive.
 	 */
@@ -1509,32 +1501,29 @@
 		ifp->if_timer = 0;
 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
 	}
-	return (error);
+	return error;
 }
 
 /*
  * Set media options.
  */
 STATIC int
-rtk_ifmedia_upd(ifp)
-	struct ifnet		*ifp;
+rtk_ifmedia_upd(struct ifnet *ifp)
 {
-	struct rtk_softc	*sc;
+	struct rtk_softc *sc;
 
 	sc = ifp->if_softc;
 
-	return (mii_mediachg(&sc->mii));
+	return mii_mediachg(&sc->mii);
 }
 
 /*
  * Report current media status.
  */
 STATIC void
-rtk_ifmedia_sts(ifp, ifmr)
-	struct ifnet		*ifp;
-	struct ifmediareq	*ifmr;
+rtk_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
-	struct rtk_softc	*sc;
+	struct rtk_softc *sc;
 
 	sc = ifp->if_softc;
 
@@ -1544,14 +1533,11 @@
 }
 
 STATIC int
-rtk_ioctl(ifp, command, data)
-	struct ifnet		*ifp;
-	u_long			command;
-	caddr_t			data;
-{
-	struct rtk_softc	*sc = ifp->if_softc;
-	struct ifreq		*ifr = (struct ifreq *) data;
-	int			s, error = 0;
+rtk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+	struct rtk_softc *sc = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *)data;
+	int s, error;
 
 	s = splnet();
 
@@ -1578,14 +1564,13 @@
 
 	splx(s);
 
-	return (error);
+	return error;
 }
 
 STATIC void
-rtk_watchdog(ifp)
-	struct ifnet		*ifp;
+rtk_watchdog(struct ifnet *ifp)
 {
-	struct rtk_softc	*sc;
+	struct rtk_softc *sc;
 
 	sc = ifp->if_softc;
 
@@ -1601,9 +1586,7 @@
  * RX and TX lists.
  */
 STATIC void
-rtk_stop(ifp, disable)
-	struct ifnet *ifp;
-	int disable;
+rtk_stop(struct ifnet *ifp, int disable)
 {
 	struct rtk_softc *sc = ifp->if_softc;
 	struct rtk_tx_desc *txd;
@@ -1638,21 +1621,20 @@
  * get confused by errant DMAs when rebooting.
  */
 STATIC void
-rtk_shutdown(vsc)
-	void			*vsc;
+rtk_shutdown(void *arg)
 {
-	struct rtk_softc	*sc = (struct rtk_softc *)vsc;
+	struct rtk_softc *sc = (struct rtk_softc *)arg;
 
 	rtk_stop(&sc->ethercom.ec_if, 0);
 }
 
 STATIC void
-rtk_tick(arg)
-	void *arg;
+rtk_tick(void *arg)
 {
 	struct rtk_softc *sc = arg;
-	int s = splnet();
+	int s;
 
+	s = splnet();
 	mii_tick(&sc->mii);
 	splx(s);
 
Index: dev/ic/rtl81x9reg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/rtl81x9reg.h,v
retrieving revision 1.11.2.2
diff -u -r1.11.2.2 rtl81x9reg.h
--- dev/ic/rtl81x9reg.h	29 Dec 2005 19:44:18 -0000	1.11.2.2
+++ dev/ic/rtl81x9reg.h	11 Feb 2007 03:42:01 -0000
@@ -37,7 +37,7 @@
 /*
  * RealTek 8129/8139 register offsets
  */
-#define	RTK_IDR0	0x0000		/* ID register 0 (station addr) */
+#define RTK_IDR0	0x0000		/* ID register 0 (station addr) */
 #define RTK_IDR1	0x0001		/* Must use 32-bit accesses (?) */
 #define RTK_IDR2	0x0002
 #define RTK_IDR3	0x0003
@@ -123,14 +123,17 @@
 /*
  * Registers specific to the 8169 gigE chip
  */
+#define RTK_GTXSTART		0x0038	/* 16 bits */
 #define RTK_TIMERINT_8169	0x0058	/* different offset than 8139 */
 #define RTK_PHYAR		0x0060
 #define RTK_TBICSR		0x0064
 #define RTK_TBI_ANAR		0x0068
 #define RTK_TBI_LPAR		0x006A
 #define RTK_GMEDIASTAT		0x006C	/* 8 bits */
+#define RTK_LDPS		0x0082	/* Link Down Power Saving */
 #define RTK_MAXRXPKTLEN		0x00DA	/* 16 bits, chip multiplies by 8 */
-#define RTK_GTXSTART		0x0038	/* 16 bits */
+#define RTK_IM			0x00E2
+
 /*
  * TX config register bits
  */
@@ -146,10 +149,17 @@
 #define RTK_LOOPTEST_ON		0x00020000
 #define RTK_LOOPTEST_ON_CPLUS	0x00060000
 
+/* Known revision codes. */
 #define RTK_HWREV_8169		0x00000000
-#define RTK_HWREV_8169S		0x04000000
-#define RTK_HWREV_8169SB	0x10000000
 #define RTK_HWREV_8110S		0x00800000
+#define RTK_HWREV_8169S		0x04000000
+#define RTK_HWREV_8169_8110SB	0x10000000
+#define RTK_HWREV_8169_8110SC	0x18000000
+#define RTK_HWREV_8168_SPIN1	0x30000000
+#define RTK_HWREV_8100E		0x30800000
+#define RTK_HWREV_8101E		0x34000000
+#define RTK_HWREV_8168_SPIN2	0x38000000
+#define RTK_HWREV_8100E_SPIN2	0x38800000
 #define RTK_HWREV_8139		0x60000000
 #define RTK_HWREV_8139A		0x70000000
 #define RTK_HWREV_8139AG	0x70800000
@@ -184,6 +194,10 @@
 #define RTK_TXSTAT_TXABRT	0x40000000
 #define RTK_TXSTAT_CARRLOSS	0x80000000
 
+#define RTK_TXSTAT_THRESH(x)	(((x) << 16) & RTK_TXSTAT_EARLY_THRESH) 
+#define RTK_TXTH_256		8	/* (x) * 32 bytes */
+#define RTK_TXTH_1536		48
+
 /*
  * Interrupt status register bits.
  */
@@ -251,6 +265,7 @@
 #define RTK_RXBUF_16		0x00000800
 #define RTK_RXBUF_32		0x00001000
 #define RTK_RXBUF_64		0x00001800
+#define RTK_RXBUF_LEN(x)	(1 << (((x) >> 11) + 13))
 
 #define RTK_RXFIFO_16BYTES	0x00000000
 #define RTK_RXFIFO_32BYTES	0x00002000
@@ -409,28 +424,7 @@
 #define RTK_GMEDIASTAT_TXFLOW	0x40	/* TX flow control on */
 #define RTK_GMEDIASTAT_TBI	0x80	/* TBI enabled */
 
-/*
- * The RealTek doesn't use a fragment-based descriptor mechanism.
- * Instead, there are only four register sets, each or which represents
- * one 'descriptor.' Basically, each TX descriptor is just a contiguous
- * packet buffer (32-bit aligned!) and we place the buffer addresses in
- * the registers so the chip knows where they are.
- *
- * We can sort of kludge together the same kind of buffer management
- * used in previous drivers, but we have to do buffer copies almost all
- * the time, so it doesn't really buy us much.
- *
- * For reception, there's just one large buffer where the chip stores
- * all received packets.
- */
 
-#ifdef dreamcast
-#define	RTK_RX_BUF_SZ		RTK_RXBUF_16
-#else
-#define RTK_RX_BUF_SZ		RTK_RXBUF_64
-#endif
-#define RTK_RXBUFLEN		(1 << ((RTK_RX_BUF_SZ >> 11) + 13))
-#define RTK_TX_LIST_CNT		4
 #define RTK_TX_EARLYTHRESH	((256 / 32) << 16)
 #define RTK_RX_FIFOTHRESH	RTK_RXFIFO_256BYTES
 #define RTK_RX_MAXDMA		RTK_RXDMA_256BYTES
@@ -439,13 +433,12 @@
 #define RTK_RXCFG_CONFIG 	(RTK_RX_FIFOTHRESH|RTK_RX_MAXDMA|RTK_RX_BUF_SZ)
 #define RTK_TXCFG_CONFIG	(RTK_TXCFG_IFG|RTK_TX_MAXDMA)
 
+#define RE_RX_FIFOTHRESH	RTK_RXFIFO_NOTHRESH
+#define RE_RX_MAXDMA		RTK_RXDMA_UNLIMITED
+#define RE_TX_MAXDMA		RTK_TXDMA_2048BYTES
 
-/*
- * The 8139C+ and 8160 gigE chips support descriptor-based TX
- * and RX. In fact, they even support TCP large send. Descriptors
- * must be allocated in contiguous blocks that are aligned on a
- * 256-byte boundary. The rings can hold a maximum of 64 descriptors.
- */
+#define RE_RXCFG_CONFIG		(RE_RX_FIFOTHRESH|RE_RX_MAXDMA|RTK_RX_BUF_SZ)
+#define RE_TXCFG_CONFIG		(RTK_TXCFG_IFG|RE_TX_MAXDMA)
 
 /*
  * RX/TX descriptor definition. When large send mode is enabled, the
@@ -454,117 +447,109 @@
  * the same for RX and TX descriptors
  */
 
-struct rtk_desc {
-	u_int32_t		rtk_cmdstat;
-	u_int32_t		rtk_vlanctl;
-	u_int32_t		rtk_bufaddr_lo;
-	u_int32_t		rtk_bufaddr_hi;
+struct re_desc {
+	volatile uint32_t	re_cmdstat;
+	volatile uint32_t	re_vlanctl;
+	volatile uint32_t	re_bufaddr_lo;
+	volatile uint32_t	re_bufaddr_hi;
 };
 
-#define RTK_TDESC_CMD_FRAGLEN	0x0000FFFF
-#define RTK_TDESC_CMD_TCPCSUM	0x00010000	/* TCP checksum enable */
-#define RTK_TDESC_CMD_UDPCSUM	0x00020000	/* UDP checksum enable */
-#define RTK_TDESC_CMD_IPCSUM	0x00040000	/* IP header checksum enable */
-#define RTK_TDESC_CMD_MSSVAL	0x07FF0000	/* Large send MSS value */
-#define RTK_TDESC_CMD_MSSVAL_SHIFT 16		/* Shift of the above */
-#define RTK_TDESC_CMD_LGSEND	0x08000000	/* TCP large send enb */
-#define RTK_TDESC_CMD_EOF	0x10000000	/* end of frame marker */
-#define RTK_TDESC_CMD_SOF	0x20000000	/* start of frame marker */
-#define RTK_TDESC_CMD_EOR	0x40000000	/* end of ring marker */
-#define RTK_TDESC_CMD_OWN	0x80000000	/* chip owns descriptor */
+#define RE_TDESC_CMD_FRAGLEN	0x0000FFFF
+#define RE_TDESC_CMD_TCPCSUM	0x00010000	/* TCP checksum enable */
+#define RE_TDESC_CMD_UDPCSUM	0x00020000	/* UDP checksum enable */
+#define RE_TDESC_CMD_IPCSUM	0x00040000	/* IP header checksum enable */
+#define RE_TDESC_CMD_MSSVAL	0x07FF0000	/* Large send MSS value */
+#define RE_TDESC_CMD_MSSVAL_SHIFT 16		/* Shift of the above */
+#define RE_TDESC_CMD_LGSEND	0x08000000	/* TCP large send enb */
+#define RE_TDESC_CMD_EOF	0x10000000	/* end of frame marker */
+#define RE_TDESC_CMD_SOF	0x20000000	/* start of frame marker */
+#define RE_TDESC_CMD_EOR	0x40000000	/* end of ring marker */
+#define RE_TDESC_CMD_OWN	0x80000000	/* chip owns descriptor */
 
-#define RTK_TDESC_VLANCTL_TAG	0x00020000	/* Insert VLAN tag */
-#define RTK_TDESC_VLANCTL_DATA	0x0000FFFF	/* TAG data */
+#define RE_TDESC_VLANCTL_TAG	0x00020000	/* Insert VLAN tag */
+#define RE_TDESC_VLANCTL_DATA	0x0000FFFF	/* TAG data */
 
 /*
  * Error bits are valid only on the last descriptor of a frame
- * (i.e. RTK_TDESC_CMD_EOF == 1)
+ * (i.e. RE_TDESC_CMD_EOF == 1)
  */
 
-#define RTK_TDESC_STAT_COLCNT	0x000F0000	/* collision count */
-#define RTK_TDESC_STAT_EXCESSCOL	0x00100000	/* excessive collisions */
-#define RTK_TDESC_STAT_LINKFAIL	0x00200000	/* link faulure */
-#define RTK_TDESC_STAT_OWINCOL	0x00400000	/* out-of-window collision */
-#define RTK_TDESC_STAT_TXERRSUM	0x00800000	/* transmit error summary */
-#define RTK_TDESC_STAT_UNDERRUN	0x02000000	/* TX underrun occurred */
-#define RTK_TDESC_STAT_OWN	0x80000000
+#define RE_TDESC_STAT_COLCNT	0x000F0000	/* collision count */
+#define RE_TDESC_STAT_EXCESSCOL	0x00100000	/* excessive collisions */
+#define RE_TDESC_STAT_LINKFAIL	0x00200000	/* link faulure */
+#define RE_TDESC_STAT_OWINCOL	0x00400000	/* out-of-window collision */
+#define RE_TDESC_STAT_TXERRSUM	0x00800000	/* transmit error summary */
+#define RE_TDESC_STAT_UNDERRUN	0x02000000	/* TX underrun occurred */
+#define RE_TDESC_STAT_OWN	0x80000000
 
 /*
  * RX descriptor cmd/vlan definitions
  */
 
-#define RTK_RDESC_CMD_EOR	0x40000000
-#define RTK_RDESC_CMD_OWN	0x80000000
-#define RTK_RDESC_CMD_BUFLEN	0x00001FFF
-
-#define RTK_RDESC_STAT_OWN	0x80000000
-#define RTK_RDESC_STAT_EOR	0x40000000
-#define RTK_RDESC_STAT_SOF	0x20000000
-#define RTK_RDESC_STAT_EOF	0x10000000
-#define RTK_RDESC_STAT_FRALIGN	0x08000000	/* frame alignment error */
-#define RTK_RDESC_STAT_MCAST	0x04000000	/* multicast pkt received */
-#define RTK_RDESC_STAT_UCAST	0x02000000	/* unicast pkt received */
-#define RTK_RDESC_STAT_BCAST	0x01000000	/* broadcast pkt received */
-#define RTK_RDESC_STAT_BUFOFLOW	0x00800000	/* out of buffer space */
-#define RTK_RDESC_STAT_FIFOOFLOW	0x00400000	/* FIFO overrun */
-#define RTK_RDESC_STAT_GIANT	0x00200000	/* pkt > 4096 bytes */
-#define RTK_RDESC_STAT_RXERRSUM	0x00100000	/* RX error summary */
-#define RTK_RDESC_STAT_RUNT	0x00080000	/* runt packet received */
-#define RTK_RDESC_STAT_CRCERR	0x00040000	/* CRC error */
-#define RTK_RDESC_STAT_PROTOID	0x00030000	/* Protocol type */
-#define RTK_RDESC_STAT_IPSUMBAD	0x00008000	/* IP header checksum bad */
-#define RTK_RDESC_STAT_UDPSUMBAD	0x00004000	/* UDP checksum bad */
-#define RTK_RDESC_STAT_TCPSUMBAD	0x00002000	/* TCP checksum bad */
-#define RTK_RDESC_STAT_FRAGLEN	0x00001FFF	/* RX'ed frame/frag len */
-#define RTK_RDESC_STAT_GFRAGLEN	0x00003FFF	/* RX'ed frame/frag len */
-
-#define RTK_RDESC_VLANCTL_TAG	0x00010000	/* VLAN tag available
-						   (rtk_vlandata valid)*/
-#define RTK_RDESC_VLANCTL_DATA	0x0000FFFF	/* TAG data */
-
-#define RTK_PROTOID_NONIP	0x00000000
-#define RTK_PROTOID_TCPIP	0x00010000
-#define RTK_PROTOID_UDPIP	0x00020000
-#define RTK_PROTOID_IP		0x00030000
-#define RTK_TCPPKT(x)		(((x) & RTK_RDESC_STAT_PROTOID) == \
-				 RTK_PROTOID_TCPIP)
-#define RTK_UDPPKT(x)		(((x) & RTK_RDESC_STAT_PROTOID) == \
-				 RTK_PROTOID_UDPIP)
+#define RE_RDESC_CMD_EOR	0x40000000
+#define RE_RDESC_CMD_OWN	0x80000000
+#define RE_RDESC_CMD_BUFLEN	0x00001FFF
+
+#define RE_RDESC_STAT_OWN	0x80000000
+#define RE_RDESC_STAT_EOR	0x40000000
+#define RE_RDESC_STAT_SOF	0x20000000
+#define RE_RDESC_STAT_EOF	0x10000000
+#define RE_RDESC_STAT_FRALIGN	0x08000000	/* frame alignment error */
+#define RE_RDESC_STAT_MCAST	0x04000000	/* multicast pkt received */
+#define RE_RDESC_STAT_UCAST	0x02000000	/* unicast pkt received */
+#define RE_RDESC_STAT_BCAST	0x01000000	/* broadcast pkt received */
+#define RE_RDESC_STAT_BUFOFLOW	0x00800000	/* out of buffer space */
+#define RE_RDESC_STAT_FIFOOFLOW	0x00400000	/* FIFO overrun */
+#define RE_RDESC_STAT_GIANT	0x00200000	/* pkt > 4096 bytes */
+#define RE_RDESC_STAT_RXERRSUM	0x00100000	/* RX error summary */
+#define RE_RDESC_STAT_RUNT	0x00080000	/* runt packet received */
+#define RE_RDESC_STAT_CRCERR	0x00040000	/* CRC error */
+#define RE_RDESC_STAT_PROTOID	0x00030000	/* Protocol type */
+#define RE_RDESC_STAT_IPSUMBAD	0x00008000	/* IP header checksum bad */
+#define RE_RDESC_STAT_UDPSUMBAD	0x00004000	/* UDP checksum bad */
+#define RE_RDESC_STAT_TCPSUMBAD	0x00002000	/* TCP checksum bad */
+#define RE_RDESC_STAT_FRAGLEN	0x00001FFF	/* RX'ed frame/frag len */
+#define RE_RDESC_STAT_GFRAGLEN	0x00003FFF	/* RX'ed frame/frag len */
+
+#define RE_RDESC_VLANCTL_TAG	0x00010000	/* VLAN tag available
+						   (re_vlandata valid)*/
+#define RE_RDESC_VLANCTL_DATA	0x0000FFFF	/* TAG data */
+
+#define RE_PROTOID_NONIP	0x00000000
+#define RE_PROTOID_TCPIP	0x00010000
+#define RE_PROTOID_UDPIP	0x00020000
+#define RE_PROTOID_IP		0x00030000
+#define RE_TCPPKT(x)		(((x) & RE_RDESC_STAT_PROTOID) == \
+				 RE_PROTOID_TCPIP)
+#define RE_UDPPKT(x)		(((x) & RE_RDESC_STAT_PROTOID) == \
+				 RE_PROTOID_UDPIP)
+
+#define RE_ADDR_LO(y)		((uint64_t)(y) & 0xFFFFFFFF)
+#define RE_ADDR_HI(y)		((uint64_t)(y) >> 32)
 
 /*
  * Statistics counter structure (8139C+ and 8169 only)
  */
-struct rtk_stats {
-	u_int32_t		rtk_tx_pkts_lo;
-	u_int32_t		rtk_tx_pkts_hi;
-	u_int32_t		rtk_tx_errs_lo;
-	u_int32_t		rtk_tx_errs_hi;
-	u_int32_t		rtk_tx_errs;
-	u_int16_t		rtk_missed_pkts;
-	u_int16_t		rtk_rx_framealign_errs;
-	u_int32_t		rtk_tx_onecoll;
-	u_int32_t		rtk_tx_multicolls;
-	u_int32_t		rtk_rx_ucasts_hi;
-	u_int32_t		rtk_rx_ucasts_lo;
-	u_int32_t		rtk_rx_bcasts_lo;
-	u_int32_t		rtk_rx_bcasts_hi;
-	u_int32_t		rtk_rx_mcasts;
-	u_int16_t		rtk_tx_aborts;
-	u_int16_t		rtk_rx_underruns;
+struct re_stats {
+	uint32_t		re_tx_pkts_lo;
+	uint32_t		re_tx_pkts_hi;
+	uint32_t		re_tx_errs_lo;
+	uint32_t		re_tx_errs_hi;
+	uint32_t		re_tx_errs;
+	uint16_t		re_missed_pkts;
+	uint16_t		re_rx_framealign_errs;
+	uint32_t		re_tx_onecoll;
+	uint32_t		re_tx_multicolls;
+	uint32_t		re_rx_ucasts_hi;
+	uint32_t		re_rx_ucasts_lo;
+	uint32_t		re_rx_bcasts_lo;
+	uint32_t		re_rx_bcasts_hi;
+	uint32_t		re_rx_mcasts;
+	uint16_t		re_tx_aborts;
+	uint16_t		re_rx_underruns;
 };
 
-#define RTK_RX_DESC_CNT		64
-#define RTK_TX_DESC_CNT_8139	64
-#define RTK_TX_DESC_CNT_8169	1024
-#define RTK_RX_LIST_SZ		(RTK_RX_DESC_CNT * sizeof(struct rtk_desc))
-#define RTK_RING_ALIGN		256
-#define RTK_IFQ_MAXLEN		512
-#define RTK_OWN(x)		(le32toh((x)->rtk_cmdstat) & RTK_RDESC_STAT_OWN)
-#define RTK_RXBYTES(x)		(le32toh((x)->rtk_cmdstat) & sc->rtk_rxlenmask)
-#define RTK_PKTSZ(x)		((x)/* >> 3*/)
-
-#define RTK_ADDR_LO(y)	((u_int64_t) (y) & 0xFFFFFFFF)
-#define RTK_ADDR_HI(y)	((u_int64_t) (y) >> 32)
+#define RE_IFQ_MAXLEN		512
 
-#define RTK_JUMBO_FRAMELEN	9018
-#define RTK_JUMBO_MTU		(RTK_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define RE_JUMBO_FRAMELEN	9018
+#define RE_JUMBO_MTU		(RE_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
Index: dev/ic/rtl81x9var.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/rtl81x9var.h,v
retrieving revision 1.17.4.1
diff -u -r1.17.4.1 rtl81x9var.h
--- dev/ic/rtl81x9var.h	4 Apr 2005 17:23:57 -0000	1.17.4.1
+++ dev/ic/rtl81x9var.h	11 Feb 2007 03:42:01 -0000
@@ -43,9 +43,20 @@
 #define RTK_ETHER_ALIGN	2
 #define RTK_RXSTAT_LEN	4
 
+#ifdef __NO_STRICT_ALIGNMENT
+/*
+ * XXX According to PR kern/33763, some 8168 and variants can't DMA
+ * XXX RX packet data into unaligned buffer. This means such chips will
+ * XXX never work on !__NO_STRICT_ALIGNMENT hosts without copying buffer.
+ */
+#define RE_ETHER_ALIGN	0
+#else
+#define RE_ETHER_ALIGN	2
+#endif
+
 struct rtk_type {
-	u_int16_t		rtk_vid;
-	u_int16_t		rtk_did;
+	uint16_t		rtk_vid;
+	uint16_t		rtk_did;
 	int			rtk_basetype;
 	const char		*rtk_name;
 };
@@ -53,16 +64,25 @@
 struct rtk_hwrev {
 	uint32_t		rtk_rev;
 	int			rtk_type;
-	char			*rtk_desc;
+	const char		*rtk_desc;
 };
 
+#define RTK_8129		1
+#define RTK_8139		2
+#define RTK_8139CPLUS		3
+#define RTK_8169		4
+
+#define RTK_ISCPLUS(x)	((x)->rtk_type == RTK_8139CPLUS || \
+			 (x)->rtk_type == RTK_8169)
+
+
 struct rtk_mii_frame {
-	u_int8_t		mii_stdelim;
-	u_int8_t		mii_opcode;
-	u_int8_t		mii_phyaddr;
-	u_int8_t		mii_regaddr;
-	u_int8_t		mii_turnaround;
-	u_int16_t		mii_data;
+	uint8_t			mii_stdelim;
+	uint8_t			mii_opcode;
+	uint8_t			mii_phyaddr;
+	uint8_t			mii_regaddr;
+	uint8_t			mii_turnaround;
+	uint16_t		mii_data;
 };
 
 /*
@@ -73,47 +93,90 @@
 #define RTK_MII_WRITEOP		0x01
 #define RTK_MII_TURNAROUND	0x02
 
-#define RTK_8129		1
-#define RTK_8139		2
-#define RTK_8139CPLUS		3
-#define RTK_8169		4
 
-#define RTK_ISCPLUS(x)	((x)->rtk_type == RTK_8139CPLUS || \
-			 (x)->rtk_type == RTK_8169)
+/*
+ * The RealTek doesn't use a fragment-based descriptor mechanism.
+ * Instead, there are only four register sets, each or which represents
+ * one 'descriptor.' Basically, each TX descriptor is just a contiguous
+ * packet buffer (32-bit aligned!) and we place the buffer addresses in
+ * the registers so the chip knows where they are. 
+ * 
+ * We can sort of kludge together the same kind of buffer management
+ * used in previous drivers, but we have to do buffer copies almost all
+ * the time, so it doesn't really buy us much.
+ * 
+ * For reception, there's just one large buffer where the chip stores
+ * all received packets.
+ */
 
-#define RTK_TX_QLEN		64
+#ifdef dreamcast
+/*
+ * XXX dreamcast has only 32KB DMA'able memory on its PCI bridge.
+ * XXX Maybe this should be handled by prop_dictionary, or
+ * XXX some other new API which returns available DMA resources.
+ */
+#define RTK_RX_BUF_SZ		RTK_RXBUF_16
+#else
+#define RTK_RX_BUF_SZ		RTK_RXBUF_64
+#endif
+#define RTK_RXBUFLEN		RTK_RXBUF_LEN(RTK_RX_BUF_SZ)
+#define RTK_TX_LIST_CNT		4
 
 /*
- * The 8139C+ and 8160 gigE chips support descriptor-based TX
+ * The 8139C+ and 8169 gigE chips support descriptor-based TX
  * and RX. In fact, they even support TCP large send. Descriptors
  * must be allocated in contiguous blocks that are aligned on a
- * 256-byte boundary. The rings can hold a maximum of 64 descriptors.
+ * 256-byte boundary. The RX rings can hold a maximum of 64 descriptors.
+ * The TX rings can hold upto 64 descriptors on 8139C+, and
+ * 1024 descriptors on 8169 gigE chips.
+ */
+#define RE_RING_ALIGN		256
+
+/*
+ * Size of descriptors and TX queue.
+ * These numbers must be power of two to simplify RE_NEXT_*() macro.
  */
+#define RE_RX_DESC_CNT		64
+#define RE_TX_DESC_CNT_8139	64
+#define RE_TX_DESC_CNT_8169	1024
+#define RE_TX_QLEN		64
+
+#define RE_NTXDESC_RSVD		4
+
+struct re_rxsoft {
+	struct mbuf		*rxs_mbuf;
+	bus_dmamap_t		rxs_dmamap;
+};
 
-struct rtk_list_data {
-	struct rtk_txq {
-		struct mbuf *txq_mbuf;
-		bus_dmamap_t txq_dmamap;
-		int txq_descidx;
-	} rtk_txq[RTK_TX_QLEN];
-	int			rtk_txq_considx;
-	int			rtk_txq_prodidx;
-	bus_dmamap_t		rtk_tx_list_map;
-	struct rtk_desc		*rtk_tx_list;
-	bus_dma_segment_t 	rtk_tx_listseg;
-	int			rtk_tx_free;	/* # of free descriptors */
-	int			rtk_tx_nextfree; /* next descriptor to use */
-	int			rtk_tx_desc_cnt; /* # of descriptors */
-	int			rtk_tx_listnseg;
-
-	struct mbuf		*rtk_rx_mbuf[RTK_RX_DESC_CNT];
-	bus_dmamap_t		rtk_rx_dmamap[RTK_RX_DESC_CNT];
-	bus_dmamap_t		rtk_rx_list_map;
-	struct rtk_desc		*rtk_rx_list;
-	bus_dma_segment_t 	rtk_rx_listseg;
-	int			rtk_rx_prodidx;
-	int			rtk_rx_listnseg;
+struct re_txq {
+	struct mbuf *txq_mbuf;
+	bus_dmamap_t txq_dmamap;
+	int txq_descidx;
+	int txq_nsegs;
 };
+
+struct re_list_data {
+	struct re_txq		re_txq[RE_TX_QLEN];
+	int			re_txq_considx;
+	int			re_txq_prodidx;
+	int			re_txq_free;
+
+	bus_dmamap_t		re_tx_list_map;
+	struct re_desc		*re_tx_list;
+	int			re_tx_free;	/* # of free descriptors */
+	int			re_tx_nextfree; /* next descriptor to use */
+	int			re_tx_desc_cnt; /* # of descriptors */
+	bus_dma_segment_t 	re_tx_listseg;
+	int			re_tx_listnseg;
+
+	struct re_rxsoft	re_rxsoft[RE_RX_DESC_CNT];
+	bus_dmamap_t		re_rx_list_map;
+	struct re_desc		*re_rx_list;
+	int			re_rx_prodidx;
+	bus_dma_segment_t 	re_rx_listseg;
+	int			re_rx_listnseg;
+};
+
 struct rtk_tx_desc {
 	SIMPLEQ_ENTRY(rtk_tx_desc) txd_q;
 	struct mbuf		*txd_mbuf;
@@ -131,20 +194,22 @@
 	bus_space_tag_t		rtk_btag;	/* bus space tag */
 	int			rtk_type;
 	bus_dma_tag_t 		sc_dmat;
-	bus_dma_segment_t 	sc_dmaseg;
-	int			sc_dmanseg;
 
-	bus_dmamap_t 		recv_dmamap;
+	bus_dma_segment_t 	sc_dmaseg;	/* for rtk(4) */
+	int			sc_dmanseg;	/* for rtk(4) */
+
+	bus_dmamap_t 		recv_dmamap;	/* for rtk(4) */
 	caddr_t			rtk_rx_buf;
 
 	struct rtk_tx_desc	rtk_tx_descs[RTK_TX_LIST_CNT];
 	SIMPLEQ_HEAD(, rtk_tx_desc) rtk_tx_free;
 	SIMPLEQ_HEAD(, rtk_tx_desc) rtk_tx_dirty;
-	struct rtk_list_data	rtk_ldata;
-	struct mbuf		*rtk_head;
-	struct mbuf		*rtk_tail;
-	u_int32_t		rtk_rxlenmask;
-	int			rtk_testmode;
+
+	struct re_list_data	re_ldata;
+	struct mbuf		*re_head;
+	struct mbuf		*re_tail;
+	uint32_t		re_rxlenmask;
+	int			re_testmode;
 
 	int			sc_flags;	/* misc flags */
 	int			sc_txthresh;	/* Early tx threshold */
@@ -162,23 +227,51 @@
 #endif
 };
 
-#define	RTK_TX_DESC_CNT(sc)	\
-	((sc)->rtk_ldata.rtk_tx_desc_cnt)
-#define	RTK_TX_LIST_SZ(sc)	\
-	(RTK_TX_DESC_CNT(sc) * sizeof(struct rtk_desc))
-#define	RTK_TX_DESC_INC(sc, x)	\
-	((x) = ((x) + 1) % RTK_TX_DESC_CNT(sc))
-#define	RTK_RX_DESC_INC(sc, x)	\
-	((x) = ((x) + 1) % RTK_RX_DESC_CNT)
+#define RE_TX_DESC_CNT(sc)	((sc)->re_ldata.re_tx_desc_cnt)
+#define RE_TX_LIST_SZ(sc)	(RE_TX_DESC_CNT(sc) * sizeof(struct re_desc))
+#define RE_NEXT_TX_DESC(sc, x)	(((x) + 1) & (RE_TX_DESC_CNT(sc) - 1))
+
+#define RE_RX_LIST_SZ		(RE_RX_DESC_CNT * sizeof(struct re_desc))
+#define RE_NEXT_RX_DESC(sc, x)	(((x) + 1) & (RE_RX_DESC_CNT - 1))
+
+#define RE_NEXT_TXQ(sc, x)	(((x) + 1) & (RE_TX_QLEN - 1))
+
+#define RE_TXDESCSYNC(sc, idx, ops)					\
+	bus_dmamap_sync((sc)->sc_dmat,					\
+	    (sc)->re_ldata.re_tx_list_map,				\
+	    sizeof(struct re_desc) * (idx),				\
+	    sizeof(struct re_desc),					\
+	    (ops))
+#define RE_RXDESCSYNC(sc, idx, ops)					\
+	bus_dmamap_sync((sc)->sc_dmat,					\
+	    (sc)->re_ldata.re_rx_list_map,				\
+	    sizeof(struct re_desc) * (idx),				\
+	    sizeof(struct re_desc),					\
+	    (ops))
+
+/*
+ * re(4) hardware ip4csum-tx could be mangled with 28 byte or less IP packets
+ */
+#define RE_IP4CSUMTX_MINLEN	28                                
+#define RE_IP4CSUMTX_PADLEN	(ETHER_HDR_LEN + RE_IP4CSUMTX_MINLEN)
+/*
+ * XXX
+ * We are allocating pad DMA buffer after RX DMA descs for now
+ * because RE_TX_LIST_SZ(sc) always occupies whole page but
+ * RE_RX_LIST_SZ is less than PAGE_SIZE so there is some unused region.
+ */
+#define RE_RX_DMAMEM_SZ		(RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN)
+#define RE_TXPADOFF		RE_RX_LIST_SZ
+#define RE_TXPADDADDR(sc)	\
+	((sc)->re_ldata.re_rx_list_map->dm_segs[0].ds_addr + RE_TXPADOFF)
+
 
 #define RTK_ATTACHED 0x00000001 /* attach has succeeded */
 #define RTK_ENABLED  0x00000002 /* chip is enabled	*/
 
 #define RTK_IS_ENABLED(sc)	((sc)->sc_flags & RTK_ENABLED)
-#define RTK_TX_THRESH(sc)	(((sc)->sc_txthresh << 16) & 0x003F0000)
 
-#define TXTH_256	8
-#define TXTH_MAX	48
+#define RTK_TXTH_MAX	RTK_TXTH_1536
 
 /*
  * register space access macros
@@ -189,9 +282,6 @@
 	bus_space_write_2(sc->rtk_btag, sc->rtk_bhandle, reg, val)
 #define CSR_WRITE_1(sc, reg, val)	\
 	bus_space_write_1(sc->rtk_btag, sc->rtk_bhandle, reg, val)
-#define CSR_WRITE_STREAM_4(sc, reg, val)	\
-	bus_space_write_stream_4(sc->rtk_btag, sc->rtk_bhandle, reg, val)
-
 
 #define CSR_READ_4(sc, reg)		\
 	bus_space_read_4(sc->rtk_btag, sc->rtk_bhandle, reg)
@@ -203,23 +293,14 @@
 #define RTK_TIMEOUT		1000
 
 /*
- * PCI low memory base and low I/O base register, and
- * other PCI registers.
+ * PCI low memory base and low I/O base registers
  */
 
 #define RTK_PCI_LOIO		0x10
 #define RTK_PCI_LOMEM		0x14
 
-#define RTK_PSTATE_MASK		0x0003
-#define RTK_PSTATE_D0		0x0000
-#define RTK_PSTATE_D1		0x0002
-#define RTK_PSTATE_D2		0x0002
-#define RTK_PSTATE_D3		0x0003
-#define RTK_PME_EN		0x0010
-#define RTK_PME_STATUS		0x8000
-
 #ifdef _KERNEL
-u_int16_t rtk_read_eeprom(struct rtk_softc *, int, int);
+uint16_t rtk_read_eeprom(struct rtk_softc *, int, int);
 void	rtk_setmulti(struct rtk_softc *);
 void	rtk_attach(struct rtk_softc *);
 int	rtk_detach(struct rtk_softc *);
Index: dev/mii/files.mii
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/files.mii,v
retrieving revision 1.36
diff -u -r1.36 files.mii
--- dev/mii/files.mii	20 Feb 2005 16:35:56 -0000	1.36
+++ dev/mii/files.mii	11 Feb 2007 03:42:02 -0000
@@ -117,3 +117,7 @@
 device	ciphy: mii_phy
 attach	ciphy at mii
 file	dev/mii/ciphy.c				ciphy
+
+device	rlphy: mii_phy
+attach	rlphy at mii
+file	dev/mii/rlphy.c				rlphy
Index: dev/mii/miidevs
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/miidevs,v
retrieving revision 1.58.2.4
diff -u -r1.58.2.4 miidevs
--- dev/mii/miidevs	28 Apr 2006 22:23:56 -0000	1.58.2.4
+++ dev/mii/miidevs	11 Feb 2007 03:42:02 -0000
@@ -58,6 +58,7 @@
 oui CICADA			0x0003F1	Cicada Semiconductor
 oui DAVICOM			0x00606e	Davicom Semiconductor
 oui ENABLESEMI			0x0010dd	Enable Semiconductor
+oui ICPLUS			0x0090c3	IC Plus Corp.
 oui ICS				0x00a0be	Integrated Circuit Systems
 oui INTEL			0x00aa00	Intel
 oui LEVEL1			0x00207b	Level 1
@@ -99,7 +100,7 @@
 oui xxPMCSIERRA2		0x009057	PMC-Sierra
 
 oui xxREALTEK			0x000732	Realtek
-
+oui yyREALTEK			0x000004	Realtek
 /*
  * List of known models.  Grouped by oui.
  */
@@ -151,6 +152,9 @@
 model xxDAVICOM DM9101		0x0000 DM9101 (AMD Am79C873) 10/100 media interface
 model xxDAVICOM DM9102		0x0004 DM9102 10/100 media interface
 
+/* IC Plus Corp. PHYs */
+model ICPLUS IP101		0x0005 IP101 10/100 PHY
+
 /* Integrated Circuit Systems PHYs */
 model ICS 1889			0x0001 ICS1889 10/100 media interface
 model ICS 1890			0x0002 ICS1890 10/100 media interface
@@ -203,6 +207,7 @@
 model xxQUALSEMI QS6612		0x0000 QS6612 10/100 media interface
 
 /* RealTek PHYs */
+model yyREALTEK RTL8201L	0x0020 RTL8201L 10/100 media interface
 model xxREALTEK RTL8169S	0x0011 RTL8169S/8110S 1000BASE-T media interface
 model REALTEK RTL8169S		0x0011 RTL8169S/8110S 1000BASE-T media interface
 
Index: dev/mii/miidevs.h
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/miidevs.h,v
retrieving revision 1.60.2.4
diff -u -r1.60.2.4 miidevs.h
--- dev/mii/miidevs.h	28 Apr 2006 22:25:19 -0000	1.60.2.4
+++ dev/mii/miidevs.h	11 Feb 2007 03:42:02 -0000
@@ -65,6 +65,7 @@
 #define	MII_OUI_CICADA	0x0003F1	/* Cicada Semiconductor */
 #define	MII_OUI_DAVICOM	0x00606e	/* Davicom Semiconductor */
 #define	MII_OUI_ENABLESEMI	0x0010dd	/* Enable Semiconductor */
+#define	MII_OUI_ICPLUS	0x0090c3	/* IC Plus Corp. */
 #define	MII_OUI_ICS	0x00a0be	/* Integrated Circuit Systems */
 #define	MII_OUI_INTEL	0x00aa00	/* Intel */
 #define	MII_OUI_LEVEL1	0x00207b	/* Level 1 */
@@ -106,7 +107,7 @@
 #define	MII_OUI_xxPMCSIERRA2	0x009057	/* PMC-Sierra */
 
 #define	MII_OUI_xxREALTEK	0x000732	/* Realtek */
-
+#define	MII_OUI_yyREALTEK	0x000004	/* Realtek */
 /*
  * List of known models.  Grouped by oui.
  */
@@ -191,6 +192,10 @@
 #define	MII_MODEL_xxDAVICOM_DM9102	0x0004
 #define	MII_STR_xxDAVICOM_DM9102	"DM9102 10/100 media interface"
 
+/* IC Plus Corp. PHYs */
+#define	MII_MODEL_ICPLUS_IP101	0x0005
+#define	MII_STR_ICPLUS_IP101	"IP101 10/100 PHY"
+
 /* Integrated Circuit Systems PHYs */
 #define	MII_MODEL_ICS_1889	0x0001
 #define	MII_STR_ICS_1889	"ICS1889 10/100 media interface"
@@ -277,6 +282,8 @@
 #define	MII_STR_xxQUALSEMI_QS6612	"QS6612 10/100 media interface"
 
 /* RealTek PHYs */
+#define	MII_MODEL_yyREALTEK_RTL8201L	0x0020
+#define	MII_STR_yyREALTEK_RTL8201L	"RTL8201L 10/100 media interface"
 #define	MII_MODEL_xxREALTEK_RTL8169S	0x0011
 #define	MII_STR_xxREALTEK_RTL8169S	"RTL8169S/8110S 1000BASE-T media interface"
 #define	MII_MODEL_REALTEK_RTL8169S	0x0011
Index: dev/mii/miidevs_data.h
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/miidevs_data.h,v
retrieving revision 1.50.2.4
diff -u -r1.50.2.4 miidevs_data.h
--- dev/mii/miidevs_data.h	28 Apr 2006 22:25:19 -0000	1.50.2.4
+++ dev/mii/miidevs_data.h	11 Feb 2007 03:42:02 -0000
@@ -77,6 +77,7 @@
  { MII_OUI_xxCICADA, MII_MODEL_xxCICADA_CS8201B, MII_STR_xxCICADA_CS8201B },
  { MII_OUI_xxDAVICOM, MII_MODEL_xxDAVICOM_DM9101, MII_STR_xxDAVICOM_DM9101 },
  { MII_OUI_xxDAVICOM, MII_MODEL_xxDAVICOM_DM9102, MII_STR_xxDAVICOM_DM9102 },
+ { MII_OUI_ICPLUS, MII_MODEL_ICPLUS_IP101, MII_STR_ICPLUS_IP101 },
  { MII_OUI_ICS, MII_MODEL_ICS_1889, MII_STR_ICS_1889 },
  { MII_OUI_ICS, MII_MODEL_ICS_1890, MII_STR_ICS_1890 },
  { MII_OUI_ICS, MII_MODEL_ICS_1892, MII_STR_ICS_1892 },
@@ -111,6 +112,7 @@
  { MII_OUI_xxPMCSIERRA2, MII_MODEL_xxPMCSIERRA2_PM8353, MII_STR_xxPMCSIERRA2_PM8353 },
  { MII_OUI_PMCSIERRA, MII_MODEL_PMCSIERRA_PM8354, MII_STR_PMCSIERRA_PM8354 },
  { MII_OUI_xxQUALSEMI, MII_MODEL_xxQUALSEMI_QS6612, MII_STR_xxQUALSEMI_QS6612 },
+ { MII_OUI_yyREALTEK, MII_MODEL_yyREALTEK_RTL8201L, MII_STR_yyREALTEK_RTL8201L },
  { MII_OUI_xxREALTEK, MII_MODEL_xxREALTEK_RTL8169S, MII_STR_xxREALTEK_RTL8169S },
  { MII_OUI_REALTEK, MII_MODEL_REALTEK_RTL8169S, MII_STR_REALTEK_RTL8169S },
  { MII_OUI_SEEQ, MII_MODEL_SEEQ_80220, MII_STR_SEEQ_80220 },
Index: dev/mii/rgephy.c
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/rgephy.c,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 rgephy.c
--- dev/mii/rgephy.c	27 Mar 2005 16:28:40 -0000	1.5.2.1
+++ dev/mii/rgephy.c	11 Feb 2007 03:42:02 -0000
@@ -43,6 +43,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/device.h>
 #include <sys/socket.h>
 
 
@@ -70,7 +71,6 @@
 static void	rgephy_reset(struct mii_softc *);
 static void	rgephy_loop(struct mii_softc *);
 static void	rgephy_load_dspcode(struct mii_softc *);
-static int	rgephy_mii_model;
 
 static const struct mii_phy_funcs rgephy_funcs = {
 	rgephy_service, rgephy_status, rgephy_reset,
@@ -93,9 +93,9 @@
 	struct mii_attach_args *ma = aux;
 
 	if (mii_phy_match(ma, rgephys) != NULL)
-		return (10);
+		return 10;
 
-	return (0);
+	return 0;
 }
 
 static void
@@ -122,24 +122,14 @@
 
 	sc->mii_funcs = &rgephy_funcs;
 
-	/* Don't do isolate on this PHY. */
-	sc->mii_flags |= MIIF_NOISOLATE;
-
 #define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
 #define	PRINT(n)	aprint_normal("%s%s", sep, (n)); sep = ", "
 
-#if 0
-	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
-	    BMCR_ISO);
-#endif
 #ifdef __FreeBSD__
 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
 	    BMCR_LOOP|BMCR_S100);
 #endif
 
-	rgephy_mii_model = MII_MODEL(ma->mii_id2);
-	PHY_RESET(sc);
-
 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
 	sc->mii_capabilities &= ~BMSR_ANEG;
 
@@ -148,19 +138,11 @@
 	 * media explicitly. Why?
 	 */
 	aprint_normal("%s: ", sc->mii_dev.dv_xname);
-#ifdef __FreeBSD__
-	mii_phy_add_media(sc);
-	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
-	    RGEPHY_BMCR_FDX);
-	PRINT(", 1000baseTX");
-	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), 0);
-	PRINT("1000baseTX-FDX");
-#else
 	if (sc->mii_capabilities & BMSR_EXTSTAT) {
 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
 	}
 	mii_phy_add_media(sc);
-#endif
+
 	/* rtl8169S does not report auto-sense; add manually.  */
 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA);
 	sep =", ";
@@ -169,17 +151,15 @@
 #undef	ADD
 #undef	PRINT
 
+	PHY_RESET(sc);
 	aprint_normal("\n");
 }
 
 static int
-rgephy_service(sc, mii, cmd)
-	struct mii_softc *sc;
-	struct mii_data *mii;
-	int cmd;
+rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
 {
 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
-	int reg, speed, gig;
+	int reg, speed, gig, anar;
 
 	switch (cmd) {
 	case MII_POLLSTAT:
@@ -187,7 +167,7 @@
 		 * If we're not polling our PHY instance, just return.
 		 */
 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
-			return (0);
+			return 0;
 		break;
 
 	case MII_MEDIACHG:
@@ -198,7 +178,7 @@
 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
 			reg = PHY_READ(sc, MII_BMCR);
 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
-			return (0);
+			return 0;
 		}
 
 		/*
@@ -209,6 +189,10 @@
 
 		PHY_RESET(sc);	/* XXX hardware bug work-around */
 
+		anar = PHY_READ(sc, RGEPHY_MII_ANAR);
+		anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX |
+		    RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10);
+
 		switch (IFM_SUBTYPE(ife->ifm_media)) {
 		case IFM_AUTO:
 #ifdef foo
@@ -216,40 +200,42 @@
 			 * If we're already in auto mode, just return.
 			 */
 			if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN)
-				return (0);
+				return 0;
 #endif
-			(void) rgephy_mii_phy_auto(sc);
+			(void)rgephy_mii_phy_auto(sc);
 			break;
 		case IFM_1000_T:
 			speed = RGEPHY_S1000;
 			goto setit;
 		case IFM_100_TX:
 			speed = RGEPHY_S100;
+			anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX;
 			goto setit;
 		case IFM_10_T:
 			speed = RGEPHY_S10;
-setit:
+			anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10;
+ setit:
 			rgephy_loop(sc);
 			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
 				speed |= RGEPHY_BMCR_FDX;
 				gig = RGEPHY_1000CTL_AFD;
+				anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10);
 			} else {
 				gig = RGEPHY_1000CTL_AHD;
+				anar &=
+				    ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD);
 			}
 
-			PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0);
-			PHY_WRITE(sc, RGEPHY_MII_BMCR, speed);
-			PHY_WRITE(sc, RGEPHY_MII_ANAR, RGEPHY_SEL_TYPE);
-
-			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
+			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) {
+				PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0);
+				PHY_WRITE(sc, RGEPHY_MII_ANAR, anar);
+				PHY_WRITE(sc, RGEPHY_MII_BMCR, speed |
+				    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
 				break;
-
-			PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig);
-			PHY_WRITE(sc, RGEPHY_MII_BMCR,
-			    speed|RGEPHY_BMCR_AUTOEN|RGEPHY_BMCR_STARTNEG);
+			}
 
 			/*
-			 * When settning the link manually, one side must
+			 * When setting the link manually, one side must
 			 * be the master and the other the slave. However
 			 * ifmedia doesn't give us a good way to specify
 			 * this, so we fake it by using one of the LINK
@@ -263,15 +249,15 @@
 				PHY_WRITE(sc, RGEPHY_MII_1000CTL,
 				    gig|RGEPHY_1000CTL_MSE);
 			}
+			PHY_WRITE(sc, RGEPHY_MII_BMCR, speed |
+			    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
 			break;
-#ifdef foo
 		case IFM_NONE:
 			PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
 			break;
-#endif
 		case IFM_100_T4:
 		default:
-			return (EINVAL);
+			return EINVAL;
 		}
 		break;
 
@@ -280,13 +266,13 @@
 		 * If we're not currently selected, just return.
 		 */
 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
-			return (0);
+			return 0;
 
 		/*
 		 * Is the interface even up?
 		 */
 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
-			return (0);
+			return 0;
 
 		/*
 		 * Only used for autonegotiation.
@@ -300,7 +286,7 @@
 		 * the BMSR twice in case it's latched.
 		 */
 		reg = PHY_READ(sc, RTK_GMEDIASTAT);
-		if (reg & RTK_GMEDIASTAT_LINK)
+		if ((reg & RTK_GMEDIASTAT_LINK) != 0)
 			break;
 
 		/*
@@ -311,7 +297,7 @@
 
 		sc->mii_ticks = 0;
 		rgephy_mii_phy_auto(sc);
-		return (0);
+		return 0;
 	}
 
 	/* Update the media status. */
@@ -330,12 +316,11 @@
 		rgephy_load_dspcode(sc);
 	}
 	mii_phy_update(sc, cmd);
-	return (0);
+	return 0;
 }
 
 static void
-rgephy_status(sc)
-	struct mii_softc *sc;
+rgephy_status(struct mii_softc *sc)
 {
 	struct mii_data *mii = sc->mii_pdata;
 	int bmsr, bmcr;
@@ -343,24 +328,22 @@
 	mii->mii_media_status = IFM_AVALID;
 	mii->mii_media_active = IFM_ETHER;
 
-	bmsr = PHY_READ(sc, RTK_GMEDIASTAT);
-
-	if (bmsr & RTK_GMEDIASTAT_LINK)
+	if ((PHY_READ(sc, RTK_GMEDIASTAT) & RTK_GMEDIASTAT_LINK) != 0)
 		mii->mii_media_status |= IFM_ACTIVE;
-	bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
 
+	bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
 	bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
 
-	if (bmcr & RGEPHY_BMCR_ISO) {
+	if ((bmcr & RGEPHY_BMCR_ISO) != 0) {
 		mii->mii_media_active |= IFM_NONE;
 		mii->mii_media_status = 0;
 		return;
 	}
 
-	if (bmcr & RGEPHY_BMCR_LOOP)
+	if ((bmcr & RGEPHY_BMCR_LOOP) != 0)
 		mii->mii_media_active |= IFM_LOOP;
 
-	if (bmcr & RGEPHY_BMCR_AUTOEN) {
+	if ((bmcr & RGEPHY_BMCR_AUTOEN) != 0) {
 		if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) {
 			/* Erg, still trying, I guess... */
 			mii->mii_media_active |= IFM_NONE;
@@ -369,42 +352,43 @@
 	}
 
 	bmsr = PHY_READ(sc, RTK_GMEDIASTAT);
-	if (bmsr & RTK_GMEDIASTAT_10MBPS)
-		mii->mii_media_active |= IFM_10_T;
-	if (bmsr & RTK_GMEDIASTAT_100MBPS)
-		mii->mii_media_active |= IFM_100_TX;
-	if (bmsr & RTK_GMEDIASTAT_1000MBPS)
+	if ((bmsr & RTK_GMEDIASTAT_1000MBPS) != 0)
 		mii->mii_media_active |= IFM_1000_T;
-	if (bmsr & RTK_GMEDIASTAT_FDX)
+	else if ((bmsr & RTK_GMEDIASTAT_100MBPS) != 0)
+		mii->mii_media_active |= IFM_100_TX;
+	else if ((bmsr & RTK_GMEDIASTAT_10MBPS) != 0)
+		mii->mii_media_active |= IFM_10_T;
+	else
+		mii->mii_media_active |= IFM_NONE;
+	if ((bmsr & RTK_GMEDIASTAT_FDX) != 0)
 		mii->mii_media_active |= IFM_FDX;
-
-	return;
 }
 
 
 static int
-rgephy_mii_phy_auto(mii)
-	struct mii_softc *mii;
+rgephy_mii_phy_auto(struct mii_softc *mii)
 {
+
 	rgephy_loop(mii);
 	PHY_RESET(mii);
 
 	PHY_WRITE(mii, RGEPHY_MII_ANAR,
 	    BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
 	DELAY(1000);
-	PHY_WRITE(mii, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AFD);
+	PHY_WRITE(mii, RGEPHY_MII_1000CTL,
+	    RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD);
 	DELAY(1000);
 	PHY_WRITE(mii, RGEPHY_MII_BMCR,
 	    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
 	DELAY(100);
 
-	return (EJUSTRETURN);
+	return EJUSTRETURN;
 }
 
 static void
 rgephy_loop(struct mii_softc *sc)
 {
-	u_int32_t bmsr;
+	uint32_t bmsr;
 	int i;
 
 	PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
@@ -412,7 +396,7 @@
 
 	for (i = 0; i < 15000; i++) {
 		bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
-		if (!(bmsr & RGEPHY_BMSR_LINK)) {
+		if ((bmsr & RGEPHY_BMSR_LINK) == 0) {
 #if 0
 			device_printf(sc->mii_dev, "looped %d\n", i);
 #endif
@@ -430,8 +414,9 @@
 /*
  * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of
  * existing revisions of the 8169S/8110S chips need to be tuned in
- * order to reliably negotiate a 1000Mbps link. Later revs of the
- * chips may not require this software tuning.
+ * order to reliably negotiate a 1000Mbps link. This is only needed
+ * for rev 0 and rev 1 of the PHY. Later versions work without
+ * any fixups.
  */
 static void
 rgephy_load_dspcode(struct mii_softc *sc)
@@ -530,6 +515,7 @@
 static void
 rgephy_reset(struct mii_softc *sc)
 {
+
 	mii_phy_reset(sc);
 	DELAY(1000);
 
@@ -548,11 +534,16 @@
 
 	/* Reset capabilities */
 	/* Step1: write our capability */
-	PHY_WRITE(sc, 0x04,0x01e1); /* 10/100 capability */
-	PHY_WRITE(sc, 0x09,0x0200); /* 1000 capability */
+	/* 10/100 capability */
+	PHY_WRITE(sc, RGEPHY_MII_ANAR,
+	    RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX |
+	    RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10 | ANAR_CSMA);
+	/* 1000 capability */
+	PHY_WRITE(sc, RGEPHY_MII_1000CTL,
+	    RGEPHY_1000CTL_AFD | RGEPHY_1000CTL_AHD);
 
-#ifdef jrs_notyet
 	/* Step2: Restart NWay */
-	PHY_WRITE(sc, 0x00, 0x1200); // NWay enable and Restart NWay
-#endif
+	/* NWay enable and Restart NWay */
+	PHY_WRITE(sc, RGEPHY_MII_BMCR,
+	    RGEPHY_BMCR_RESET | RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
 }
Index: dev/pci/if_re_pci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_re_pci.c,v
retrieving revision 1.8.2.4
diff -u -r1.8.2.4 if_re_pci.c
--- dev/pci/if_re_pci.c	29 Dec 2005 19:44:18 -0000	1.8.2.4
+++ dev/pci/if_re_pci.c	11 Feb 2007 03:42:02 -0000
@@ -41,7 +41,7 @@
  * Senior Networking Software Engineer
  * Wind River Systems
  *
- * Netbsd bus-specific frontends for written by
+ * NetBSD bus-specific frontends for written by
  * Jonathan Stone <jonathan@netbsd.org>
  */
 
@@ -76,11 +76,6 @@
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcidevs.h>
 
-/*
- * Default to using PIO access for this driver.
- */
-#define RE_USEIOSPACE
-
 #include <dev/ic/rtl81x9reg.h>
 #include <dev/ic/rtl81x9var.h>
 #include <dev/ic/rtl8169var.h>
@@ -93,31 +88,58 @@
 	pcitag_t sc_pcitag;
 };
 
-static int	re_pci_probe(struct device *, struct cfdata *, void *);
+static int	re_pci_match(struct device *, struct cfdata *, void *);
 static void	re_pci_attach(struct device *, struct device *, void *);
 
 /*
  * Various supported device vendors/types and their names.
  */
 static const struct rtk_type re_devs[] = {
-	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8139, RTK_HWREV_8139CPLUS,
-		"RealTek 8139C+ 10/100BaseTX" },
-	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169, RTK_HWREV_8169,
-		"RealTek 8169 Gigabit Ethernet" },
-	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169, RTK_HWREV_8169S,
-		"RealTek 8169S Single-chip Gigabit Ethernet" },
-	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169, RTK_HWREV_8169SB,
-		"RealTek 8169SB Single-chip Gigabit Ethernet" },
-	{ PCI_VENDOR_COREGA, PCI_PRODUCT_COREGA_LAPCIGT, RTK_HWREV_8169S,
-		"Corega CG-LAPCIGT Gigabit Ethernet" },
-	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169, RTK_HWREV_8110S,
-		"RealTek 8110S Single-chip Gigabit Ethernet" },
-	{ PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DGE528T, RTK_HWREV_8169S,
-		"D-Link DGE-528T Gigabit Ethernet" },
-	{ PCI_VENDOR_USR2, PCI_PRODUCT_USR2_USR997902, RTK_HWREV_8169S,
-		"US Robotics (3Com) USR997902 Gigabit Ethernet" },
-	{ PCI_VENDOR_LINKSYS, PCI_PRODUCT_LINKSYS_EG1032, RTK_HWREV_8169S,
-		"Linksys EG1032 rev. 3 Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8139,
+	    RTK_HWREV_8139CPLUS,
+	    "RealTek 8139C+ 10/100BaseTX" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8101E,
+	    RTK_HWREV_8100E,
+	    "RealTek 8100E PCIe 10/100BaseTX" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8101E,
+	    RTK_HWREV_8101E,
+	    "RealTek 8101E PCIe 10/100BaseTX" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168,
+	    RTK_HWREV_8168_SPIN1,
+	    "RealTek 8168B/8111B PCIe Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168,
+	    RTK_HWREV_8168_SPIN2,
+	    "RealTek 8168B/8111B PCIe Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
+	    RTK_HWREV_8169,
+	    "RealTek 8169 Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
+	    RTK_HWREV_8169S,
+	    "RealTek 8169S Single-chip Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
+	    RTK_HWREV_8110S,
+	    "RealTek 8110S Single-chip Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
+	    RTK_HWREV_8169_8110SB,
+	    "RealTek 8169SB/8110SB Single-chip Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
+	    RTK_HWREV_8169_8110SC,
+	    "RealTek 8169SC/8110SC Single-chip Gigabit Ethernet" },
+	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169SC,
+	    RTK_HWREV_8169_8110SC,
+	    "RealTek 8169SC/8110SC Single-chip Gigabit Ethernet" },
+	{ PCI_VENDOR_COREGA, PCI_PRODUCT_COREGA_LAPCIGT,
+	    RTK_HWREV_8169S,
+	    "Corega CG-LAPCIGT Gigabit Ethernet" },
+	{ PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DGE528T,
+	    RTK_HWREV_8169S,
+	    "D-Link DGE-528T Gigabit Ethernet" },
+	{ PCI_VENDOR_USR2, PCI_PRODUCT_USR2_USR997902,
+	    RTK_HWREV_8169S,
+	    "US Robotics (3Com) USR997902 Gigabit Ethernet" },
+	{ PCI_VENDOR_LINKSYS, PCI_PRODUCT_LINKSYS_EG1032,
+	    RTK_HWREV_8169S,
+	    "Linksys EG1032 rev. 3 Gigabit Ethernet" },
 	{ 0, 0, 0, NULL }
 };
 
@@ -130,10 +152,15 @@
 	{ RTK_HWREV_8139C, RTK_8139, "C" },
 	{ RTK_HWREV_8139D, RTK_8139, "8139D/8100B/8100C" },
 	{ RTK_HWREV_8139CPLUS, RTK_8139CPLUS, "C+"},
+	{ RTK_HWREV_8168_SPIN1, RTK_8169, "8168B/8111B"},
+	{ RTK_HWREV_8168_SPIN2, RTK_8169, "8168B/8111B"},
 	{ RTK_HWREV_8169, RTK_8169, "8169"},
 	{ RTK_HWREV_8169S, RTK_8169, "8169S"},
-	{ RTK_HWREV_8169SB, RTK_8169, "8169SB"},
 	{ RTK_HWREV_8110S, RTK_8169, "8110S"},
+	{ RTK_HWREV_8169_8110SB, RTK_8169, "8169SB"},
+	{ RTK_HWREV_8169_8110SC, RTK_8169, "8169SC"},
+	{ RTK_HWREV_8100E, RTK_8169, "8100E"},
+	{ RTK_HWREV_8101E, RTK_8169, "8101E"},
 	{ RTK_HWREV_8100, RTK_8139, "8100"},
 	{ RTK_HWREV_8101, RTK_8139, "8101"},
 	{ 0, 0, NULL }
@@ -141,7 +168,7 @@
 
 #define RE_LINKSYS_EG1032_SUBID	0x00241737
 
-CFATTACH_DECL(re_pci, sizeof(struct re_pci_softc), re_pci_probe, re_pci_attach,
+CFATTACH_DECL(re_pci, sizeof(struct re_pci_softc), re_pci_match, re_pci_attach,
 	      NULL, NULL);
 
 /*
@@ -149,15 +176,16 @@
  * IDs against our list and return a device name if we find a match.
  */
 static int
-re_pci_probe(struct device *parent, struct cfdata *match, void *aux)
+re_pci_match(struct device *parent, struct cfdata *match, void *aux)
 {
-	const struct rtk_type		*t;
+	const struct rtk_type	*t;
 	struct pci_attach_args	*pa = aux;
-	bus_space_tag_t		rtk_btag;
-	bus_space_handle_t	rtk_bhandle;
-	bus_size_t		bsize;
+	bus_space_tag_t		iot, memt, bst;
+	bus_space_handle_t	ioh, memh, bsh;
+	bus_size_t		memsize, iosize, bsize;
 	u_int32_t		hwrev;
 	pcireg_t subid;
+	boolean_t ioh_valid, memh_valid;
 
 	subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
 
@@ -177,24 +205,25 @@
 			 * Temporarily map the I/O space
 			 * so we can read the chip ID register.
 			 */
-#ifdef RE_USEIOSPACE
-			if (pci_mapreg_map(pa, RTK_PCI_LOIO,
-			    PCI_MAPREG_TYPE_IO, 0, &rtk_btag,
-			    &rtk_bhandle, NULL, &bsize)) {
-				aprint_error("can't map i/o space\n");
+			ioh_valid = (pci_mapreg_map(pa, RTK_PCI_LOIO,
+			    PCI_MAPREG_TYPE_IO, 0, &iot, &ioh,
+			    NULL, &iosize) == 0);
+			memh_valid = (pci_mapreg_map(pa, RTK_PCI_LOMEM,
+			    PCI_MAPREG_TYPE_MEM, 0, &memt, &memh,
+			    NULL, &memsize) == 0);
+			if (ioh_valid) {
+				bst = iot;
+				bsh = ioh;
+				bsize = iosize;
+			} else if (memh_valid) {
+				bst = memt;
+				bsh = memh;
+				bsize = memsize;
+			} else
 				return 0;
-			}
-#else
-			if (pci_mapreg_map(pa, RTK_PCI_LOMEM,
-			    PCI_MAPREG_TYPE_MEM, 0, &rtk_btag,
-			    &rtk_bhandle, NULL, &bsize)) {
-				aprint_error("can't map mem space\n");
-				return 0;
-			}
-#endif
-			hwrev = bus_space_read_4(rtk_btag, rtk_bhandle,
-			    RTK_TXCFG) & RTK_TXCFG_HWREV;
-			bus_space_unmap(rtk_btag, rtk_bhandle, bsize);
+			hwrev = bus_space_read_4(bst, bsh, RTK_TXCFG) &
+			    RTK_TXCFG_HWREV;
+			bus_space_unmap(bst, bsh, bsize);
 			if (t->rtk_basetype == hwrev)
 				return 2;	/* defeat rtk(4) */
 		}
@@ -215,11 +244,14 @@
 	const char *intrstr = NULL;
 	const struct rtk_type	*t;
 	const struct rtk_hwrev	*hw_rev;
-	int			hwrev;
+	uint32_t		hwrev;
 	int			error = 0;
 	int			pmreg;
+	boolean_t		ioh_valid, memh_valid;
 	pcireg_t		command;
-	bus_size_t		bsize;
+	bus_space_tag_t		iot, memt;
+	bus_space_handle_t	ioh, memh;
+	bus_size_t		iosize, memsize, bsize;
 
 
 	/*
@@ -227,7 +259,7 @@
 	 */
 	if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
 		command = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR);
-		if (command & RTK_PSTATE_MASK) {
+		if (command & PCI_PMCSR_STATE_MASK) {
 			u_int32_t		iobase, membase, irq;
 
 			/* Save important PCI config data. */
@@ -238,9 +270,9 @@
 			/* Reset the power state. */
 			aprint_normal("%s: chip is is in D%d power mode "
 		    	    "-- setting to D0\n", sc->sc_dev.dv_xname,
-		    	    command & RTK_PSTATE_MASK);
+		    	    command & PCI_PMCSR_STATE_MASK);
 
-			command &= ~RTK_PSTATE_MASK;
+			command &= ~PCI_PMCSR_STATE_MASK;
 			pci_conf_write(pc, pa->pa_tag,
 			    pmreg + PCI_PMCSR, command);
 
@@ -258,19 +290,23 @@
 	command |= PCI_COMMAND_MASTER_ENABLE;
 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
 
-#ifdef RE_USEIOSPACE
-	if (pci_mapreg_map(pa, RTK_PCI_LOIO, PCI_MAPREG_TYPE_IO, 0,
-	    &sc->rtk_btag, &sc->rtk_bhandle, NULL, &bsize)) {
-		aprint_error("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+	ioh_valid = (pci_mapreg_map(pa, RTK_PCI_LOIO, PCI_MAPREG_TYPE_IO, 0,
+	    &iot, &ioh, NULL, &iosize) == 0);
+	memh_valid = (pci_mapreg_map(pa, RTK_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0,
+	    &memt, &memh, NULL, &memsize) == 0);
+	if (ioh_valid) {
+		sc->rtk_btag = iot;
+		sc->rtk_bhandle = ioh;
+		bsize = iosize;
+	} else if (memh_valid) {
+		sc->rtk_btag = memt;
+		sc->rtk_bhandle = memh;
+		bsize = memsize;
+	} else {
+		aprint_error("%s: can't map registers\n", sc->sc_dev.dv_xname);
 		return;
 	}
-#else
-	if (pci_mapreg_map(pa, RTK_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0,
-	    &sc->rtk_btag, &sc->rtk_bhandle, NULL, &bsize)) {
-		aprint_error("%s: can't map mem space\n", sc->sc_dev.dv_xname);
-		return;
-	}
-#endif
+
 	t = re_devs;
 	hwrev = CSR_READ_4(sc, RTK_TXCFG) & RTK_TXCFG_HWREV;
 
@@ -325,24 +361,27 @@
 	re_attach(sc);
 
 	/*
-	 * Perform hardware diagnostic.
-	 * XXX: this diagnostic only makes sense for attachemnts with 64-bit
-	 * busses: PCI, but not CardBus.
+	 * Perform hardware diagnostic on the original RTL8169.
+	 * Some 32-bit cards were incorrectly wired and would
+	 * malfunction if plugged into a 64-bit slot.
 	 */
-	error = re_diag(sc);
-	if (error) {
-		aprint_error(
-		    "%s: attach aborted due to hardware diag failure\n",
-		    sc->sc_dev.dv_xname);
-
-		re_detach(sc);
+	if (hwrev == RTK_HWREV_8169) {
+		error = re_diag(sc);
+		if (error) {
+			aprint_error(
+			    "%s: attach aborted due to hardware diag failure\n",
+			    sc->sc_dev.dv_xname);
+
+			re_detach(sc);
+
+			if (psc->sc_ih != NULL) {
+				pci_intr_disestablish(pc, psc->sc_ih);
+				psc->sc_ih = NULL;
+			}
 
-		if (psc->sc_ih != NULL) {
-			pci_intr_disestablish(pc, psc->sc_ih);
-			psc->sc_ih = NULL;
+			if (bsize)
+				bus_space_unmap(sc->rtk_btag, sc->rtk_bhandle,
+				    bsize);
 		}
-
-		if (bsize)
-			bus_space_unmap(sc->rtk_btag, sc->rtk_bhandle, bsize);
 	}
 }
Index: dev/pci/if_rtk_pci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_rtk_pci.c,v
retrieving revision 1.22.4.1
diff -u -r1.22.4.1 if_rtk_pci.c
--- dev/pci/if_rtk_pci.c	17 Mar 2006 15:24:00 -0000	1.22.4.1
+++ dev/pci/if_rtk_pci.c	11 Feb 2007 03:42:02 -0000
@@ -82,7 +82,7 @@
  * on the part of Realtek. Memory mapped mode does appear to work on
  * uniprocessor systems though.
  */
-#ifndef dreamcast		/* XXX */
+#if !defined(__sh__)		/* XXX: dreamcast, landisk */
 #define RTK_USEIOSPACE
 #endif
 
@@ -178,15 +178,15 @@
 		printf("\n");
 		panic("rtk_pci_attach: impossible");
 	}
-	printf(": %s\n", t->rtk_name);
+	printf(": %s (rev. 0x%02x)\n", t->rtk_name, PCI_REVISION(pa->pa_class));
 
 	/*
 	 * Handle power management nonsense.
 	 */
 
 	if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
-		command = pci_conf_read(pc, pa->pa_tag, pmreg + 4);
-		if (command & RTK_PSTATE_MASK) {
+		command = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR);
+		if (command & PCI_PMCSR_STATE_MASK) {
 			pcireg_t iobase, membase, irq;
 
 			/* Save important PCI config data. */
@@ -197,9 +197,10 @@
 			/* Reset the power state. */
 			printf("%s: chip is in D%d power mode "
 			    "-- setting to D0\n", sc->sc_dev.dv_xname,
-			    command & RTK_PSTATE_MASK);
-			command &= 0xFFFFFFFC;
-			pci_conf_write(pc, pa->pa_tag, pmreg + 4, command);
+			    command & PCI_PMCSR_STATE_MASK);
+			command &= ~PCI_PMCSR_STATE_MASK;
+			pci_conf_write(pc, pa->pa_tag,
+			    pmreg + PCI_PMCSR, command);
 
 			/* Restore PCI config data. */
 			pci_conf_write(pc, pa->pa_tag, RTK_PCI_LOIO, iobase);
Index: dev/pci/pcidevs
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pcidevs,v
retrieving revision 1.701.2.39
diff -u -r1.701.2.39 pcidevs
--- dev/pci/pcidevs	20 Nov 2006 15:49:38 -0000	1.701.2.39
+++ dev/pci/pcidevs	11 Feb 2007 03:42:04 -0000
@@ -2579,13 +2579,17 @@
 /* RATOC Systems products */
 product RATOC	REXPCI31	0x0853	REX PCI-31/33 SCSI
 
-/* Realtek (Creative Labs?) products */
-product REALTEK	RT8029		0x8029	8029 Ethernet
-product REALTEK	RT8129		0x8129	8129 10/100 Ethernet
+/* Realtek products */
+product REALTEK RT8029		0x8029	8029 Ethernet
+product REALTEK RT8100		0x8100	8100 Ethernet
+product REALTEK RT8129		0x8129	8129 10/100 Ethernet
+product REALTEK RT8101E		0x8136	8101E Ethernet
 product REALTEK RT8138		0x8138	8138 10/100 Ethernet
 product REALTEK RT8139B		0x8138	8139B 10/100 Ethernet
 product REALTEK RT8139		0x8139	8139 10/100 Ethernet
-product REALTEK RT8169		0x8169	8169 10/100/1000 Ethernet
+product REALTEK RT8169SC	0x8167	8169SC/8110SC 10/100/1000 Ethernet
+product REALTEK RT8168		0x8168	8168B/8111B 10/100/1000 Ethernet
+product REALTEK RT8169		0x8169	8169/S/SB 10/100/1000 Ethernet
 product REALTEK RT8180		0x8180	8180 802.11b
 
 /* RICOH products */
Index: dev/pci/pcidevs.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pcidevs.h,v
retrieving revision 1.702.2.37
diff -u -r1.702.2.37 pcidevs.h
--- dev/pci/pcidevs.h	20 Nov 2006 15:51:12 -0000	1.702.2.37
+++ dev/pci/pcidevs.h	11 Feb 2007 03:42:06 -0000
@@ -2586,13 +2586,17 @@
 /* RATOC Systems products */
 #define	PCI_PRODUCT_RATOC_REXPCI31	0x0853		/* REX PCI-31/33 SCSI */
 
-/* Realtek (Creative Labs?) products */
+/* Realtek products */
 #define	PCI_PRODUCT_REALTEK_RT8029	0x8029		/* 8029 Ethernet */
+#define	PCI_PRODUCT_REALTEK_RT8100	0x8100		/* 8100 Ethernet */
 #define	PCI_PRODUCT_REALTEK_RT8129	0x8129		/* 8129 10/100 Ethernet */
+#define	PCI_PRODUCT_REALTEK_RT8101E	0x8136		/* 8101E Ethernet */
 #define	PCI_PRODUCT_REALTEK_RT8138	0x8138		/* 8138 10/100 Ethernet */
 #define	PCI_PRODUCT_REALTEK_RT8139B	0x8138		/* 8139B 10/100 Ethernet */
 #define	PCI_PRODUCT_REALTEK_RT8139	0x8139		/* 8139 10/100 Ethernet */
-#define	PCI_PRODUCT_REALTEK_RT8169	0x8169		/* 8169 10/100/1000 Ethernet */
+#define	PCI_PRODUCT_REALTEK_RT8169SC	0x8167		/* 8169SC/8110SC 10/100/1000 Ethernet */
+#define	PCI_PRODUCT_REALTEK_RT8168	0x8168		/* 8168B/8111B 10/100/1000 Ethernet */
+#define	PCI_PRODUCT_REALTEK_RT8169	0x8169		/* 8169/S/SB 10/100/1000 Ethernet */
 #define	PCI_PRODUCT_REALTEK_RT8180	0x8180		/* 8180 802.11b */
 
 /* RICOH products */
Index: dev/pci/pcidevs_data.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pcidevs_data.h,v
retrieving revision 1.700.2.37
diff -u -r1.700.2.37 pcidevs_data.h
--- dev/pci/pcidevs_data.h	20 Nov 2006 15:51:12 -0000	1.700.2.37
+++ dev/pci/pcidevs_data.h	11 Feb 2007 03:42:08 -0000
@@ -8700,10 +8700,18 @@
 	    "8029 Ethernet",
 	},
 	{
+	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8100,
+	    "8100 Ethernet",
+	},
+	{
 	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8129,
 	    "8129 10/100 Ethernet",
 	},
 	{
+	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8101E,
+	    "8101E Ethernet",
+	},
+	{
 	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8138,
 	    "8138 10/100 Ethernet",
 	},
@@ -8716,8 +8724,16 @@
 	    "8139 10/100 Ethernet",
 	},
 	{
+	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169SC,
+	    "8169SC/8110SC 10/100/1000 Ethernet",
+	},
+	{
+	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168,
+	    "8168B/8111B 10/100/1000 Ethernet",
+	},
+	{
 	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
-	    "8169 10/100/1000 Ethernet",
+	    "8169/S/SB 10/100/1000 Ethernet",
 	},
 	{
 	    PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8180,
@@ -10904,4 +10920,4 @@
 	    "Video Controller",
 	},
 };
-const int pci_nproducts = 2143;
+const int pci_nproducts = 2147;
--- /dev/null	2007-02-11 11:35:08.000000000 +0900
+++ dev/mii/rlphy.c	2007-02-11 12:17:29.000000000 +0900
@@ -0,0 +1,336 @@
+/*	$NetBSD: rlphy.c,v 1.12 2006/11/16 01:33:06 christos Exp $	*/
+/*	$OpenBSD: rlphy.c,v 1.20 2005/07/31 05:27:30 pvalchev Exp $	*/
+
+/*
+ * Copyright (c) 1998, 1999 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for the internal PHY found on RTL8139 based nics, based
+ * on drivers for the 'exphy' (Internal 3Com phys) and 'nsphy'
+ * (National Semiconductor DP83840).
+ */
+
+/*
+ * Ported to NetBSD by Juan Romero Pardines <xtraeme@NetBSD.org>
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+#include <machine/bus.h>
+#include <dev/ic/rtl81x9reg.h>
+
+int	rlphymatch(struct device *, struct cfdata *, void *);
+void	rlphyattach(struct device *, struct device *, void *);
+
+CFATTACH_DECL(rlphy, sizeof(struct mii_softc),
+    rlphymatch, rlphyattach, mii_phy_detach, mii_phy_activate);
+
+int	rlphy_service(struct mii_softc *, struct mii_data *, int);
+void	rlphy_status(struct mii_softc *);
+
+const struct mii_phy_funcs rlphy_funcs = {
+	rlphy_service, rlphy_status, mii_phy_reset,
+};
+
+static const struct mii_phydesc rlphys[] = {
+	{ MII_OUI_yyREALTEK,		MII_MODEL_yyREALTEK_RTL8201L,
+          MII_STR_yyREALTEK_RTL8201L },
+	{ MII_OUI_ICPLUS,		MII_MODEL_ICPLUS_IP101,
+	  MII_STR_ICPLUS_IP101 },
+
+	{ 0,				0,
+	  NULL },
+};
+
+int
+rlphymatch(struct device *parent, struct cfdata *match, void *aux)
+{
+	struct mii_attach_args *ma = aux;
+
+	if (mii_phy_match(ma, rlphys) != NULL)
+		return (10);
+
+	if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
+	    MII_MODEL(ma->mii_id2) != 0)
+		return 0;
+
+	if (strcmp(parent->dv_cfdata->cf_name, "rtk") != 0 &&
+	    strcmp(parent->dv_cfdata->cf_name, "re") != 0)
+		return 0;
+
+	/*
+	 * A "real" phy should get preference, but on the 8139 there
+	 * is no phyid register.
+	 */
+	return 5;
+}
+
+void
+rlphyattach(struct device *parent, struct device *self, void *aux)
+{
+	struct mii_softc *sc = (void *)self;
+	struct mii_attach_args *ma = aux;
+	struct mii_data *mii = ma->mii_data;
+
+	if (MII_MODEL(ma->mii_id2) == MII_MODEL_yyREALTEK_RTL8201L) {
+		aprint_normal(": %s, rev. %d\n", MII_STR_yyREALTEK_RTL8201L,
+		    MII_REV(ma->mii_id2));
+	} else
+		aprint_normal(": Realtek internal PHY\n");
+
+	sc->mii_inst = mii->mii_instance;
+	sc->mii_phy = ma->mii_phyno;
+	sc->mii_funcs = &rlphy_funcs;
+	sc->mii_pdata = mii;
+	sc->mii_flags = ma->mii_flags;
+
+	sc->mii_flags |= MIIF_NOISOLATE;
+
+	PHY_RESET(sc);
+
+	aprint_normal("%s: ", sc->mii_dev.dv_xname);
+	sc->mii_capabilities =
+	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+	if (sc->mii_capabilities & BMSR_MEDIAMASK)
+		mii_phy_add_media(sc);
+	aprint_normal("\n");
+}
+
+int
+rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+
+	int rv;
+
+	if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
+		return ENXIO;
+
+	/*
+	 * Can't isolate the RTL8139 phy, so it has to be the only one.
+	 */
+	if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+		panic("rlphy_service: attempt to isolate phy");
+
+	switch (cmd) {
+	case MII_POLLSTAT:
+		break;
+
+	case MII_MEDIACHG:
+		/*
+		 * If the interface is not up, don't do anything.
+		 */
+		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+			break;
+
+		switch (IFM_SUBTYPE(ife->ifm_media)) {
+		case IFM_AUTO:
+			/*
+			 * If we're already in auto mode, just return.
+			 */
+			if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
+				return (0);
+			(void) mii_phy_auto(sc, 0);
+			break;
+		case IFM_100_T4:
+			/*
+			 * XXX Not supported as a manual setting right now.
+			 */
+			return (EINVAL);
+		default:
+			/*
+			 * BMCR data is stored in the ifmedia entry.
+			 */
+			switch (ife->ifm_media &
+			    (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
+				case IFM_ETHER|IFM_10_T:
+					rv = ANAR_10|ANAR_CSMA;
+					break;
+				case IFM_ETHER|IFM_10_T|IFM_FDX:
+					rv = ANAR_10_FD|ANAR_CSMA;
+					break;
+				case IFM_ETHER|IFM_100_TX:
+					rv = ANAR_TX|ANAR_CSMA;
+					break;
+				case IFM_ETHER|IFM_100_TX|IFM_FDX:
+					rv = ANAR_TX_FD|ANAR_CSMA;
+					break;
+				case IFM_ETHER|IFM_100_T4:
+					rv = ANAR_T4|ANAR_CSMA;
+					break;
+				default:
+					rv = 0;
+					break;
+			}
+
+			PHY_WRITE(sc, MII_ANAR, rv);
+			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
+		}
+		break;
+
+	case MII_TICK:
+		/*
+		 * Is the interface even up?
+		 */
+		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+			return (0);
+
+		/*
+		 * Only used for autonegotiation.
+		 */
+		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+			break;
+
+		/*
+		 * The RealTek PHY's autonegotiation doesn't need to be
+		 * kicked; it continues in the background.
+		 */
+		break;
+
+	case MII_DOWN:
+		mii_phy_down(sc);
+		return (0);
+	}
+
+	/* Update the media status. */
+	mii_phy_status(sc);
+
+	/* Callback if something changed. */
+	mii_phy_update(sc, cmd);
+	return (0);
+}
+
+void
+rlphy_status(struct mii_softc *sc)
+{
+	struct mii_data *mii = sc->mii_pdata;
+	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+	int bmsr, bmcr, anlpar;
+
+	mii->mii_media_status = IFM_AVALID;
+	mii->mii_media_active = IFM_ETHER;
+
+	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
+	if (bmsr & BMSR_LINK)
+		mii->mii_media_status |= IFM_ACTIVE;
+
+	bmcr = PHY_READ(sc, MII_BMCR);
+	if (bmcr & BMCR_ISO) {
+		mii->mii_media_active |= IFM_NONE;
+		mii->mii_media_status = 0;
+		return;
+	}
+
+	if (bmcr & BMCR_LOOP)
+		mii->mii_media_active |= IFM_LOOP;
+
+	if (bmcr & BMCR_AUTOEN) {
+		/*
+		 * NWay autonegotiation takes the highest-order common
+		 * bit of the ANAR and ANLPAR (i.e. best media advertised
+		 * both by us and our link partner).
+		 */
+		if ((bmsr & BMSR_ACOMP) == 0) {
+			/* Erg, still trying, I guess... */
+			mii->mii_media_active |= IFM_NONE;
+			return;
+		}
+
+		if ((anlpar = PHY_READ(sc, MII_ANAR) &
+		    PHY_READ(sc, MII_ANLPAR))) {
+			if (anlpar & ANLPAR_T4)
+				mii->mii_media_active |= IFM_100_T4;
+			else if (anlpar & ANLPAR_TX_FD)
+				mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+			else if (anlpar & ANLPAR_TX)
+				mii->mii_media_active |= IFM_100_TX;
+			else if (anlpar & ANLPAR_10_FD)
+				mii->mii_media_active |= IFM_10_T|IFM_FDX;
+			else if (anlpar & ANLPAR_10)
+				mii->mii_media_active |= IFM_10_T;
+			else
+				mii->mii_media_active |= IFM_NONE;
+			return;
+		}
+
+		/*
+		 * If the other side doesn't support NWAY, then the
+		 * best we can do is determine if we have a 10Mbps or
+		 * 100Mbps link. There's no way to know if the link 
+		 * is full or half duplex, so we default to half duplex
+		 * and hope that the user is clever enough to manually
+		 * change the media settings if we're wrong.
+		 */
+
+		/*
+		 * The RealTek PHY supports non-NWAY link speed
+		 * detection, however it does not report the link
+		 * detection results via the ANLPAR or BMSR registers.
+		 * (What? RealTek doesn't do things the way everyone
+		 * else does? I'm just shocked, shocked I tell you.)
+		 * To determine the link speed, we have to do one
+		 * of two things:
+		 *
+		 * - If this is a standalone RealTek RTL8201(L) PHY,
+		 *   we can determine the link speed by testing bit 0
+		 *   in the magic, vendor-specific register at offset
+		 *   0x19.
+		 *
+		 * - If this is a RealTek MAC with integrated PHY, we
+		 *   can test the 'SPEED10' bit of the MAC's media status
+		 *   register.
+		 */
+		if (strcmp("rtk",
+		    sc->mii_dev.dv_parent->dv_cfdata->cf_name)
+		    == 0) {
+			if (PHY_READ(sc, RTK_MEDIASTAT) & RTK_MEDIASTAT_SPEED10)
+				mii->mii_media_active |= IFM_10_T;
+			else
+				mii->mii_media_active |= IFM_100_TX;
+		} else {
+			if (PHY_READ(sc, 0x0019) & 0x01)
+				mii->mii_media_active |= IFM_100_TX;
+			else
+				mii->mii_media_active |= IFM_10_T;
+		}
+
+	} else
+		mii->mii_media_active = ife->ifm_media;
+}


---
Izumi Tsutsui