svn commit: r211378 - stable/7/sys/pci
Pyun YongHyeon
yongari at FreeBSD.org
Sun Aug 15 23:13:09 UTC 2010
Author: yongari
Date: Sun Aug 15 23:13:09 2010
New Revision: 211378
URL: http://svn.freebsd.org/changeset/base/211378
Log:
MFC r210244:
Implement WOL. WOL is supported on RTL8139B or newer controllers.
PR: kern/148013
Modified:
stable/7/sys/pci/if_rl.c
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/pci/if_rl.c
==============================================================================
--- stable/7/sys/pci/if_rl.c Sun Aug 15 23:11:38 2010 (r211377)
+++ stable/7/sys/pci/if_rl.c Sun Aug 15 23:13:09 2010 (r211378)
@@ -221,6 +221,8 @@ static int rl_suspend(device_t);
static void rl_tick(void *);
static void rl_txeof(struct rl_softc *);
static void rl_watchdog(struct rl_softc *);
+static void rl_setwol(struct rl_softc *);
+static void rl_clrwol(struct rl_softc *);
#ifdef RL_USEIOSPACE
#define RL_RES SYS_RES_IOPORT
@@ -800,7 +802,7 @@ rl_attach(device_t dev)
struct ifnet *ifp;
struct rl_softc *sc;
struct rl_type *t;
- int error = 0, i, rid;
+ int error = 0, hwrev, i, pmc, rid;
int unit;
uint16_t rl_did = 0;
@@ -926,6 +928,25 @@ rl_attach(device_t dev)
ifp->if_start = rl_start;
ifp->if_init = rl_init;
ifp->if_capabilities = IFCAP_VLAN_MTU;
+ /* Check WOL for RTL8139B or newer controllers. */
+ if (sc->rl_type == RL_8139 &&
+ pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
+ hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
+ switch (hwrev) {
+ case RL_HWREV_8139B:
+ case RL_HWREV_8130:
+ case RL_HWREV_8139C:
+ case RL_HWREV_8139D:
+ case RL_HWREV_8101:
+ case RL_HWREV_8100:
+ ifp->if_capabilities |= IFCAP_WOL;
+ /* Disable WOL. */
+ rl_clrwol(sc);
+ break;
+ default:
+ break;
+ }
+ }
ifp->if_capenable = ifp->if_capabilities;
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
@@ -1776,7 +1797,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
struct ifreq *ifr = (struct ifreq *)data;
struct mii_data *mii;
struct rl_softc *sc = ifp->if_softc;
- int error = 0;
+ int error = 0, mask;
switch (command) {
case SIOCSIFFLAGS:
@@ -1803,6 +1824,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
case SIOCSIFCAP:
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
#ifdef DEVICE_POLLING
if (ifr->ifr_reqcap & IFCAP_POLLING &&
!(ifp->if_capenable & IFCAP_POLLING)) {
@@ -1828,6 +1850,15 @@ rl_ioctl(struct ifnet *ifp, u_long comma
return (error);
}
#endif /* DEVICE_POLLING */
+ if ((mask & IFCAP_WOL) != 0 &&
+ (ifp->if_capabilities & IFCAP_WOL) != 0) {
+ if ((mask & IFCAP_WOL_UCAST) != 0)
+ ifp->if_capenable ^= IFCAP_WOL_UCAST;
+ if ((mask & IFCAP_WOL_MCAST) != 0)
+ ifp->if_capenable ^= IFCAP_WOL_MCAST;
+ if ((mask & IFCAP_WOL_MAGIC) != 0)
+ ifp->if_capenable ^= IFCAP_WOL_MAGIC;
+ }
break;
default:
error = ether_ioctl(ifp, command, data);
@@ -1916,6 +1947,7 @@ rl_suspend(device_t dev)
RL_LOCK(sc);
rl_stop(sc);
+ rl_setwol(sc);
sc->suspended = 1;
RL_UNLOCK(sc);
@@ -1932,12 +1964,31 @@ rl_resume(device_t dev)
{
struct rl_softc *sc;
struct ifnet *ifp;
+ int pmc;
+ uint16_t pmstat;
sc = device_get_softc(dev);
ifp = sc->rl_ifp;
RL_LOCK(sc);
+ if ((ifp->if_capabilities & IFCAP_WOL) != 0 &&
+ pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
+ /* Disable PME and clear PME status. */
+ pmstat = pci_read_config(sc->rl_dev,
+ pmc + PCIR_POWER_STATUS, 2);
+ if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) {
+ pmstat &= ~PCIM_PSTAT_PMEENABLE;
+ pci_write_config(sc->rl_dev,
+ pmc + PCIR_POWER_STATUS, pmstat, 2);
+ }
+ /*
+ * Clear WOL matching such that normal Rx filtering
+ * wouldn't interfere with WOL patterns.
+ */
+ rl_clrwol(sc);
+ }
+
/* reinitialize interface if necessary */
if (ifp->if_flags & IFF_UP)
rl_init_locked(sc);
@@ -1962,7 +2013,93 @@ rl_shutdown(device_t dev)
RL_LOCK(sc);
rl_stop(sc);
+ /*
+ * Mark interface as down since otherwise we will panic if
+ * interrupt comes in later on, which can happen in some
+ * cases.
+ */
+ sc->rl_ifp->if_flags &= ~IFF_UP;
+ rl_setwol(sc);
RL_UNLOCK(sc);
return (0);
}
+
+static void
+rl_setwol(struct rl_softc *sc)
+{
+ struct ifnet *ifp;
+ int pmc;
+ uint16_t pmstat;
+ uint8_t v;
+
+ RL_LOCK_ASSERT(sc);
+
+ ifp = sc->rl_ifp;
+ if ((ifp->if_capabilities & IFCAP_WOL) == 0)
+ return;
+ if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
+ return;
+
+ /* Enable config register write. */
+ CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
+
+ /* Enable PME. */
+ v = CSR_READ_1(sc, RL_CFG1);
+ v &= ~RL_CFG1_PME;
+ if ((ifp->if_capenable & IFCAP_WOL) != 0)
+ v |= RL_CFG1_PME;
+ CSR_WRITE_1(sc, RL_CFG1, v);
+
+ v = CSR_READ_1(sc, RL_CFG3);
+ v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
+ if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+ 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;
+ if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
+ v |= RL_CFG5_WOL_UCAST;
+ if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
+ v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST;
+ if ((ifp->if_capenable & IFCAP_WOL) != 0)
+ v |= RL_CFG5_WOL_LANWAKE;
+ CSR_WRITE_1(sc, RL_CFG5, v);
+ /* Request PME if WOL is requested. */
+ pmstat = pci_read_config(sc->rl_dev, pmc + PCIR_POWER_STATUS, 2);
+ pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
+ if ((ifp->if_capenable & IFCAP_WOL) != 0)
+ pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
+ pci_write_config(sc->rl_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
+}
+
+static void
+rl_clrwol(struct rl_softc *sc)
+{
+ struct ifnet *ifp;
+ uint8_t v;
+
+ ifp = sc->rl_ifp;
+ if ((ifp->if_capabilities & IFCAP_WOL) == 0)
+ return;
+
+ /* Enable config register write. */
+ CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
+
+ v = CSR_READ_1(sc, RL_CFG3);
+ v &= ~(RL_CFG3_WOL_LINK | 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;
+ CSR_WRITE_1(sc, RL_CFG5, v);
+}
More information about the svn-src-stable-7
mailing list