Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Jan 2012 23:31:43 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r229535 - in stable/8/sys: dev/re pci
Message-ID:  <201201042331.q04NVh8p003646@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Wed Jan  4 23:31:43 2012
New Revision: 229535
URL: http://svn.freebsd.org/changeset/base/229535

Log:
  MFC r227850-227851,227854,227914,227916:
  r227850:
    Writing access to RL_CFG5 register also requires EEPROM write
    access.
    While I'm here, enable WOL through magic packet but disable waking
    up system via unicast, multicast and broadcast frames.  Otherwise,
    multicast or unicast frame(e.g. ICMP echo request) can wake up
    system which is not probably wanted behavior on most environments.
    This was not known as problem because RL_CFG5 register access had
    not effect until this change.
    The capability to wake up system with unicast/multicast frames
    are still set in driver, default off, so users who need that
    feature can still activate it with ifconfig(8).
  
  r227851:
    Perform media change after setting IFF_DRV_RUNNING flag. Without it,
    driver would ignore the first link state update if controller
    already established a link such that it would have to take
    additional link state handling in re_tick().
  
  r227854:
    Disable accepting frames in re_stop() to put RX MAC into idle state.
    Because there is no reliable way to know whether RX MAC is in
    stopped state, rejecting all frames would be the only way to
    minimize possible races.
    Otherwise it's possible to receive frames while stop command
    execution is in progress and controller can DMA the frame to freed
    RX buffer during that period.
    This was observed on recent PCIe controllers(i.e. RTL8111F).
  
    While this change may not be required on old controllers it
    wouldn't make negative effects on old controllers.  One side effect
    of this change is disabling receive so driver reprograms RL_RXCFG
    to receive WOL frames when it is put into suspend or shutdown.
  
    This should address occasional 'memory modified free' errors seen
    on recent RealTek controllers.
  
  r227914:
    Make sure to stop TX MAC before freeing queued TX frames.
    For RTL8111DP, check if the TX MAC is active by reading RL_GTXSTART
    register.  For RTL8402/8168E-VL/8168F/8411, wait until TX queue is
    empty.
  
  r227916:
    To save more power, switch to 10/100Mbps link when controller is
    put into suspend/shutdown.  Old PCI controllers performed that
    operation in firmware but for RTL8111C or newer controllers, it's
    responsibility of driver.  It's not clear whether the firmware of
    RTL8111B still downgrades its speed to 10/100Mbps so leave it as it
    was.

Modified:
  stable/8/sys/dev/re/if_re.c
  stable/8/sys/pci/if_rlreg.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/re/if_re.c
==============================================================================
--- stable/8/sys/dev/re/if_re.c	Wed Jan  4 23:29:57 2012	(r229534)
+++ stable/8/sys/dev/re/if_re.c	Wed Jan  4 23:31:43 2012	(r229535)
@@ -294,6 +294,7 @@ static void re_set_rxmode		(struct rl_so
 static void re_reset		(struct rl_softc *);
 static void re_setwol		(struct rl_softc *);
 static void re_clrwol		(struct rl_softc *);
+static void re_set_linkspeed	(struct rl_softc *);
 
 #ifdef RE_DIAG
 static int re_diag		(struct rl_softc *);
@@ -1405,13 +1406,18 @@ re_attach(device_t dev)
 		    RL_FLAG_AUTOPAD | RL_FLAG_MACSLEEP;
 		break;
 	case RL_HWREV_8401E:
-	case RL_HWREV_8402:
 	case RL_HWREV_8105E:
 	case RL_HWREV_8105E_SPIN1:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
 		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
 		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD;
 		break;
+	case RL_HWREV_8402:
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
+		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
+		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD |
+		    RL_FLAG_CMDSTOP_WAIT_TXQ;
+		break;
 	case RL_HWREV_8168B_SPIN1:
 	case RL_HWREV_8168B_SPIN2:
 		sc->rl_flags |= RL_FLAG_WOLRXENB;
@@ -1428,22 +1434,28 @@ re_attach(device_t dev)
 		/* FALLTHROUGH */
 	case RL_HWREV_8168CP:
 	case RL_HWREV_8168D:
-	case RL_HWREV_8168DP:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
 		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
-		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2;
+		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 | RL_FLAG_WOL_MANLINK;
+		break;
+	case RL_HWREV_8168DP:
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
+		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_AUTOPAD |
+		    RL_FLAG_JUMBOV2 | RL_FLAG_WAIT_TXPOLL | RL_FLAG_WOL_MANLINK;
 		break;
 	case RL_HWREV_8168E:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
 		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
-		    RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2;
+		    RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 |
+		    RL_FLAG_WOL_MANLINK;
 		break;
 	case RL_HWREV_8168E_VL:
 	case RL_HWREV_8168F:
 	case RL_HWREV_8411:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
 		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
-		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2;
+		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 |
+		    RL_FLAG_CMDSTOP_WAIT_TXQ | RL_FLAG_WOL_MANLINK;
 		break;
 	case RL_HWREV_8169_8110SB:
 	case RL_HWREV_8169_8110SBL:
@@ -1594,6 +1606,7 @@ re_attach(device_t dev)
 	if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &reg) == 0)
 		ifp->if_capabilities |= IFCAP_WOL;
 	ifp->if_capenable = ifp->if_capabilities;
