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, &reg)) {
+               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

Reply via email to