On Tue, Apr 22, 2014 at 04:43:51PM +0200, Alessandro DE LAURENZIS wrote: > Folks, > > OpenBSD 5.4-Rel, GENERIC kernel. I'm trying to set up a file server that > should be remotely controlled (broken LCD). > > I need to switch it on by means of WOL functionality (supported by and > activated into the BIOS). > > The interface is: > > $ dmesg | egrep bge > bge0 at pci2 dev 0 function 0 "Broadcom BCM5751" rev 0x01, BCM5750 A1 > (0x4001): apic 1 int 16, address 00:14:22:e1:0b:05 > brgphy0 at bge0 phy 1: BCM5750 10/100/1000baseT PHY, rev. 0 > > When I halt the system *without* powering down it and then switch it off > pressing the power button, the interface is still on (LED activity is > visible) and I can wake up the system through the ARP magic packet. > > But if I try to power it off through "halt -p" the interface is > physically powered down too (and, of course, it no more react to the WOL > packets). > > I also tried to set "powerdown=YES" in /etc/rc.shutdown, but without > luck. > > Any hints? Pressing the power button each time is not an option, 'cause > the server location isn't easly accessible. > > All the best
What you'd need is wol support for bge, like was done for some other drivers. I believe your 'halt' workaround prevents bge_stop() from being run which deliberately shuts down the card's receive logic. The BIOS might enable WoL at system startup behind the driver's back and it might be left enabled if bge_stop() doesn't run. I'd recommend getting a separate dedicated ethernet card for use with WoL. Currently, these drivers support WOL in OpenBSD: nfe(4), re(4), vr(4), xl(4) More drivers might be added in the future but I'm not actively working on this anymore. I wrote a diff for WoL support for bge(4) in 2011, see below. For most bge chips enabling WOL might leave the machine vulnerable to potential exploits of remote management features in the chip's firmware. Remote management needs to be enabled for WoL to work and is probably buggier than windows xp was at launch date (Theo was saying some of these remote management systems embed MSDOS... Not sure if that was a joke but I don't really want to know.) The bge chip version this implements WOL for should be safe (no remote management) but I've been told this chip version is very rare so I didn't bother committing the diff back then. I have no idea if this diff still applies cleanly to -current (it probably won't) or whether it will make WoL work with your hardware. Consider it an unsupported gift. Stay safe. [[[ This diff makes WOL work with a bge device mikeb gave to me. The datasheet describes scary remote system management stuff for these chips (ASF/SMI), but this is unsupported on the BCM5700 so it should be fine to enable WOL there. Coincidentally, the card mikeb gave me is a BCM5700: bge0 at pci2 dev 8 function 0 "Schneider & Koch SK-9D21" rev 0x11, BCM5700 Altima (0x7104): apic 1 int 11, address 00:00:5a:9d:11:b2 brgphy0 at bge0 phy 1: BCM5411 10/100/1000baseT PHY, rev. 1 The diff below makes WOL work with this card. With quite a lot of hoops to jump through compared to other cards :-/ However, without a gross hack, namely calling bge_init() and bge_stop() from bge_wol_power(), WOL only works if the interface was taken 'up' at least once. Any ideas what parts of init() and stop() are the important bits? I've tried a few things but haven't been successful. The chip doesn't shadow the PCI PMCSR register, so I added definitions for it to the generic PCI code. Index: mii/brgphyreg.h =================================================================== RCS file: /cvs/src/sys/dev/mii/brgphyreg.h,v retrieving revision 1.15 diff -u -p -r1.15 brgphyreg.h --- mii/brgphyreg.h 10 Jul 2010 07:59:33 -0000 1.15 +++ mii/brgphyreg.h 28 Oct 2011 23:45:28 -0000 @@ -206,6 +206,7 @@ #define BRGPHY_AUXCTL_TX_TST 0x0400 /* TX test, always 1 */ #define BRGPHY_AUXCTL_DIS_PRF 0x0080 /* dis part resp filter */ #define BRGPHY_AUXCTL_DIAG_MODE 0x0004 /* Diagnostic mode */ +#define BRGPHY_AUXCTL_WOL_ENBL 0x000A /* Enable WOL */ #define BRGPHY_MII_AUXSTS 0x19 /* AUX status */ #define BRGPHY_AUXSTS_ACOMP 0x8000 /* autoneg complete */ Index: pci/if_bge.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_bge.c,v retrieving revision 1.307 diff -u -p -r1.307 if_bge.c --- pci/if_bge.c 22 Jun 2011 16:44:27 -0000 1.307 +++ pci/if_bge.c 30 Oct 2011 21:02:41 -0000 @@ -192,6 +192,10 @@ void bge_miibus_statchg(struct device *) void bge_reset(struct bge_softc *); void bge_link_upd(struct bge_softc *); +#ifndef SMALL_KERNEL +int bge_wol(struct ifnet *, int); +void bge_wol_power(struct bge_softc *); +#endif #ifdef BGE_DEBUG #define DPRINTF(x) do { if (bgedebug) printf x; } while (0) @@ -2218,6 +2222,17 @@ bge_attach(struct device *parent, struct sc->bge_flags |= BGE_PHY_FIBER_TBI; } +#ifndef SMALL_KERNEL + if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700) { + ifp->if_capabilities |= IFCAP_WOL; + ifp->if_wol = bge_wol; + + /* This heuristic matches the Linux driver. */ + if (!(hwcfg & BGE_HWCFG_EEPROM_WRITE_PROTECT)) + sc->bge_flags |= BGE_WOL_NEEDS_VAUX; + } +#endif + /* Hookup IRQ last. */ DPRINTFN(5, ("pci_intr_establish\n")); sc->bge_intrhand = pci_intr_establish(pc, ih, IPL_NET, bge_intr, sc, @@ -2307,11 +2322,17 @@ bge_activate(struct device *self, int ac switch (act) { case DVACT_QUIESCE: rv = config_activate_children(self, act); +#ifndef SMALL_KERNEL + bge_wol_power(sc); +#endif break; case DVACT_SUSPEND: rv = config_activate_children(self, act); if (ifp->if_flags & IFF_RUNNING) bge_stop(sc); +#ifndef SMALL_KERNEL + bge_wol_power(sc); +#endif break; case DVACT_RESUME: if (ifp->if_flags & IFF_UP) @@ -3729,3 +3750,113 @@ bge_link_upd(struct bge_softc *sc) BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE| BGE_MACSTAT_LINK_CHANGED); } + +#ifndef SMALL_KERNEL +int +bge_wol(struct ifnet *ifp, int enable) +{ + struct bge_softc *sc = ifp->if_softc; + + if (enable) + sc->bge_flags |= BGE_WOL; + else + sc->bge_flags &= ~BGE_WOL; + + return (0); +} + +void +bge_wol_power(struct bge_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct pci_attach_args *pa = &sc->bge_pa; + pcireg_t reg; + int s, offset, if_flags; + + if (!(sc->bge_flags & BGE_WOL)) + return; + + s = splnet(); + + /* + * In case the interface was never up we need to init the + * chip for WOL to work. + * XXX Need a smaller hammer than bge_init()/bge_stop(). + */ + bge_init(sc); + + /* Tell the firmware we're taking control of WOL. */ + bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_WOL, BGE_MAGIC_WOL_NUMBER); + DELAY(100); + + bge_stop(sc); + + /* Disable host interrupts. */ + BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); + + /* Clear the PME status bit. */ + if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PWRMGMT, + &offset, ®)) + pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCI_PMCSR, + reg|PCI_PMCSR_PME_STATUS); + + /* Configure 10Mbps, the chip draws too much power in D3cold. */ + if (!(sc->bge_flags & BGE_PHY_FIBER_TBI) && + !(sc->bge_flags & BGE_PHY_FIBER_MII)) { + sc->bge_ifmedia.ifm_media = IFM_ETHER|IFM_10_T; + if_flags = ifp->if_flags; + ifp->if_flags |= IFF_UP; + bge_ifmedia_upd(ifp); + ifp->if_flags = if_flags; + } + + /* Disable DMA. */ + BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_FRMHDR_DMA_ENB| + BGE_MACMODE_TXDMA_ENB|BGE_MACMODE_RXDMA_ENB); + + /* Halt CPUs. */ + BGE_SETBIT(sc, BGE_TXCPU_MODE, BGE_TXCPUMODE_HALTCPU); + BGE_SETBIT(sc, BGE_RXCPU_MODE, BGE_RXCPUMODE_HALTCPU); + + /* Configure the PHY for WOL mode. */ + bge_miibus_writereg(&sc->bge_dev, 1, BRGPHY_MII_AUXCTL, + BRGPHY_AUXCTL_WOL_ENBL); + BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_PORTMODE); + CSR_WRITE_4(sc, BGE_MAC_MODE, BGE_PORTMODE_MII| + BGE_MACMODE_LINK_POLARITY|BGE_MACMODE_MAGIC_PKT_ENB); + DELAY(100); + + /* Disable RX and TX CPUs, enable alternate clock. */ + BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_CLOCKCTL_RW); + BGE_SETBIT(sc, BGE_PCI_CLKCTL, + BGE_PCICLOCKCTL_RXCPU_CLK_DIS|BGE_PCICLOCKCTL_TXCPU_CLK_DIS| + BGE_PCICLOCKCTL_ALTCLK|BGE_PCICLOCKCTL_LOW_SPEED_PLL); + DELAY(500); + BGE_CLRBIT(sc, BGE_PCI_CLKCTL, BGE_PCICLOCKCTL_ALTCLK); + BGE_CLRBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_CLOCKCTL_RW); + + /* Switch from main power to aux power. The procedure differs + * based on chip model. We only support BCM5700 here. */ + if (sc->bge_flags & BGE_WOL_NEEDS_VAUX) { + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, + BGE_MLC_INTR_ONATTN|BGE_MLC_AUTO_EEPROM| + BGE_MLC_MISCIO_OUTEN0|BGE_MLC_MISCIO_OUTEN1| + BGE_MLC_MISCIO_OUTEN2| + BGE_MLC_MISCIO_OUT0|BGE_MLC_MISCIO_OUT1); + DELAY(100); + } + + /* Re-enable RX in promiscuous mode. */ + BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE|BGE_RXMODE_RX_PROMISC); + + /* Enable PME assertion and put the device to sleep. */ + if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PWRMGMT, + &offset, ®)) { + pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCI_PMCSR, + reg|PCI_PMCSR_PME_EN); + pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D3); + } + + splx(s); +} +#endif Index: pci/if_bgereg.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_bgereg.h,v retrieving revision 1.104 diff -u -p -r1.104 if_bgereg.h --- pci/if_bgereg.h 15 Feb 2011 19:49:47 -0000 1.104 +++ pci/if_bgereg.h 30 Oct 2011 18:29:53 -0000 @@ -80,6 +80,7 @@ #define BGE_VER_SHIFT 16 #define BGE_SOFTWARE_GENCOMM_FW 0x00000B78 #define BGE_FW_PAUSE 0x00000002 +#define BGE_SOFTWARE_GENCOMM_WOL 0x00000D30 #define BGE_SOFTWARE_GENCOMM_NICCFG2 0x00000D38 #define BGE_SOFTWARE_GENCOMM_NICCFG3 0x00000D3C #define BGE_SOFTWARE_GENCOMM_NICCFG4 0x00000D60 @@ -421,6 +422,7 @@ #define BGE_PCICLOCKCTL_PCIPLL_DISABLE 0x00004000 #define BGE_PCICLOCKCTL_SYSPLL_DISABLE 0x00008000 #define BGE_PCICLOCKCTL_BIST_ENABLE 0x00010000 +#define BGE_PCICLOCKCTL_LOW_SPEED_PLL 0x00020000 /* * High priority mailbox registers @@ -2057,6 +2059,12 @@ */ #define BGE_MAGIC_NUMBER 0x4B657654 +/* + * This magic number needs to be written to the firmware mailbox at + * 0xd30 before WOL is configured. + */ +#define BGE_MAGIC_WOL_NUMBER 0x474C0000 + typedef struct { u_int32_t bge_addr_hi; u_int32_t bge_addr_lo; @@ -2239,6 +2247,7 @@ struct bge_status_block { #define BGE_HWCFG_PHYLED_MODE 0x0000000C #define BGE_HWCFG_MEDIA 0x00000030 #define BGE_HWCFG_ASF 0x00000080 +#define BGE_HWCFG_EEPROM_WRITE_PROTECT 0x00000100 #define BGE_VOLTAGE_1POINT3 0x00000000 #define BGE_VOLTAGE_1POINT8 0x00000001 @@ -2611,6 +2620,8 @@ struct bge_softc { #define BGE_5755_PLUS 0x00800000 #define BGE_5714_FAMILY 0x01000000 #define BGE_5700_FAMILY 0x02000000 +#define BGE_WOL 0x04000000 +#define BGE_WOL_NEEDS_VAUX 0x08000000 bus_dma_tag_t bge_dmatag; u_int32_t bge_chipid; Index: pci/pcireg.h =================================================================== RCS file: /cvs/src/sys/dev/pci/pcireg.h,v retrieving revision 1.42 diff -u -p -r1.42 pcireg.h --- pci/pcireg.h 19 Jun 2011 12:02:23 -0000 1.42 +++ pci/pcireg.h 28 Oct 2011 21:56:28 -0000 @@ -516,11 +516,13 @@ typedef u_int8_t pci_revision_t; * Power Management Control Status Register; access via capability pointer. */ #define PCI_PMCSR 0x04 -#define PCI_PMCSR_STATE_MASK 0x03 -#define PCI_PMCSR_STATE_D0 0x00 -#define PCI_PMCSR_STATE_D1 0x01 -#define PCI_PMCSR_STATE_D2 0x02 -#define PCI_PMCSR_STATE_D3 0x03 +#define PCI_PMCSR_STATE_MASK 0x0003 +#define PCI_PMCSR_STATE_D0 0x0000 +#define PCI_PMCSR_STATE_D1 0x0001 +#define PCI_PMCSR_STATE_D2 0x0002 +#define PCI_PMCSR_STATE_D3 0x0003 +#define PCI_PMCSR_PME_STATUS 0x8000 +#define PCI_PMCSR_PME_EN 0x0100 /* * HyperTransport; access via capability pointer. ]]]