summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2008-03-03 03:33:58 +0000
committeryongari <yongari@FreeBSD.org>2008-03-03 03:33:58 +0000
commit2214a89c72d6a8cf08423353e77ec7932073868e (patch)
treee51cdde5c954869cc8f77d62944597b5c26c9cb4 /sys
parent0b47bb7a155ee39e176b17afa024c56d5e23c42d (diff)
downloadFreeBSD-src-2214a89c72d6a8cf08423353e77ec7932073868e.zip
FreeBSD-src-2214a89c72d6a8cf08423353e77ec7932073868e.tar.gz
Implement WOL.
Tested by: Fabian Keil ( freebsd-listen AT fabienkeli DOT de )
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/re/if_re.c108
-rw-r--r--sys/pci/if_rlreg.h40
2 files changed, 147 insertions, 1 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 3ba66008..9a05419 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -280,6 +280,8 @@ static void re_miibus_statchg (device_t);
static void re_setmulti (struct rl_softc *);
static void re_reset (struct rl_softc *);
+static void re_setwol (struct rl_softc *);
+static void re_clrwol (struct rl_softc *);
#ifdef RE_DIAG
static int re_diag (struct rl_softc *);
@@ -1334,6 +1336,9 @@ re_attach(dev)
ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
if (ifp->if_capabilities & IFCAP_HWCSUM)
ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
+ /* Enable WOL if PM is supported. */
+ if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &reg) == 0)
+ ifp->if_capabilities |= IFCAP_WOL;
ifp->if_capenable = ifp->if_capabilities;
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
@@ -2715,6 +2720,15 @@ re_ioctl(ifp, command, data)
else
ifp->if_hwassist &= ~CSUM_TSO;
}
+ 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;
+ }
if (reinit && ifp->if_drv_flags & IFF_DRV_RUNNING)
re_init(sc);
VLAN_CAPABILITIES(ifp);
@@ -2820,6 +2834,7 @@ re_suspend(dev)
RL_LOCK(sc);
re_stop(sc);
+ re_setwol(sc);
sc->suspended = 1;
RL_UNLOCK(sc);
@@ -2848,6 +2863,11 @@ re_resume(dev)
if (ifp->if_flags & IFF_UP)
re_init_locked(sc);
+ /*
+ * Clear WOL matching such that normal Rx filtering
+ * wouldn't interfere with WOL patterns.
+ */
+ re_clrwol(sc);
sc->suspended = 0;
RL_UNLOCK(sc);
@@ -2874,7 +2894,95 @@ re_shutdown(dev)
* cases.
*/
sc->rl_ifp->if_flags &= ~IFF_UP;
+ re_setwol(sc);
RL_UNLOCK(sc);
return (0);
}
+
+static void
+re_setwol(sc)
+ struct rl_softc *sc;
+{
+ struct ifnet *ifp;
+ int pmc;
+ uint16_t pmstat;
+ uint8_t v;
+
+ RL_LOCK_ASSERT(sc);
+
+ if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
+ return;
+
+ ifp = sc->rl_ifp;
+ /* 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, 0);
+
+ 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);
+
+ /*
+ * It seems that hardware resets its link speed to 100Mbps in
+ * power down mode so switching to 100Mbps in driver is not
+ * needed.
+ */
+
+ /* 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
+re_clrwol(sc)
+ struct rl_softc *sc;
+{
+ int pmc;
+ uint8_t v;
+
+ RL_LOCK_ASSERT(sc);
+
+ 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);
+
+ 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, 0);
+
+ 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);
+}
diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h
index 5b63290..74d9121 100644
--- a/sys/pci/if_rlreg.h
+++ b/sys/pci/if_rlreg.h
@@ -76,7 +76,11 @@
#define RL_EECMD 0x0050 /* EEPROM command register */
#define RL_CFG0 0x0051 /* config register #0 */
#define RL_CFG1 0x0052 /* config register #1 */
- /* 0053-0057 reserved */
+#define RL_CFG2 0x0053 /* config register #2 */
+#define RL_CFG3 0x0054 /* config register #3 */
+#define RL_CFG4 0x0055 /* config register #4 */
+#define RL_CFG5 0x0056 /* config register #5 */
+ /* 0057 reserved */
#define RL_MEDIASTAT 0x0058 /* media status register (8139) */
/* 0059-005A reserved */
#define RL_MII 0x005A /* 8129 chip only */
@@ -359,16 +363,50 @@
* Config 1 register
*/
#define RL_CFG1_PWRDWN 0x01
+#define RL_CFG1_PME 0x01
#define RL_CFG1_SLEEP 0x02
+#define RL_CFG1_VPDEN 0x02
#define RL_CFG1_IOMAP 0x04
#define RL_CFG1_MEMMAP 0x08
#define RL_CFG1_RSVD 0x10
+#define RL_CFG1_LWACT 0x10
#define RL_CFG1_DRVLOAD 0x20
#define RL_CFG1_LED0 0x40
#define RL_CFG1_FULLDUPLEX 0x40 /* 8129 only */
#define RL_CFG1_LED1 0x80
/*
+ * Config 2 register
+ */
+#define RL_CFG2_PCI33MHZ 0x00
+#define RL_CFG2_PCI66MHZ 0x01
+#define RL_CFG2_PCI64BIT 0x08
+#define RL_CFG2_AUXPWR 0x10
+
+/*
+ * Config 3 register
+ */
+#define RL_CFG3_GRANTSEL 0x80
+#define RL_CFG3_WOL_MAGIC 0x20
+#define RL_CFG3_WOL_LINK 0x10
+#define RL_CFG3_FAST_B2B 0x01
+
+/*
+ * Config 4 register
+ */
+#define RL_CFG4_LWPTN 0x04
+#define RL_CFG4_LWPME 0x10
+
+/*
+ * Config 5 register
+ */
+#define RL_CFG5_WOL_BCAST 0x40
+#define RL_CFG5_WOL_MCAST 0x20
+#define RL_CFG5_WOL_UCAST 0x10
+#define RL_CFG5_WOL_LANWAKE 0x02
+#define RL_CFG5_PME_STS 0x01
+
+/*
* 8139C+ register definitions
*/
OpenPOWER on IntegriCloud