On Fri 25/04, Fred wrote: > On 04/25/14 11:24, Alessandro DE LAURENZIS wrote: > </snipped> > > > >I'm attaching a tarball with all the modified files, 'cause we proceeded > >iteratively and it's very easy to miss something; it would be great if > >you could revisit the code and prepare a patch usable with 5.4-Rel > >(I applied some hunks by hand because they were not directly manageable > >by the patch command). > > tar balls can only be sent to tech@ and ports@
Sorry guys, I was not aware of the policy. Hereafter the patch I applied to 5.4-Stable, based on the original Stefan's one, plus all his suggestions and additions. It is not directly applicable to 5.5-current, 'cause some constant renaming and other minor modifications, but it shouldn't be too hard to adapt it. Of course, Stefan should revisit the code, since -as I already highlighted- this is the result of an iterative process. Cheers [[ diff -ru ../orig/mii/brgphyreg.h ./mii/brgphyreg.h --- ../orig/mii/brgphyreg.h Fri Apr 25 18:05:55 2014 +++ ./mii/brgphyreg.h Wed Apr 23 21:11:39 2014 @@ -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 */ diff -ru ../orig/pci/if_bge.c ./pci/if_bge.c --- ../orig/pci/if_bge.c Fri Apr 25 18:06:24 2014 +++ ./pci/if_bge.c Fri Apr 25 12:00:14 2014 @@ -202,6 +202,10 @@ 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 *); @@ -2949,6 +2953,35 @@ CSR_WRITE_4(sc, BGE_MSI_MODE, reg); } +#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")); sc->bge_intrhand = pci_intr_establish(pc, ih, IPL_NET, bge_intr, sc, @@ -3038,7 +3071,6 @@ struct bge_softc *sc = (struct bge_softc *)self; struct ifnet *ifp = &sc->arpcom.ac_if; int rv = 0; - switch (act) { case DVACT_QUIESCE: rv = config_activate_children(self, act); @@ -3047,12 +3079,23 @@ 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) bge_init(sc); rv = config_activate_children(self, act); break; + case DVACT_POWERDOWN: + rv = config_activate_children(self, act); + if (ifp->if_flags & IFF_RUNNING) + bge_stop(sc); +#ifndef SMALL_KERNEL + bge_wol_power(sc); +#endif + break; } return (rv); } @@ -4562,3 +4605,177 @@ 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_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); + + 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 diff -ru ../orig/pci/if_bgereg.h ./pci/if_bgereg.h --- ../orig/pci/if_bgereg.h Fri Apr 25 18:06:36 2014 +++ ./pci/if_bgereg.h Thu Apr 24 07:51:12 2014 @@ -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 @@ -435,6 +436,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 @@ -2070,6 +2072,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 @@ -2260,6 +2264,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; @@ -2438,12 +2448,15 @@ */ #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 @@ -2843,6 +2856,9 @@ #define BGE_APE 0x10000000 #define BGE_CPMU_PRESENT 0x20000000 #define BGE_TAGGED_STATUS 0x40000000 +#define BGE_WOL 0x04000000 +#define BGE_WOL_NEEDS_VAUX 0x08000000 +#define BGE_NO_GPIO2 0x10000000 bus_dma_tag_t bge_dmatag; u_int32_t bge_mfw_flags; /* Management F/W flags */ diff -ru ../orig/pci/pcireg.h ./pci/pcireg.h --- ../orig/pci/pcireg.h Fri Apr 25 18:06:52 2014 +++ ./pci/pcireg.h Thu Apr 24 07:41:50 2014 @@ -517,11 +517,13 @@ * 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. ]] -- Alessandro DE LAURENZIS [mailto:just22....@gmail.com] LinkedIn: http://it.linkedin.com/in/delaurenzis