This should work on sparc64? if so I can test in my sunfire v210... - this box isn't set up to build a kernel so it will be some work to make it build -
On Wed, Apr 23, 2014 at 11:15 AM, Stefan Sperling <s...@openbsd.org> wrote: > The reason we don't enable WOL with bge cards is that they contain > ASF firmware support which should not be exposed to untrusted traffic, > so it's safer to power down bge devices altogether on power down. > Since all bges except the rare 5700 version support ASF, this currently > means no WOL support for bge cards at all. > > (If you want to know what's so bad about ASF, search the net for > security problems with intel AMT -- ASF is a precursor to this.) > > Apparently there is an eeprom configuration bit that tells us > if ASF is enabled or not. Can we trust this bit? > If we decide that the bit is trustworthy enough, we could allow > users to enable wol for bge cards as long as ASF is disabled > (yet I'd still want a warning in the man page). > > The diff below tries to do this. I don't have any hardware to test > with so I'd be delighted if some bge owners could give this a spin. > If this doesn't make wol work and the problem can't be fixed, then > we can skip the entire ASF discussion anyway. > > To test this: > > - recompile your kernel with the below diff > - reboot > - run 'ifconfig bge0 wol' > - run 'shutdown -hp now' > - try to send a magic packet from another machine with 'arp -W MAC_ADDR' > and hope for the bge box to power back up > > If it doesn't work, please check your BIOS for WOL and ASF-related > configuration settings and check if tweaking them helps. > > Thanks. > > Index: mii/brgphyreg.h > =================================================================== > RCS file: /cvs/src/sys/dev/mii/brgphyreg.h,v > retrieving revision 1.16 > diff -u -p -r1.16 brgphyreg.h > --- mii/brgphyreg.h 13 Jan 2013 05:40:05 -0000 1.16 > +++ mii/brgphyreg.h 23 Apr 2014 14:11:06 -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.353 > diff -u -p -r1.353 if_bge.c > --- pci/if_bge.c 24 Feb 2014 20:00:48 -0000 1.353 > +++ pci/if_bge.c 23 Apr 2014 15:33:54 -0000 > @@ -202,6 +202,10 @@ void bge_sig_pre_reset(struct bge_softc > void bge_stop_fw(struct bge_softc *, int); > 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 > > void bge_ape_lock_init(struct bge_softc *); > void bge_ape_read_fw_ver(struct bge_softc *); > @@ -3064,6 +3068,35 @@ bge_attach(struct device *parent, struct > if (BGE_IS_5755_PLUS(sc) && sc->bge_flags & BGE_MSI) > CSR_WRITE_4(sc, BGE_MSI_MODE, CSR_READ_4(sc, BGE_MSI_MODE) & > ~BGE_MSIMODE_ONE_SHOT_DISABLE); > + > +#ifndef SMALL_KERNEL > + if (hwcfg & BGE_HWCFG_NO_GPIO2) > + sc->bge_flags |= BGE_NO_GPIO2; > + > + if (BGE_ASICREV(sc->bge_chipid) != BGE_ASICREV_BCM5700) { > + /* Check if ASF is enabled. */ > + if (!(sc->bge_flags & BGE_NO_EEPROM)) { > + if (bge_read_eeprom(sc, (caddr_t)&hwcfg, > + BGE_EE_FEATURE_CFG_OFFSET, sizeof(hwcfg)) == 0) { > + hwcfg = ntohl(hwcfg); > + if (hwcfg & BGE_HWCFG_ASF) > + sc->bge_flags |= BGE_ASF_MODE; > + } > + } else if (hwcfg & BGE_HWCFG_ASF) { > + sc->bge_flags |= BGE_ASF_MODE; > + } > + } > + > + /* Allow WoL if ASF is unsupported or disabled. */ > + if (!(sc->bge_flags & BGE_ASF_MODE)) { > + 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")); > @@ -3160,6 +3193,9 @@ bge_activate(struct device *self, int ac > 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) > @@ -4728,3 +4764,177 @@ 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 pcireg; > + int s, offset, if_flags; > + u_int32_t reg; > + > + 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, &pcireg)) > + pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCI_PMCSR, > + pcireg|PCI_PMCSR_PME_STATUS); > + > + /* Configure 10Mbps, the chip draws too much power in D3cold. */ > + if (!(sc->bge_flags & BGE_FIBER_TBI) && > + !(sc->bge_flags & BGE_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); > + > + if (sc->bge_flags & BGE_WOL_NEEDS_VAUX) { > + /* Switch from main power to aux power. */ > + if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700 || > + BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5701) { > + 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); > + } else if (PCI_PRODUCT(pa->pa_id) == > + PCI_PRODUCT_BROADCOM_BCM5761 || > + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5761S) { > + /* These have GPIO 0 and GPIO 2 swapped. */ > + reg = (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); > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + reg |= BGE_MLC_MISCIO_OUT2; > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + reg &= ~BGE_MLC_MISCIO_OUT0; > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + } else { > + reg = 0; > + > + /* Workaround for drawing too much power. */ > + if (BGE_ASICREV(sc->bge_chipid) == > + BGE_ASICREV_BCM5714) { > + reg |= BGE_MLC_MISCIO_OUTEN3; > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + } > + > + if (sc->bge_flags & BGE_NO_GPIO2) { > + reg |= (BGE_MLC_MISCIO_OUTEN0| > + BGE_MLC_MISCIO_OUTEN1| > + BGE_MLC_MISCIO_OUT1); > + } else { > + reg |= (BGE_MLC_MISCIO_OUTEN0| > + BGE_MLC_MISCIO_OUTEN1| > + BGE_MLC_MISCIO_OUTEN2| > + BGE_MLC_MISCIO_OUT1| > + BGE_MLC_MISCIO_OUT2); > + } > + > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + > + reg |= BGE_MLC_MISCIO_OUT0; > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + > + if (!(sc->bge_flags & BGE_NO_GPIO2)) { > + reg &= ~BGE_MLC_MISCIO_OUT2; > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, reg); > + DELAY(100); > + } > + } > + } else if (BGE_ASICREV(sc->bge_chipid) != BGE_ASICREV_BCM5700 && > + BGE_ASICREV(sc->bge_chipid) != BGE_ASICREV_BCM5701) { > + /* Die with vmain power. */ > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, > + BGE_MLC_MISCIO_OUT1|BGE_MLC_MISCIO_OUTEN1); > + DELAY(100); > + BGE_CLRBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUT1); > + DELAY(100); > + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, 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.123 > diff -u -p -r1.123 if_bgereg.h > --- pci/if_bgereg.h 5 Feb 2014 05:59:42 -0000 1.123 > +++ pci/if_bgereg.h 23 Apr 2014 15:14:07 -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 > @@ -438,6 +439,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 > @@ -2102,6 +2104,8 @@ > #define BGE_MLC_INTR_CLR 0x00000002 > #define BGE_MLC_INTR_SET 0x00000004 > #define BGE_MLC_INTR_ONATTN 0x00000008 > +#define BGE_MLC_MISCIO_OUTEN3 0x00000040 > +#define BGE_MLC_MISCIO_OUT3 0x00000080 > #define BGE_MLC_MISCIO_IN0 0x00000100 > #define BGE_MLC_MISCIO_IN1 0x00000200 > #define BGE_MLC_MISCIO_IN2 0x00000400 > @@ -2292,6 +2296,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; > @@ -2470,12 +2480,15 @@ struct bge_status_block { > */ > #define BGE_EE_MAC_OFFSET 0x7C > #define BGE_EE_MAC_OFFSET_5906 0x10 > +#define BGE_EE_FEATURE_CFG_OFFSET 0xC4 > #define BGE_EE_HWCFG_OFFSET 0xC8 > > #define BGE_HWCFG_VOLTAGE 0x00000003 > #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_HWCFG_NO_GPIO2 0x00100000 > > #define BGE_VOLTAGE_1POINT3 0x00000000 > #define BGE_VOLTAGE_1POINT8 0x00000001 > @@ -2869,6 +2882,9 @@ struct bge_softc { > #define BGE_TAGGED_STATUS 0x00200000 > #define BGE_MSI 0x00400000 > #define BGE_RDMA_BUG 0x00800000 > +#define BGE_WOL 0x04000000 > +#define BGE_WOL_NEEDS_VAUX 0x08000000 > +#define BGE_NO_GPIO2 0x10000000 > > u_int32_t bge_phy_flags; > #define BGE_PHY_NO_3LED 0x00000001 > Index: pci/pcireg.h > =================================================================== > RCS file: /cvs/src/sys/dev/pci/pcireg.h,v > retrieving revision 1.46 > diff -u -p -r1.46 pcireg.h > --- pci/pcireg.h 9 Apr 2014 06:36:33 -0000 1.46 > +++ pci/pcireg.h 23 Apr 2014 14:11:06 -0000 > @@ -518,11 +518,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. > > > >