Author: yongari
Date: Wed Jan  4 23:32:50 2012
New Revision: 229536
URL: http://svn.freebsd.org/changeset/base/229536

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/7/sys/dev/re/if_re.c
  stable/7/sys/pci/if_rlreg.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/dev/re/if_re.c
==============================================================================
--- stable/7/sys/dev/re/if_re.c Wed Jan  4 23:31:43 2012        (r229535)
+++ stable/7/sys/dev/re/if_re.c Wed Jan  4 23:32:50 2012        (r229536)
@@ -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 *);
@@ -1406,13 +1407,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;
@@ -1429,22 +1435,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:
@@ -1595,6 +1607,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
@@ -3191,14 +3204,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);
 }
@@ -3453,10 +3466,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);
@@ -3582,6 +3627,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;
@@ -3601,9 +3714,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);
 
@@ -3620,12 +3737,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)
@@ -3634,6 +3748,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/7/sys/pci/if_rlreg.h
==============================================================================
--- stable/7/sys/pci/if_rlreg.h Wed Jan  4 23:31:43 2012        (r229535)
+++ stable/7/sys/pci/if_rlreg.h Wed Jan  4 23:32:50 2012        (r229536)
@@ -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 */
@@ -914,22 +915,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)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to