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:[email protected]]
LinkedIn: http://it.linkedin.com/in/delaurenzis