git: fc68534a9ad9 - main - rge: add Wake-on-LAN support for magic packet
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 10 Apr 2026 17:43:17 UTC
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__ */