+	ifp->if_capenable &= ~(IFCAP_WOL_UCAST | IFCAP_WOL_MCAST);
 	/*
 	 * Don't enable TSO by default.  It is known to generate
 	 * corrupted TCP segments(bad TCP options) under certain
@@ -3197,14 +3210,14 @@ re_init_locked(struct rl_softc *sc)
 	if (sc->rl_testmode)
 		return;
 
-	mii_mediachg(mii);
-
 	CSR_WRITE_1(sc, RL_CFG1, CSR_READ_1(sc, RL_CFG1) | RL_CFG1_DRVLOAD);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
 	sc->rl_flags &= ~RL_FLAG_LINK;
+	mii_mediachg(mii);
+
 	sc->rl_watchdog_timer = 0;
 	callout_reset(&sc->rl_stat_callout, hz, re_tick, sc);
 }
@@ -3459,10 +3472,42 @@ re_stop(struct rl_softc *sc)
 	callout_stop(&sc->rl_stat_callout);
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 
-	if ((sc->rl_flags & RL_FLAG_CMDSTOP) != 0)
+	/*
+	 * Disable accepting frames to put RX MAC into idle state.
+	 * Otherwise it's possible to get frames while stop command
+	 * execution is in progress and controller can DMA the frame
+	 * to already freed RX buffer during that period.
+	 */
+	CSR_WRITE_4(sc, RL_RXCFG, CSR_READ_4(sc, RL_RXCFG) &
+	    ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_MULTI |
+	    RL_RXCFG_RX_BROAD));
+
+	if ((sc->rl_flags & RL_FLAG_WAIT_TXPOLL) != 0) {
+		for (i = RL_TIMEOUT; i > 0; i--) {
+			if ((CSR_READ_1(sc, sc->rl_txstart) &
+			    RL_TXSTART_START) == 0)
+				break;
+			DELAY(20);
+		}
+		if (i == 0)
+			device_printf(sc->rl_dev,
+			    "stopping TX poll timed out!\n");
+		CSR_WRITE_1(sc, RL_COMMAND, 0x00);
+	} else if ((sc->rl_flags & RL_FLAG_CMDSTOP) != 0) {
 		CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_STOPREQ | RL_CMD_TX_ENB |
 		    RL_CMD_RX_ENB);
-	else
+		if ((sc->rl_flags & RL_FLAG_CMDSTOP_WAIT_TXQ) != 0) {
+			for (i = RL_TIMEOUT; i > 0; i--) {
+				if ((CSR_READ_4(sc, RL_TXCFG) &
+				    RL_TXCFG_QUEUE_EMPTY) != 0)
+					break;
+				DELAY(100);
+			}
+			if (i == 0)
+				device_printf(sc->rl_dev,
+				   "stopping TXQ timed out!\n");
+		}
+	} else
 		CSR_WRITE_1(sc, RL_COMMAND, 0x00);
 	DELAY(1000);
 	CSR_WRITE_2(sc, RL_IMR, 0x0000);
