On Wed, Apr 23, 2014 at 03:16:52PM +0200, Alessandro DE LAURENZIS wrote: > Your patch is still applicable to 5.4 stable (with only minor refinements), > but unfortunately it doesn't change anything for this BGE chip...
Thanks, this motivated me to poke a bit further at it. Just to make sure: Did you try to enable wol with 'ifconfig bge0 wol'? > Do you think a PCMCIA Eth card with one of the mentioned chips could be > a reasonable solution? I mean, my understanding is that the BIOS plays a > role in WoL stuff, so I'm wondering if a PCMCIA will stay powered on > even when the system is switched off, like the Ethernet port is supposed > to be... I doubt PCMCIA would work. Cards going into PCI slots should work. Some have a small power cable coming off the NIC that can be plugged into the mainboard. Newer cards use the PCI bus directly for this via the PME# signal. Anyway, I've revised my bge diff a bit. It first checks if ASF is disabled and allows WOL if it is disabled. We really don't want to trust ASF. http://www.intel.com/content/dam/doc/white-paper/asf-standards-based-systems-management-paper.pdf It's a component of AMT. AMT has pretty bad security: http://web.it.kth.se/~maguire/DEGREE-PROJECT-REPORTS/100402-Vassilios_Ververis-with-cover.pdf Not sure if we can trust the EEPROM not to tell lies about ASF being disabled. But that can be discussed with others once I know whether this diff makes wol work for you. I hope I got the power-down sequnce right for all cards, it's based on what Linux does but I don't have any hardware to test this. Diff is against -current from a week ago or so. Might work with 5.5. 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.