diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2011-04-17 20:52:44 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2011-04-17 20:52:44 +0000 |
commit | 991276d863e6447a59df3df49691d6f7c57ad61b (patch) | |
tree | e7eb89a45f0254418ad3a27fe6417221a31d0cdd | |
parent | 40f4f477efe1ee200e76a151532311ef37de34da (diff) |
Add wol support to xl(4). Not really tested, but hopefully someone will
test it now that it's in-tree. ok deraadt ("It causes no harm")
-rw-r--r-- | sys/dev/ic/xl.c | 38 | ||||
-rw-r--r-- | sys/dev/ic/xlreg.h | 18 | ||||
-rw-r--r-- | sys/dev/pci/if_xl_pci.c | 35 |
3 files changed, 88 insertions, 3 deletions
diff --git a/sys/dev/ic/xl.c b/sys/dev/ic/xl.c index b4408d71825..d79d6312071 100644 --- a/sys/dev/ic/xl.c +++ b/sys/dev/ic/xl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xl.c,v 1.100 2011/04/05 18:01:21 henning Exp $ */ +/* $OpenBSD: xl.c,v 1.101 2011/04/17 20:52:43 stsp Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -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. */ @@ -2669,6 +2687,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 }; diff --git a/sys/dev/ic/xlreg.h b/sys/dev/ic/xlreg.h index b64260e4c1b..3b1490f4d4d 100644 --- a/sys/dev/ic/xlreg.h +++ b/sys/dev/ic/xlreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xlreg.h,v 1.26 2010/09/21 01:05:12 claudio Exp $ */ +/* $OpenBSD: xlreg.h,v 1.27 2011/04/17 20:52:43 stsp Exp $ */ /* * Copyright (c) 1997, 1998 @@ -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) \ @@ -741,6 +750,13 @@ struct xl_stats { #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 *); extern int xl_detach(struct xl_softc *); diff --git a/sys/dev/pci/if_xl_pci.c b/sys/dev/pci/if_xl_pci.c index 2916e413db7..ef70bd42c0b 100644 --- a/sys/dev/pci/if_xl_pci.c +++ b/sys/dev/pci/if_xl_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_xl_pci.c,v 1.35 2011/04/03 15:36:03 jasper Exp $ */ +/* $OpenBSD: if_xl_pci.c,v 1.36 2011/04/17 20:52:43 stsp Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -92,10 +92,14 @@ int xl_pci_match(struct device *, void *, 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, struct device *self, void *aux) 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, struct device *self, void *aux) 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 |