@@ -3588,6 +3633,74 @@ re_shutdown(device_t dev)
 }
 
 static void
+re_set_linkspeed(struct rl_softc *sc)
+{
+	struct mii_softc *miisc;
+	struct mii_data *mii;
+	int aneg, i, phyno;
+
+	RL_LOCK_ASSERT(sc);
+
+	mii = device_get_softc(sc->rl_miibus);
+	mii_pollstat(mii);
+	aneg = 0;
+	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+	    (IFM_ACTIVE | IFM_AVALID)) {
+		switch IFM_SUBTYPE(mii->mii_media_active) {
+		case IFM_10_T:
+		case IFM_100_TX:
+			return;
+		case IFM_1000_T:
+			aneg++;
+			break;
+		default:
+			break;
+		}
+	}
+	miisc = LIST_FIRST(&mii->mii_phys);
+	phyno = miisc->mii_phy;
+	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+		mii_phy_reset(miisc);
+	re_miibus_writereg(sc->rl_dev, phyno, MII_100T2CR, 0);
+	re_miibus_writereg(sc->rl_dev, phyno,
+	    MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);
+	re_miibus_writereg(sc->rl_dev, phyno,
+	    MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
+	DELAY(1000);
+	if (aneg != 0) {
+		/*
+		 * Poll link state until re(4) get a 10/100Mbps link.
+		 */
+		for (i = 0; i < MII_ANEGTICKS_GIGE; i++) {
+			mii_pollstat(mii);
+			if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID))
+			    == (IFM_ACTIVE | IFM_AVALID)) {
+				switch (IFM_SUBTYPE(mii->mii_media_active)) {
+				case IFM_10_T:
+				case IFM_100_TX:
+					return;
+				default:
+					break;
+				}
+			}
+			RL_UNLOCK(sc);
+			pause("relnk", hz);
+			RL_LOCK(sc);
+		}
+		if (i == MII_ANEGTICKS_GIGE)
+			device_printf(sc->rl_dev,
+			    "establishing a link failed, WOL may not work!");
+	}
+	/*
+	 * No link, force MAC to have 100Mbps, full-duplex link.
+	 * MAC does not require reprogramming on resolved speed/duplex,
+	 * so this is just for completeness.
+	 */
+	mii->mii_media_status = IFM_AVALID | IFM_ACTIVE;
+	mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
+}
+
+static void
 re_setwol(struct rl_softc *sc)
 {
 	struct ifnet		*ifp;
@@ -3607,9 +3720,13 @@ re_setwol(struct rl_softc *sc)
 			CSR_WRITE_1(sc, RL_GPIO,
 			    CSR_READ_1(sc, RL_GPIO) & ~0x01);
 	}
-	if ((ifp->if_capenable & IFCAP_WOL) != 0 &&
-	    (sc->rl_flags & RL_FLAG_WOLRXENB) != 0)
-		CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RX_ENB);
+	if ((ifp->if_capenable & IFCAP_WOL) != 0) {
+		re_set_rxmode(sc);
+		if ((sc->rl_flags & RL_FLAG_WOL_MANLINK) != 0)
+			re_set_linkspeed(sc);
+		if ((sc->rl_flags & RL_FLAG_WOLRXENB) != 0)
+			CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RX_ENB);
+	}
 	/* Enable config register write. */
 	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 
@@ -3626,12 +3743,9 @@ re_setwol(struct rl_softc *sc)
 		v |= RL_CFG3_WOL_MAGIC;
 	CSR_WRITE_1(sc, RL_CFG3, v);
 
-	/* Config register write done. */
-	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
-
 	v = CSR_READ_1(sc, RL_CFG5);
-	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
-	v &= ~RL_CFG5_WOL_LANWAKE;
+	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST |
+	    RL_CFG5_WOL_LANWAKE);
 	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
 		v |= RL_CFG5_WOL_UCAST;
 	if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
