Date: Fri, 10 Apr 2026 17:43:17 +0000 From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Christos Longros <chris.longros@gmail.com> Subject: git: fc68534a9ad9 - main - rge: add Wake-on-LAN support for magic packet Message-ID: <69d936b5.32c58.504c3558@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=fc68534a9ad93f6df1756ffa8e707c30a35ce4d7 commit fc68534a9ad93f6df1756ffa8e707c30a35ce4d7 Author: Christos Longros <chris.longros@gmail.com> AuthorDate: 2026-04-10 17:31:38 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2026-04-10 17:31:38 +0000 rge: add Wake-on-LAN support for magic packet Advertise IFCAP_WOL_MAGIC when PCI power management is available and enable it by default. On suspend or shutdown, rge_setwol() enables the WOL_MAGIC and WOL_LANWAKE bits in CFG3/CFG5, disables the RXDV gate, and enables PM so the NIC stays powered to watch for magic packets. Move hardware-specific WOL register configuration into rge_wol_config() in if_rge_hw.c to keep hardware-specific functions in sync with OpenBSD. Update rge.4 to document WoL support. Tested on FreeBSD 16.0-CURRENT bare metal with Realtek RTL8125 on a Gigabyte B650 Gaming X AX motherboard. Signed-off-by: Christos Longros <chris.longros@gmail.com> Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D56259 --- share/man/man4/rge.4 | 6 +++--- sys/dev/rge/if_rge.c | 57 +++++++++++++++++++++++-------------------------- sys/dev/rge/if_rge_hw.c | 53 +++++++++++++++++---------------------------- sys/dev/rge/if_rge_hw.h | 1 + 4 files changed, 51 insertions(+), 66 deletions(-) diff --git a/share/man/man4/rge.4 b/share/man/man4/rge.4 index 2b781e287e3c..f9077a56f28b 100644 --- a/share/man/man4/rge.4 +++ b/share/man/man4/rge.4 @@ -3,7 +3,7 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause .\" -.Dd December 18, 2025 +.Dd April 5, 2026 .Dt RGE 4 .Os .Sh NAME @@ -39,8 +39,8 @@ over CAT6 cable. .Pp All NICs supported by the .Nm -driver have TCP/IP checksum offload and hardware VLAN tagging/insertion -features, and use a descriptor-based DMA mechanism. +driver have TCP/IP checksum offload, hardware VLAN tagging/insertion +features, Wake On Lan (WOL), and use a descriptor-based DMA mechanism. They are also capable of TCP large send (TCP segmentation offload). .Pp diff --git a/sys/dev/rge/if_rge.c b/sys/dev/rge/if_rge.c index 0007b07e0fa6..17225e065482 100644 --- a/sys/dev/rge/if_rge.c +++ b/sys/dev/rge/if_rge.c @@ -103,12 +103,7 @@ static void rge_tx_task(void *, int); static void rge_txq_flush_mbufs(struct rge_softc *sc); static void rge_tick(void *); static void rge_link_state(struct rge_softc *); -#if 0 -#ifndef SMALL_KERNEL -int rge_wol(struct ifnet *, int); -void rge_wol_power(struct rge_softc *); -#endif -#endif +static void rge_setwol(struct rge_softc *); struct rge_matchid { uint16_t vendor; @@ -161,7 +156,11 @@ rge_attach_if(struct rge_softc *sc, const char *eaddr) if_setcapabilities(sc->sc_ifp, IFCAP_HWCSUM); if_setcapenable(sc->sc_ifp, if_getcapabilities(sc->sc_ifp)); - /* TODO: set WOL */ + /* Enable WOL if PM is supported. */ + if (pci_has_pm(sc->sc_dev)) { + if_setcapabilitiesbit(sc->sc_ifp, IFCAP_WOL_MAGIC, 0); + if_setcapenablebit(sc->sc_ifp, IFCAP_WOL_MAGIC, 0); + } /* Attach interface */ ether_ifattach(sc->sc_ifp, eaddr); @@ -654,26 +653,6 @@ rge_detach(device_t dev) return (0); } -#if 0 - -int -rge_activate(struct device *self, int act) -{ -#ifndef SMALL_KERNEL - struct rge_softc *sc = (struct rge_softc *)self; -#endif - - switch (act) { - case DVACT_POWERDOWN: -#ifndef SMALL_KERNEL - rge_wol_power(sc); -#endif - break; - } - return (0); -} -#endif - static void rge_intr_msi(void *arg) { @@ -1014,7 +993,9 @@ rge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) reinit = 1; } - /* TODO: WOL */ + if ((mask & IFCAP_WOL_MAGIC) != 0 && + (if_getcapabilities(ifp) & IFCAP_WOL_MAGIC) != 0) + if_togglecapenable(ifp, IFCAP_WOL_MAGIC); if ((mask & IFCAP_RXCSUM) != 0 && (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) { @@ -2620,6 +2601,22 @@ rge_link_state(struct rge_softc *sc) } } +static void +rge_setwol(struct rge_softc *sc) +{ + if_t ifp = sc->sc_ifp; + int enable; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!pci_has_pm(sc->sc_dev)) + return; + + enable = (if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0; + + rge_wol_config(sc, enable); +} + /** * @brief Suspend */ @@ -2630,7 +2627,7 @@ rge_suspend(device_t dev) RGE_LOCK(sc); rge_stop_locked(sc); - /* TODO: wake on lan */ + rge_setwol(sc); sc->sc_suspended = true; RGE_UNLOCK(sc); @@ -2646,7 +2643,6 @@ rge_resume(device_t dev) struct rge_softc *sc = device_get_softc(dev); RGE_LOCK(sc); - /* TODO: wake on lan */ /* reinit if required */ if (if_getflags(sc->sc_ifp) & IFF_UP) @@ -2669,6 +2665,7 @@ rge_shutdown(device_t dev) RGE_LOCK(sc); rge_stop_locked(sc); + rge_setwol(sc); RGE_UNLOCK(sc); return (0); diff --git a/sys/dev/rge/if_rge_hw.c b/sys/dev/rge/if_rge_hw.c index 35a0e93dd193..ba01e389af14 100644 --- a/sys/dev/rge/if_rge_hw.c +++ b/sys/dev/rge/if_rge_hw.c @@ -2196,50 +2196,37 @@ rge_get_link_status(struct rge_softc *sc) return ((RGE_READ_2(sc, RGE_PHYSTAT) & RGE_PHYSTAT_LINK) ? 1 : 0); } -#if 0 -#ifndef SMALL_KERNEL -int -rge_wol(struct ifnet *ifp, int enable) +void +rge_wol_config(struct rge_softc *sc, int enable) { - struct rge_softc *sc = ifp->if_softc; - - if (enable) { - if (!(RGE_READ_1(sc, RGE_CFG1) & RGE_CFG1_PM_EN)) { - printf("%s: power management is disabled, " - "cannot do WOL\n", sc->sc_dev.dv_xname); - return (ENOTSUP); - } - - } - - rge_iff(sc); - if (enable) RGE_MAC_SETBIT(sc, 0xc0b6, 0x0001); else RGE_MAC_CLRBIT(sc, 0xc0b6, 0x0001); + /* Enable config register write. */ RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); - RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_WOL_LANWAKE | RGE_CFG5_WOL_UCAST | - RGE_CFG5_WOL_MCAST | RGE_CFG5_WOL_BCAST); + + /* Clear all WOL bits, then set as requested. */ RGE_CLRBIT_1(sc, RGE_CFG3, RGE_CFG3_WOL_LINK | RGE_CFG3_WOL_MAGIC); - if (enable) + RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_WOL_LANWAKE | + RGE_CFG5_WOL_UCAST | RGE_CFG5_WOL_MCAST | RGE_CFG5_WOL_BCAST); + if (enable) { + RGE_SETBIT_1(sc, RGE_CFG3, RGE_CFG3_WOL_MAGIC); RGE_SETBIT_1(sc, RGE_CFG5, RGE_CFG5_WOL_LANWAKE); - RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); + } - return (0); -} + /* Config register write done. */ + RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); -void -rge_wol_power(struct rge_softc *sc) -{ - /* Disable RXDV gate. */ - RGE_CLRBIT_1(sc, RGE_PPSW, 0x08); - DELAY(2000); + if (enable) { + /* Disable RXDV gate so WOL packets can reach the NIC. */ + RGE_CLRBIT_1(sc, RGE_PPSW, 0x08); + DELAY(2000); - RGE_SETBIT_1(sc, RGE_CFG1, RGE_CFG1_PM_EN); - RGE_SETBIT_1(sc, RGE_CFG2, RGE_CFG2_PMSTS_EN); + /* Enable power management. */ + RGE_SETBIT_1(sc, RGE_CFG1, RGE_CFG1_PM_EN); + RGE_SETBIT_1(sc, RGE_CFG2, RGE_CFG2_PMSTS_EN); + } } -#endif -#endif diff --git a/sys/dev/rge/if_rge_hw.h b/sys/dev/rge/if_rge_hw.h index 86f0da7c87b3..4e6ee5f1975f 100644 --- a/sys/dev/rge/if_rge_hw.h +++ b/sys/dev/rge/if_rge_hw.h @@ -37,5 +37,6 @@ extern uint16_t rge_read_phy(struct rge_softc *, uint16_t, uint16_t); extern void rge_write_phy_ocp(struct rge_softc *, uint16_t, uint16_t); extern uint16_t rge_read_phy_ocp(struct rge_softc *sc, uint16_t reg); extern int rge_get_link_status(struct rge_softc *); +extern void rge_wol_config(struct rge_softc *, int); #endif /* __IF_RGE_HW_H__ */home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69d936b5.32c58.504c3558>
