On Thu, Mar 31, 2011 at 06:54:44PM +0200, Stefan Sperling wrote:
> This is an attempt to add wol support to xl(4).
>
> Unfortunately, while I have an xl(4) card to test with none of the
> motherboards I have will do WOL with it since they all lack an
> on-board WOL connector :(
>
> So test reports are needed.
> Please also check whether WOL is disabled by default.
I haven't received any test reports yet.
If someone could donate a motherboard with a wol connector, preferrably
with suitable cpu and ram, that would help with getting wol support for
this and some other drivers for similarly old hardware.
It doesn't need to be a fast machine. I just need a board that has a connector.
>
> Index: ic/xl.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/xl.c,v
> retrieving revision 1.99
> diff -u -p -r1.99 xl.c
> --- ic/xl.c 22 Sep 2010 08:49:14 -0000 1.99
> +++ ic/xl.c 31 Mar 2011 15:48:36 -0000
> @@ -191,6 +191,9 @@ void xl_testpacket(struct xl_softc *);
> int xl_miibus_readreg(struct device *, int, int);
> void xl_miibus_writereg(struct device *, int, int, int);
> void xl_miibus_statchg(struct device *);
> +#ifndef SMALL_KERNEL
> +int xl_wol(struct ifnet *, int);
> +#endif
>
> int
> xl_activate(struct device *self, int act)
> @@ -2368,6 +2371,12 @@ xl_stop(struct xl_softc *sc)
> ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
>
> xl_freetxrx(sc);
> +
> +#ifndef SMALL_KERNEL
> + /* Call upper layer WOL power routine if WOL is enabled. */
> + if ((sc->xl_flags & XL_FLAG_WOL) && sc->wol_power)
> + sc->wol_power(sc->wol_power_arg);
> +#endif
> }
>
> void
> @@ -2637,6 +2646,15 @@ xl_attach(struct xl_softc *sc)
> CSR_WRITE_2(sc, XL_W0_MFG_ID, XL_NO_XCVR_PWR_MAGICBITS);
> }
>
> +#ifndef SMALL_KERNEL
> + /* Check availability of WOL. */
> + if ((sc->xl_caps & XL_CAPS_PWRMGMT) != 0) {
> + ifp->if_capabilities |= IFCAP_WOL;
> + ifp->if_wol = xl_wol;
> + xl_wol(ifp, 0);
> + }
> +#endif
> +
> /*
> * Call MI attach routines.
> */
> @@ -2668,6 +2686,24 @@ xl_detach(struct xl_softc *sc)
>
> return (0);
> }
> +
> +#ifndef SMALL_KERNEL
> +int
> +xl_wol(struct ifnet *ifp, int enable)
> +{
> + struct xl_softc *sc = ifp->if_softc;
> +
> + XL_SEL_WIN(7);
> + if (enable) {
> + CSR_WRITE_2(sc, XL_W7_BM_PME, XL_BM_PME_MAGIC);
> + sc->xl_flags |= XL_FLAG_WOL;
> + } else {
> + CSR_WRITE_2(sc, XL_W7_BM_PME, 0);
> + sc->xl_flags &= ~XL_FLAG_WOL;
> + }
> + return (0);
> +}
> +#endif
>
> struct cfdriver xl_cd = {
> 0, "xl", DV_IFNET
> Index: ic/xlreg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/xlreg.h,v
> retrieving revision 1.26
> diff -u -p -r1.26 xlreg.h
> --- ic/xlreg.h 21 Sep 2010 01:05:12 -0000 1.26
> +++ ic/xlreg.h 31 Mar 2011 15:42:36 -0000
> @@ -411,6 +411,12 @@
> #define XL_W7_BM_LEN 0x06
> #define XL_W7_BM_STATUS 0x0B
> #define XL_W7_BM_TIMEr 0x0A
> +#define XL_W7_BM_PME 0x0C
> +
> +#define XL_BM_PME_WAKE 0x0001
> +#define XL_BM_PME_MAGIC 0x0002
> +#define XL_BM_PME_LINKCHG 0x0004
> +#define XL_BM_PME_WAKETIMER 0x0008
>
> /*
> * bus master control registers
> @@ -571,6 +577,7 @@ struct xl_mii_frame {
> #define XL_FLAG_NO_XCVR_PWR 0x0080
> #define XL_FLAG_USE_MMIO 0x0100
> #define XL_FLAG_NO_MMIO 0x0200
> +#define XL_FLAG_WOL 0x0400
>
> #define XL_NO_XCVR_PWR_MAGICBITS 0x0900
>
> @@ -604,6 +611,8 @@ struct xl_softc {
> caddr_t sc_listkva;
> bus_dmamap_t sc_rx_sparemap;
> bus_dmamap_t sc_tx_sparemap;
> + void (*wol_power)(void *);
> + void *wol_power_arg;
> };
>
> #define xl_rx_goodframes(x) \
> @@ -740,6 +749,13 @@ struct xl_stats {
> #define XL_PSTATE_D3 0x0003
> #define XL_PME_EN 0x0010
> #define XL_PME_STATUS 0x8000
> +
> +/* Bits in the XL_PCI_PWRMGMTCAP register */
> +#define XL_PME_CAP_D0 0x0800
> +#define XL_PME_CAP_D1 0x1000
> +#define XL_PME_CAP_D2 0x2000
> +#define XL_PME_CAP_D3_HOT 0x4000
> +#define XL_PME_CAP_D3_COLD 0x8000
>
> extern int xl_intr(void *);
> extern void xl_attach(struct xl_softc *);
> Index: pci/if_xl_pci.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_xl_pci.c,v
> retrieving revision 1.34
> diff -u -p -r1.34 if_xl_pci.c
> --- pci/if_xl_pci.c 19 Sep 2010 09:22:58 -0000 1.34
> +++ pci/if_xl_pci.c 31 Mar 2011 15:43:05 -0000
> @@ -92,10 +92,14 @@ int xl_pci_match(struct device *, void *
> void xl_pci_attach(struct device *, struct device *, void *);
> int xl_pci_detach(struct device *, int);
> void xl_pci_intr_ack(struct xl_softc *);
> +#ifndef SMALL_KERNEL
> +void xl_pci_wol_power(void *);
> +#endif
>
> struct xl_pci_softc {
> struct xl_softc psc_softc;
> pci_chipset_tag_t psc_pc;
> + pcitag_t psc_tag;
> bus_size_t psc_iosize;
> bus_size_t psc_funsize;
> };
> @@ -156,9 +160,11 @@ xl_pci_attach(struct device *parent, str
> u_int32_t command;
>
> psc->psc_pc = pc;
> + psc->psc_tag = pa->pa_tag;
> sc->sc_dmat = pa->pa_dmat;
>
> sc->xl_flags = 0;
> + sc->wol_power = sc->wol_power_arg = NULL;
>
> /* set required flags */
> switch (PCI_PRODUCT(pa->pa_id)) {
> @@ -260,6 +266,18 @@ xl_pci_attach(struct device *parent, str
> pci_conf_write(pc, pa->pa_tag, XL_PCI_LOMEM, mem);
> pci_conf_write(pc, pa->pa_tag, XL_PCI_INTLINE, irq);
> }
> +
> +#ifndef SMALL_KERNEL
> + /* The card is WOL-capable if it supports PME# assertion
> + * from D3hot power state. Install a callback to configure
> + * PCI power state for WOL. It will be invoked when the
> + * interface stops and WOL was enabled. */
> + command = pci_conf_read(pc, pa->pa_tag, XL_PCI_PWRMGMTCAP);
> + if (command & XL_PME_CAP_D3_HOT) {
> + sc->wol_power = xl_pci_wol_power;
> + sc->wol_power_arg = psc;
> + }
> +#endif
> }
>
> /*
> @@ -342,3 +360,18 @@ xl_pci_intr_ack(struct xl_softc *sc)
> bus_space_write_4(sc->xl_funct, sc->xl_funch, XL_PCI_INTR,
> XL_PCI_INTRACK);
> }
> +
> +#ifndef SMALL_KERNEL
> +void
> +xl_pci_wol_power(void *ppsc)
> +{
> + u_int32_t command;
> + struct xl_pci_softc *psc = (struct xl_pci_softc*)ppsc;
> +
> + /* Make sure power management is enabled, and set the card into
> + * D3hot power state so it stays active after system shutdown. */
> + command = pci_conf_read(psc->psc_pc, psc->psc_tag, XL_PCI_PWRMGMTCTRL);
> + command |= XL_PME_EN | XL_PSTATE_D3;
> + pci_conf_write(psc->psc_pc, psc->psc_tag, XL_PCI_PWRMGMTCTRL, command);
> +}
> +#endif