@@ -3640,6 +3754,9 @@ re_setwol(struct rl_softc *sc)
 		v |= RL_CFG5_WOL_LANWAKE;
 	CSR_WRITE_1(sc, RL_CFG5, v);
 
+	/* Config register write done. */
+	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+
 	if ((ifp->if_capenable & IFCAP_WOL) != 0 &&
 	    (sc->rl_flags & RL_FLAG_PHYWAKE_PM) != 0)
 		CSR_WRITE_1(sc, RL_PMCH, CSR_READ_1(sc, RL_PMCH) & ~0x80);

Modified: stable/8/sys/pci/if_rlreg.h
==============================================================================
--- stable/8/sys/pci/if_rlreg.h	Wed Jan  4 23:29:57 2012	(r229534)
+++ stable/8/sys/pci/if_rlreg.h	Wed Jan  4 23:31:43 2012	(r229535)
@@ -143,6 +143,7 @@
  */
 #define	RL_TXCFG_CLRABRT	0x00000001	/* retransmit aborted pkt */
 #define	RL_TXCFG_MAXDMA		0x00000700	/* max DMA burst size */
+#define	RL_TXCFG_QUEUE_EMPTY	0x00000800	/* 8168E-VL or higher */
 #define	RL_TXCFG_CRCAPPEND	0x00010000	/* CRC append (0 = yes) */
 #define	RL_TXCFG_LOOPBKTST	0x00060000	/* loopback test */
 #define	RL_TXCFG_IFG2		0x00080000	/* 8169 only */
@@ -897,22 +898,25 @@ struct rl_softc {
 	int			rl_int_rx_act;
 	int			rl_int_rx_mod;
 	uint32_t		rl_flags;
-#define	RL_FLAG_MSI		0x0001
-#define	RL_FLAG_AUTOPAD		0x0002
-#define	RL_FLAG_PHYWAKE_PM	0x0004
-#define	RL_FLAG_PHYWAKE		0x0008
-#define	RL_FLAG_JUMBOV2		0x0010
-#define	RL_FLAG_PAR		0x0020
-#define	RL_FLAG_DESCV2		0x0040
-#define	RL_FLAG_MACSTAT		0x0080
-#define	RL_FLAG_FASTETHER	0x0100
-#define	RL_FLAG_CMDSTOP		0x0200
-#define	RL_FLAG_MACRESET	0x0400
-#define	RL_FLAG_MSIX		0x0800
-#define	RL_FLAG_WOLRXENB	0x1000
-#define	RL_FLAG_MACSLEEP	0x2000
-#define	RL_FLAG_PCIE		0x4000
-#define	RL_FLAG_LINK		0x8000
+#define	RL_FLAG_MSI		0x00000001
+#define	RL_FLAG_AUTOPAD		0x00000002
+#define	RL_FLAG_PHYWAKE_PM	0x00000004
+#define	RL_FLAG_PHYWAKE		0x00000008
+#define	RL_FLAG_JUMBOV2		0x00000010
+#define	RL_FLAG_PAR		0x00000020
+#define	RL_FLAG_DESCV2		0x00000040
+#define	RL_FLAG_MACSTAT		0x00000080
+#define	RL_FLAG_FASTETHER	0x00000100
+#define	RL_FLAG_CMDSTOP		0x00000200
+#define	RL_FLAG_MACRESET	0x00000400
+#define	RL_FLAG_MSIX		0x00000800
+#define	RL_FLAG_WOLRXENB	0x00001000
+#define	RL_FLAG_MACSLEEP	0x00002000
+#define	RL_FLAG_WAIT_TXPOLL	0x00004000
+#define	RL_FLAG_CMDSTOP_WAIT_TXQ	0x00008000
+#define	RL_FLAG_WOL_MANLINK	0x00010000
+#define	RL_FLAG_PCIE		0x40000000
+#define	RL_FLAG_LINK		0x80000000
 };
 
 #define	RL_LOCK(_sc)		mtx_lock(&(_sc)->rl_mtx)



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