On Wed, Dec 23, 2020 at 12:35:46PM +0800, Kevin Lo wrote: > Hi, > > This diff implements WoL support in rge(4). I can wakeup the machine with WoL > after suspending it through `zzz` or powering off it through `halt -p`.
Thanks! This works as expected in my testing. -Otto > > Index: share/man/man4/rge.4 > =================================================================== > RCS file: /cvs/src/share/man/man4/rge.4,v > retrieving revision 1.4 > diff -u -p -u -p -r1.4 rge.4 > --- share/man/man4/rge.4 12 Oct 2020 02:11:10 -0000 1.4 > +++ share/man/man4/rge.4 23 Dec 2020 04:33:26 -0000 > @@ -37,6 +37,15 @@ Rivet Networks Killer E3000 Adapter (250 > .It > TP-LINK TL-NG421 Adapter (2500baseT) > .El > +.Pp > +The > +.Nm > +driver additionally supports Wake on LAN (WoL). > +See > +.Xr arp 8 > +and > +.Xr ifconfig 8 > +for more details. > .Sh SEE ALSO > .Xr arp 4 , > .Xr ifmedia 4 , > Index: sys/dev/pci/if_rge.c > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_rge.c,v > retrieving revision 1.9 > diff -u -p -u -p -r1.9 if_rge.c > --- sys/dev/pci/if_rge.c 12 Dec 2020 11:48:53 -0000 1.9 > +++ sys/dev/pci/if_rge.c 23 Dec 2020 04:33:27 -0000 > @@ -59,6 +59,7 @@ int rge_debug = 0; > > int rge_match(struct device *, void *, void *); > void rge_attach(struct device *, struct device *, void *); > +int rge_activate(struct device *, int); > int rge_intr(void *); > int rge_encap(struct rge_softc *, struct mbuf *, int); > int rge_ioctl(struct ifnet *, u_long, caddr_t); > @@ -111,6 +112,10 @@ int rge_get_link_status(struct rge_soft > void rge_txstart(void *); > void rge_tick(void *); > void rge_link_state(struct rge_softc *); > +#ifndef SMALL_KERNEL > +int rge_wol(struct ifnet *, int); > +void rge_wol_power(struct rge_softc *); > +#endif > > static const struct { > uint16_t reg; > @@ -126,7 +131,7 @@ static const struct { > }; > > struct cfattach rge_ca = { > - sizeof(struct rge_softc), rge_match, rge_attach > + sizeof(struct rge_softc), rge_match, rge_attach, NULL, rge_activate > }; > > struct cfdriver rge_cd = { > @@ -272,6 +277,11 @@ rge_attach(struct device *parent, struct > ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; > #endif > > +#ifndef SMALL_KERNEL > + ifp->if_capabilities |= IFCAP_WOL; > + ifp->if_wol = rge_wol; > + rge_wol(ifp, 0); > +#endif > timeout_set(&sc->sc_timeout, rge_tick, sc); > task_set(&sc->sc_task, rge_txstart, sc); > > @@ -288,6 +298,25 @@ rge_attach(struct device *parent, struct > } > > int > +rge_activate(struct device *self, int act) > +{ > + struct rge_softc *sc = (struct rge_softc *)self; > + int rv = 0; > + > + switch (act) { > + case DVACT_POWERDOWN: > + rv = config_activate_children(self, act); > +#ifndef SMALL_KERNEL > + rge_wol_power(sc); > +#endif > + default: > + rv = config_activate_children(self, act); > + break; > + } > + return (rv); > +} > + > +int > rge_intr(void *arg) > { > struct rge_softc *sc = arg; > @@ -2025,6 +2054,7 @@ rge_hw_init(struct rge_softc *sc) > /* Set PCIe uncorrectable error status. */ > rge_write_csi(sc, 0x108, > rge_read_csi(sc, 0x108) | 0x00100000); > + > } > > void > @@ -2391,3 +2421,48 @@ rge_link_state(struct rge_softc *sc) > if_link_state_change(ifp); > } > } > + > +#ifndef SMALL_KERNEL > +int > +rge_wol(struct ifnet *ifp, 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); > + > + 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); > + RGE_CLRBIT_1(sc, RGE_CFG3, RGE_CFG3_WOL_LINK | RGE_CFG3_WOL_MAGIC); > + if (enable) > + RGE_SETBIT_1(sc, RGE_CFG5, RGE_CFG5_WOL_LANWAKE); > + RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); > + > + return (0); > +} > + > +void > +rge_wol_power(struct rge_softc *sc) > +{ > + /* Disable RXDV gate. */ > + 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); > +} > +#endif > Index: sys/dev/pci/if_rgereg.h > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_rgereg.h,v > retrieving revision 1.5 > diff -u -p -u -p -r1.5 if_rgereg.h > --- sys/dev/pci/if_rgereg.h 22 Nov 2020 14:06:22 -0000 1.5 > +++ sys/dev/pci/if_rgereg.h 23 Dec 2020 04:33:27 -0000 > @@ -111,16 +111,24 @@ > #define RGE_EECMD_WRITECFG 0xc0 > > /* Flags for register RGE_CFG1 */ > +#define RGE_CFG1_PM_EN 0x01 > #define RGE_CFG1_SPEED_DOWN 0x10 > > /* Flags for register RGE_CFG2 */ > +#define RGE_CFG2_PMSTS_EN 0x20 > #define RGE_CFG2_CLKREQ_EN 0x80 > > /* Flags for register RGE_CFG3 */ > #define RGE_CFG3_RDY_TO_L23 0x02 > +#define RGE_CFG3_WOL_LINK 0x10 > +#define RGE_CFG3_WOL_MAGIC 0x20 > > /* Flags for register RGE_CFG5 */ > #define RGE_CFG5_PME_STS 0x01 > +#define RGE_CFG5_WOL_LANWAKE 0x02 > +#define RGE_CFG5_WOL_UCAST 0x10 > +#define RGE_CFG5_WOL_MCAST 0x20 > +#define RGE_CFG5_WOL_BCAST 0x40 > > /* Flags for register RGE_CSIAR */ > #define RGE_CSIAR_BYTE_EN 0x0000000f