diff options
author | yongari <yongari@FreeBSD.org> | 2008-01-14 07:16:48 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2008-01-14 07:16:48 +0000 |
commit | ac52885c0b330eb8194cc1a30862228df0d55714 (patch) | |
tree | e0ab782f5223a6ce2bedb2fc861f55b2c6f8b064 /sys/dev/stge | |
parent | 53056b5673504715a87508ebc5700e22d4034030 (diff) | |
download | FreeBSD-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.c | 57 | ||||
-rw-r--r-- | sys/dev/stge/if_stgereg.h | 8 |
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) |