summaryrefslogtreecommitdiffstats
path: root/sys/dev/stge
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2008-01-14 07:16:48 +0000
committeryongari <yongari@FreeBSD.org>2008-01-14 07:16:48 +0000
commitac52885c0b330eb8194cc1a30862228df0d55714 (patch)
treee0ab782f5223a6ce2bedb2fc861f55b2c6f8b064 /sys/dev/stge
parent53056b5673504715a87508ebc5700e22d4034030 (diff)
downloadFreeBSD-src-ac52885c0b330eb8194cc1a30862228df0d55714.zip
FreeBSD-src-ac52885c0b330eb8194cc1a30862228df0d55714.tar.gz
Implement WOL capability.
- Turn on WOL bits in suspend/shutdown method. - WOL is disabled in resume routine as WOL can interfere normal Rx operation. - Move stge_reset() to stge_init_locked() as resetting hardware clears configured Rx information which in turn results in non-working Rx module after suspend/shutdown operation.
Diffstat (limited to 'sys/dev/stge')
-rw-r--r--sys/dev/stge/if_stge.c57
-rw-r--r--sys/dev/stge/if_stgereg.h8
2 files changed, 54 insertions, 11 deletions
diff --git a/sys/dev/stge/if_stge.c b/sys/dev/stge/if_stge.c
index 5ddb14e..c397103 100644
--- a/sys/dev/stge/if_stge.c
+++ b/sys/dev/stge/if_stge.c
@@ -187,6 +187,7 @@ static int stge_init_rx_ring(struct stge_softc *);
static void stge_poll(struct ifnet *, enum poll_cmd, int);
#endif
+static void stge_setwol(struct stge_softc *);
static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
static int sysctl_hw_stge_rxint_nframe(SYSCTL_HANDLER_ARGS);
static int sysctl_hw_stge_rxint_dmawait(SYSCTL_HANDLER_ARGS);
@@ -736,6 +737,7 @@ stge_attach(device_t dev)
ifp->if_hwassist = 0;
ifp->if_capabilities = 0;
}
+ ifp->if_capabilities |= IFCAP_WOL_MAGIC;
ifp->if_capenable = ifp->if_capabilities;
/*
@@ -1121,15 +1123,33 @@ stge_dma_free(struct stge_softc *sc)
static int
stge_shutdown(device_t dev)
{
- struct stge_softc *sc;
- sc = device_get_softc(dev);
+ return (stge_suspend(dev));
+}
- STGE_LOCK(sc);
- stge_stop(sc);
- STGE_UNLOCK(sc);
+static void
+stge_setwol(struct stge_softc *sc)
+{
+ struct ifnet *ifp;
+ uint8_t v;
- return (0);
+ STGE_LOCK_ASSERT(sc);
+
+ ifp = sc->sc_ifp;
+ v = CSR_READ_1(sc, STGE_WakeEvent);
+ /* Disable all WOL bits. */
+ v &= ~(WE_WakePktEnable | WE_MagicPktEnable | WE_LinkEventEnable |
+ WE_WakeOnLanEnable);
+ if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+ v |= WE_MagicPktEnable | WE_WakeOnLanEnable;
+ CSR_WRITE_1(sc, STGE_WakeEvent, v);
+ /* Reset Tx and prevent transmission. */
+ CSR_WRITE_4(sc, STGE_AsicCtrl,
+ CSR_READ_4(sc, STGE_AsicCtrl) | AC_TxReset);
+ /*
+ * TC9021 automatically reset link speed to 100Mbps when it's put
+ * into sleep so there is no need to try to resetting link speed.
+ */
}
static int
@@ -1142,6 +1162,7 @@ stge_suspend(device_t dev)
STGE_LOCK(sc);
stge_stop(sc);
sc->sc_suspended = 1;
+ stge_setwol(sc);
STGE_UNLOCK(sc);
return (0);
@@ -1152,10 +1173,19 @@ stge_resume(device_t dev)
{
struct stge_softc *sc;
struct ifnet *ifp;
+ uint8_t v;
sc = device_get_softc(dev);
STGE_LOCK(sc);
+ /*
+ * Clear WOL bits, so special frames wouldn't interfere
+ * normal Rx operation anymore.
+ */
+ v = CSR_READ_1(sc, STGE_WakeEvent);
+ v &= ~(WE_WakePktEnable | WE_MagicPktEnable | WE_LinkEventEnable |
+ WE_WakeOnLanEnable);
+ CSR_WRITE_1(sc, STGE_WakeEvent, v);
ifp = sc->sc_ifp;
if (ifp->if_flags & IFF_UP)
stge_init_locked(sc);
@@ -1450,6 +1480,11 @@ stge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
else
ifp->if_hwassist = 0;
}
+ if ((mask & IFCAP_WOL) != 0 &&
+ (ifp->if_capabilities & IFCAP_WOL) != 0) {
+ if ((mask & IFCAP_WOL_MAGIC) != 0)
+ ifp->if_capenable ^= IFCAP_WOL_MAGIC;
+ }
if ((mask & IFCAP_VLAN_HWTAGGING) != 0) {
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
@@ -2096,6 +2131,11 @@ stge_init_locked(struct stge_softc *sc)
*/
stge_stop(sc);
+ /*
+ * Reset the chip to a known state.
+ */
+ stge_reset(sc, STGE_RESET_FULL);
+
/* Init descriptors. */
error = stge_init_rx_ring(sc);
if (error != 0) {
@@ -2309,11 +2349,6 @@ stge_stop(struct stge_softc *sc)
sc->sc_watchdog_timer = 0;
/*
- * Reset the chip to a known state.
- */
- stge_reset(sc, STGE_RESET_FULL);
-
- /*
* Disable interrupts.
*/
CSR_WRITE_2(sc, STGE_IntEnable, 0);
diff --git a/sys/dev/stge/if_stgereg.h b/sys/dev/stge/if_stgereg.h
index 4a62f4f..9add8cb 100644
--- a/sys/dev/stge/if_stgereg.h
+++ b/sys/dev/stge/if_stgereg.h
@@ -314,6 +314,14 @@ struct stge_rfd {
#define STGE_ExpRomData 0x50 /* 8-bit */
#define STGE_WakeEvent 0x51 /* 8-bit */
+#define WE_WakePktEnable (1U << 0)
+#define WE_MagicPktEnable (1U << 1)
+#define WE_LinkEventEnable (1U << 2)
+#define WE_WakePolarity (1U << 3)
+#define WE_WakePktEvent (1U << 4)
+#define WE_MagicPktEvent (1U << 5)
+#define WE_LinkEvent (1U << 6)
+#define WE_WakeOnLanEnable (1U << 7)
#define STGE_Countdown 0x54
#define CD_Count(x) ((x) & 0xffff)
OpenPOWER on IntegriCloud