On Tue, Apr 22, 2014 at 04:43:51PM +0200, Alessandro DE LAURENZIS wrote:
> Folks,
> 
> OpenBSD 5.4-Rel, GENERIC kernel. I'm trying to set up a file server that
> should be remotely controlled (broken LCD).
> 
> I need to switch it on by means of WOL functionality (supported by and
> activated into the BIOS).
> 
> The interface is:
> 
> $ dmesg | egrep bge
> bge0 at pci2 dev 0 function 0 "Broadcom BCM5751" rev 0x01, BCM5750 A1 
> (0x4001): apic 1 int 16, address 00:14:22:e1:0b:05
> brgphy0 at bge0 phy 1: BCM5750 10/100/1000baseT PHY, rev. 0
> 
> When I halt the system *without* powering down it and then switch it off
> pressing the power button, the interface is still on (LED activity is
> visible) and I can wake up the system through the ARP magic packet.
> 
> But if I try to power it off through "halt -p" the interface is
> physically powered down too (and, of course, it no more react to the WOL
> packets).
> 
> I also tried to set "powerdown=YES" in /etc/rc.shutdown, but without
> luck.
> 
> Any hints? Pressing the power button each time is not an option, 'cause
> the server location isn't easly accessible.
> 
> All the best

What you'd need is wol support for bge, like was done for some
other drivers. I believe your 'halt' workaround prevents bge_stop()
from being run which deliberately shuts down the card's receive logic.
The BIOS might enable WoL at system startup behind the driver's back
and it might be left enabled if bge_stop() doesn't run.

I'd recommend getting a separate dedicated ethernet card for use
with WoL. Currently, these drivers support WOL in OpenBSD:

  nfe(4), re(4), vr(4), xl(4)

More drivers might be added in the future but I'm not actively
working on this anymore.

I wrote a diff for WoL support for bge(4) in 2011, see below.
For most bge chips enabling WOL might leave the machine vulnerable to
potential exploits of remote management features in the chip's firmware.
Remote management needs to be enabled for WoL to work and is probably
buggier than windows xp was at launch date (Theo was saying some of these
remote management systems embed MSDOS... Not sure if that was a joke but I
don't really want to know.)

The bge chip version this implements WOL for should be safe
(no remote management) but I've been told this chip version is
very rare so I didn't bother committing the diff back then.

I have no idea if this diff still applies cleanly to -current (it
probably won't) or whether it will make WoL work with your hardware.
Consider it an unsupported gift.

Stay safe.

[[[
This diff makes WOL work with a bge device mikeb gave to me.

The datasheet describes scary remote system management stuff
for these chips (ASF/SMI), but this is unsupported on the BCM5700
so it should be fine to enable WOL there. Coincidentally, the
card mikeb gave me is a BCM5700:

bge0 at pci2 dev 8 function 0 "Schneider & Koch SK-9D21" rev 0x11, BCM5700 
Altima (0x7104): apic 1 int 11, address 00:00:5a:9d:11:b2
brgphy0 at bge0 phy 1: BCM5411 10/100/1000baseT PHY, rev. 1

The diff below makes WOL work with this card.
With quite a lot of hoops to jump through compared to other cards :-/

However, without a gross hack, namely calling bge_init() and bge_stop()
from bge_wol_power(), WOL only works if the interface was taken 'up'
at least once. Any ideas what parts of init() and stop() are the
important bits? I've tried a few things but haven't been successful.

The chip doesn't shadow the PCI PMCSR register, so I added
definitions for it to the generic PCI code.

Index: mii/brgphyreg.h
===================================================================
RCS file: /cvs/src/sys/dev/mii/brgphyreg.h,v
retrieving revision 1.15
diff -u -p -r1.15 brgphyreg.h
--- mii/brgphyreg.h     10 Jul 2010 07:59:33 -0000      1.15
+++ mii/brgphyreg.h     28 Oct 2011 23:45:28 -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.307
diff -u -p -r1.307 if_bge.c
--- pci/if_bge.c        22 Jun 2011 16:44:27 -0000      1.307
+++ pci/if_bge.c        30 Oct 2011 21:02:41 -0000
@@ -192,6 +192,10 @@ void bge_miibus_statchg(struct device *)
 
 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
 
 #ifdef BGE_DEBUG
 #define DPRINTF(x)     do { if (bgedebug) printf x; } while (0)
@@ -2218,6 +2222,17 @@ bge_attach(struct device *parent, struct
                    sc->bge_flags |= BGE_PHY_FIBER_TBI;
        }
 
+#ifndef SMALL_KERNEL
+       if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700) {
+               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,
@@ -2307,11 +2322,17 @@ bge_activate(struct device *self, int ac
        switch (act) {
        case DVACT_QUIESCE:
                rv = config_activate_children(self, act);
+#ifndef SMALL_KERNEL
+               bge_wol_power(sc);
+#endif
                break;
        case DVACT_SUSPEND:
                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)
@@ -3729,3 +3750,113 @@ 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 reg;
+       int s, offset, if_flags;
+
+       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, &reg))
+               pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCI_PMCSR,
+                   reg|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);
+
+       /* Switch from main power to aux power. The procedure differs
+        * based on chip model. We only support BCM5700 here. */
+       if (sc->bge_flags & BGE_WOL_NEEDS_VAUX) {
+               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);
+       }
+
+       /* 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
Index: pci/if_bgereg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_bgereg.h,v
retrieving revision 1.104
diff -u -p -r1.104 if_bgereg.h
--- pci/if_bgereg.h     15 Feb 2011 19:49:47 -0000      1.104
+++ pci/if_bgereg.h     30 Oct 2011 18:29:53 -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
@@ -421,6 +422,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
@@ -2057,6 +2059,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;
@@ -2239,6 +2247,7 @@ struct bge_status_block {
 #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_VOLTAGE_1POINT3            0x00000000
 #define BGE_VOLTAGE_1POINT8            0x00000001
@@ -2611,6 +2620,8 @@ struct bge_softc {
 #define BGE_5755_PLUS          0x00800000
 #define BGE_5714_FAMILY                0x01000000
 #define BGE_5700_FAMILY                0x02000000
+#define BGE_WOL                        0x04000000
+#define BGE_WOL_NEEDS_VAUX     0x08000000
 
        bus_dma_tag_t           bge_dmatag;
        u_int32_t               bge_chipid;
Index: pci/pcireg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/pcireg.h,v
retrieving revision 1.42
diff -u -p -r1.42 pcireg.h
--- pci/pcireg.h        19 Jun 2011 12:02:23 -0000      1.42
+++ pci/pcireg.h        28 Oct 2011 21:56:28 -0000
@@ -516,11 +516,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.
]]]

Reply via email to