kern/112089: re(4): only works after a lot of patching

Ed Schouten ed at fxq.nl
Tue Apr 24 19:40:06 UTC 2007


>Number:         112089
>Category:       kern
>Synopsis:       re(4): only works after a lot of patching
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 24 19:40:05 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Ed Schouten
>Release:        FreeBSD 6.2-STABLE i386
>Organization:
>Environment:
FreeBSD 6.2-STABLE #0: Sun Apr 22 17:39:47 CEST 2007

re0: <RealTek 8168/8111B PCIe Gigabit Ethernet> port 0xa800-0xa8ff mem 0xfeaff000-0xfeafffff irq 19 at device 0.0 on pci3
miibus0: <MII bus> on re0
rgephy0: <RTL8169S/8110S media interface> on miibus0
rgephy0:  10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 1000baseT-FDX, auto
re0: Ethernet address: 00:18:f3:75:0a:0d
re0: [FAST]

re0 at pci3:0:0:   class=0x020000 card=0x81aa1043 chip=0x816810ec rev=0x01 hdr=0x00
    vendor     = 'Realtek Semiconductor'
    class      = network
    subclass   = ethernet
>Description:
My desktop with an ASUS P5B motherboard has an on-board re(4) network
interface. It has three problems, sorted by importance:

- I have to run `ifconfig re0 promisc' in order to accept IPv6 traffic
  properly.
- In a lot of cases, TCP traffic gets lost, causing important webpages
  like Google.com to not appear.
- Running `tcpdump -i re0 -n' renders the interface for about 8 seconds
  inactive.
>How-To-Repeat:
>Fix:
Based on a lot of emails on the FreeBSD mailinglists, I've composed a
patch that fixes these issues. I've been using it on my desktop for a
couple of months now and it's the only way I can use my NIC properly.

--- src/sys/dev/re/if_re.c	Thu Mar 15 19:34:07 2007
+++ src/sys/dev/re/if_re.c	Thu Mar 15 19:31:20 2007
@@ -249,6 +249,7 @@
 static int re_ioctl		(struct ifnet *, u_long, caddr_t);
 static void re_init		(void *);
 static void re_init_locked	(struct rl_softc *);
+static void re_init_rxcfg	(struct rl_softc *);
 static void re_stop		(struct rl_softc *);
 static void re_watchdog		(struct rl_softc *);
 static int re_suspend		(device_t);
@@ -620,6 +621,7 @@
 	struct ifmultiaddr	*ifma;
 	u_int32_t		rxfilt;
 	int			mcnt = 0;
+	u_int32_t		hwrev;
 
 	RL_LOCK_ASSERT(sc);
 
@@ -660,8 +662,24 @@
 		rxfilt &= ~RL_RXCFG_RX_MULTI;
 
 	CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
-	CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
-	CSR_WRITE_4(sc, RL_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, RL_TXCFG) & RL_TXCFG_HWREV;
+
+	if (hwrev == RL_HWREV_8100E || hwrev == RL_HWREV_8101E ||
+	    hwrev == RL_HWREV_8168_SPIN1 || hwrev == RL_HWREV_8168_SPIN2) {
+		CSR_WRITE_4(sc, RL_MAR0, bswap32(hashes[1]));
+		CSR_WRITE_4(sc, RL_MAR4, bswap32(hashes[0]));
+	} else {
+		CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
+		CSR_WRITE_4(sc, RL_MAR4, hashes[1]);
+	}
 }
 
 static void
@@ -2040,7 +2058,8 @@
 	 * below can assemble the packet into a single buffer that's
 	 * padded out to the mininum frame size.
 	 */
-	if (arg.rl_flags && (*m_head)->m_pkthdr.len < RL_MIN_FRAMELEN)
+	if (arg.rl_flags && !(arg.rl_flags & RL_TDESC_CMD_TCPCSUM) &&
+	    (*m_head)->m_pkthdr.len < RL_MIN_FRAMELEN)
 		error = EFBIG;
 	else
 		error = bus_dmamap_load_mbuf(sc->rl_ldata.rl_mtag, map,
@@ -2243,7 +2262,6 @@
 {
 	struct ifnet		*ifp = sc->rl_ifp;
 	struct mii_data		*mii;
-	u_int32_t		rxcfg = 0;
 	union {
 		uint32_t align_dummy;
 		u_char eaddr[ETHER_ADDR_LEN];
@@ -2322,31 +2340,8 @@
 	CSR_WRITE_1(sc, RL_EARLY_TX_THRESH, 16);
 
 	CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG);
-
-	/* Set the individual bit to receive frames for this host only. */
-	rxcfg = CSR_READ_4(sc, RL_RXCFG);
-	rxcfg |= RL_RXCFG_RX_INDIV;
-
-	/* If we want promiscuous mode, set the allframes bit. */
-	if (ifp->if_flags & IFF_PROMISC)
-		rxcfg |= RL_RXCFG_RX_ALLPHYS;
-	else
-		rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
-	CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
-
-	/*
-	 * Set capture broadcast bit to capture broadcast frames.
-	 */
-	if (ifp->if_flags & IFF_BROADCAST)
-		rxcfg |= RL_RXCFG_RX_BROAD;
-	else
-		rxcfg &= ~RL_RXCFG_RX_BROAD;
-	CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
-
-	/*
-	 * Program the multicast filter, if necessary.
-	 */
-	re_setmulti(sc);
+	
+	re_init_rxcfg(sc);
 
 #ifdef DEVICE_POLLING
 	/*
@@ -2412,6 +2407,39 @@
 	callout_reset(&sc->rl_stat_callout, hz, re_tick, sc);
 }
 
+static void
+re_init_rxcfg(sc)
+	struct rl_softc		*sc;
+{
+	u_int32_t		rxcfg;
+	struct ifnet		*ifp = sc->rl_ifp;
+
+	/* Set the individual bit to receive frames for this host only. */
+	rxcfg = CSR_READ_4(sc, RL_RXCFG);
+	rxcfg |= RL_RXCFG_RX_INDIV;
+
+	/* If we want promiscuous mode, set the allframes bit. */
+	if (ifp->if_flags & IFF_PROMISC)
+		rxcfg |= RL_RXCFG_RX_ALLPHYS;
+	else
+		rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
+	CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+
+	/*
+	 * Set capture broadcast bit to capture broadcast frames.
+	 */
+	if (ifp->if_flags & IFF_BROADCAST)
+		rxcfg |= RL_RXCFG_RX_BROAD;
+	else
+		rxcfg &= ~RL_RXCFG_RX_BROAD;
+	CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+
+	/*
+	 * Program the multicast filter, if necessary.
+	 */
+	re_setmulti(sc);
+}
+
 /*
  * Set media options.
  */
@@ -2473,10 +2501,16 @@
 		break;
 	case SIOCSIFFLAGS:
 		RL_LOCK(sc);
-		if (ifp->if_flags & IFF_UP)
-			re_init_locked(sc);
-		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		if (ifp->if_flags & IFF_UP) {
+			if ((ifp->if_flags ^ sc->rl_if_flags) &
+			    (IFF_PROMISC | IFF_BROADCAST))
+				re_init_rxcfg(sc);
+			else
+				re_init_locked(sc);
+		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 			re_stop(sc);
+		}
+		sc->rl_if_flags = ifp->if_flags;
 		RL_UNLOCK(sc);
 		break;
 	case SIOCADDMULTI:
--- src/sys/pci/if_rlreg.h	Sat Dec  2 00:07:27 2006
+++ src/sys/pci/if_rlreg.h	Sat Dec  2 00:18:53 2006
@@ -737,6 +737,7 @@
 	struct mtx		rl_intlock;
 	int			rl_txstart;
 	int			rl_link;
+	int			rl_if_flags;
 };
 
 #define	RL_LOCK(_sc)		mtx_lock(&(_sc)->rl_mtx)
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list